diff --git a/include/rfraw.h b/include/rfraw.h new file mode 100644 index 00000000..ad21887e --- /dev/null +++ b/include/rfraw.h @@ -0,0 +1,24 @@ +/** @file + RfRaw format functions. + + Copyright (C) 2020 Christian W. Zuckschwerdt <zany@triq.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +*/ + +#ifndef INCLUDE_RFRAW_H_ +#define INCLUDE_RFRAW_H_ + +#include "pulse_detect.h" +#include <stdbool.h> + +/// Check if a given string is in RfRaw format. +bool rfraw_check(char const *p); + +/// Decode RfRaw string to pulse data. +bool rfraw_parse(pulse_data_t *data, char const *p); + +#endif /* INCLUDE_RFRAW_H_ */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4a6b1aef..6f418ffc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,7 @@ add_library(r_433 STATIC pulse_detect_fsk.c r_api.c r_util.c + rfraw.c samp_grab.c sdr.c term_ctl.c diff --git a/src/Makefile.am b/src/Makefile.am index ea5b2095..558ae871 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,6 +24,7 @@ rtl_433_SOURCES = abuf.c \ pulse_detect_fsk.c \ r_api.c \ r_util.c \ + rfraw.c \ rtl_433.c \ samp_grab.c \ sdr.c \ diff --git a/src/pulse_detect.c b/src/pulse_detect.c index d9d61c1b..daa02f4a 100644 --- a/src/pulse_detect.c +++ b/src/pulse_detect.c @@ -10,6 +10,7 @@ */ #include "pulse_detect.h" +#include "rfraw.h" #include "pulse_demod.h" #include "pulse_detect_fsk.h" #include "baseband.h" @@ -112,9 +113,9 @@ void pulse_data_print_vcd(FILE *file, pulse_data_t const *data, int ch_id) void pulse_data_load(FILE *file, pulse_data_t *data, uint32_t sample_rate) { - char s[256]; + char s[1024]; int i = 0; - int size = sizeof(data->pulse) / sizeof(int); + int size = sizeof(data->pulse) / sizeof(*data->pulse); pulse_data_clear(data); data->sample_rate = sample_rate; @@ -136,6 +137,11 @@ void pulse_data_load(FILE *file, pulse_data_t *data, uint32_t sample_rate) continue; // still reading a header } } + if (rfraw_check(s)) { + rfraw_parse(data, s); + i = data->num_pulses; + continue; + } // parse two ints. char *p = s; char *endptr; diff --git a/src/rfraw.c b/src/rfraw.c new file mode 100644 index 00000000..4ecf5736 --- /dev/null +++ b/src/rfraw.c @@ -0,0 +1,175 @@ +/** @file + RfRaw format functions. + + Copyright (C) 2020 Christian W. Zuckschwerdt <zany@triq.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +*/ + +#include "rfraw.h" +#include "fatal.h" +#include <string.h> + +static int hexstr_get_nibble(char const **p) +{ + if (!p || !*p || !**p) return -1; + while (**p == ' ' || **p == '\t' || **p == '-' || **p == ':') ++*p; + + int c = **p; + if (c >= '0' && c <= '9') { + ++*p; + return c - '0'; + } + if (c >= 'A' && c <= 'F') { + ++*p; + return c - 'A' + 10; + } + if (c >= 'a' && c <= 'f') { + ++*p; + return c - 'a' + 10; + } + + return -1; +} + +static int hexstr_get_byte(char const **p) +{ + int h = hexstr_get_nibble(p); + int l = hexstr_get_nibble(p); + if (h >= 0 && l >= 0) + return (h << 4) | l; + return -1; +} + +static int hexstr_get_word(char const **p) +{ + int h = hexstr_get_byte(p); + int l = hexstr_get_byte(p); + if (h >= 0 && l >= 0) + return (h << 8) | l; + return -1; +} + +static int hexstr_peek_byte(char const *p) +{ + int h = hexstr_get_nibble(&p); + int l = hexstr_get_nibble(&p); + if (h >= 0 && l >= 0) + return (h << 4) | l; + return -1; +} + +bool rfraw_check(char const *p) +{ + // require 0xaa 0xb0 or 0xaa 0xb1 + return hexstr_get_nibble(&p) == 0xa + && hexstr_get_nibble(&p) == 0xa + && hexstr_get_nibble(&p) == 0xb + && (hexstr_get_nibble(&p) | 1) == 0x1; +/* + if (!p || !*p) return false; + while (*p == ' ' || *p == '\t' || *p == '-' || *p == ':') ++p; + if (*p != 'A' && *p != 'a') return false; + p++; + while (*p == ' ' || *p == '\t' || *p == '-' || *p == ':') ++p; + if (*p != 'A' && *p != 'a') return false; + p++; + while (*p == ' ' || *p == '\t' || *p == '-' || *p == ':') ++p; + if (*p != 'B' && *p != 'b') return false; + p++; + while (*p == ' ' || *p == '\t' || *p == '-' || *p == ':') ++p; + if (*p != '0' && *p != '1') return false; + p++; + while (*p == ' ' || *p == '\t' || *p == '-' || *p == ':') ++p; + if (*p != '0') return false; + return true; +*/ +} + +static bool parse_rfraw(pulse_data_t *data, char const **p) +{ + if (!p || !*p || !**p) return false; + + int hdr = hexstr_get_byte(p); + if (hdr !=0xaa) return false; + + int fmt = hexstr_get_byte(p); + if (fmt != 0xb0 && fmt != 0xb1) + return false; + + if (fmt == 0xb0) { + hexstr_get_byte(p); // ignore len + } + + int bins_len = hexstr_get_byte(p); + if (bins_len > 8) return false; + + int repeats = 1; + if (fmt == 0xb0) { + repeats = hexstr_get_byte(p); + } + + int bins[8] = {0}; + for (int i = 0; i < bins_len; ++i) { + bins[i] = hexstr_get_word(p); + } + + unsigned prev_pulses = data->num_pulses; + bool pulse_needed = true; + while (*p) { + if (hexstr_peek_byte(*p) == 0x55) { + hexstr_get_byte(p); // consume 0x55 + break; + } + + int w = hexstr_get_nibble(p); + if (w < 0) return false; + if (w >= 8) { // pulse + if (!pulse_needed) { + data->gap[data->num_pulses] = 0; + data->num_pulses++; + } + data->pulse[data->num_pulses] = bins[w & 7]; + pulse_needed = false; + } + else { // gap + if (pulse_needed) { + data->pulse[data->num_pulses] = 0; + } + data->gap[data->num_pulses] = bins[w]; + data->num_pulses++; + pulse_needed = true; + } + } + //data->gap[data->num_pulses - 1] = 3000; // TODO: extend last gap? + + unsigned pkt_pulses = data->num_pulses - prev_pulses; + for (int i = 1; i < repeats && data->num_pulses + pkt_pulses <= PD_MAX_PULSES; ++i) { + memcpy(&data->pulse[data->num_pulses], &data->pulse[prev_pulses], pkt_pulses * sizeof (*data->pulse)); + memcpy(&data->gap[data->num_pulses], &data->gap[prev_pulses], pkt_pulses * sizeof (*data->pulse)); + data->num_pulses += pkt_pulses; + } + //pulse_data_print(data); + + data->sample_rate = 1000000; // us + return true; +} + +bool rfraw_parse(pulse_data_t *data, char const *p) +{ + if (!p || !*p) + return false; + + // don't reset pulse data + // pulse_data_clear(data); + + while (*p) { + if (!parse_rfraw(data, &p)) + break; + } + //pulse_data_print(data); + return true; +} diff --git a/src/rtl_433.c b/src/rtl_433.c index 25c0ff4e..1382a3f7 100644 --- a/src/rtl_433.c +++ b/src/rtl_433.c @@ -39,6 +39,7 @@ #include "pulse_detect.h" #include "pulse_detect_fsk.h" #include "pulse_demod.h" +#include "rfraw.h" #include "data.h" #include "r_util.h" #include "optparse.h" @@ -1349,10 +1350,29 @@ int main(int argc, char **argv) { } if (cfg->verbosity) fprintf(stderr, "Verifying test data with device %s.\n", r_dev->name); + if (rfraw_check(e)) { + pulse_data_t pulse_data = {0}; + rfraw_parse(&pulse_data, e); + list_t single_dev = {0}; + list_push(&single_dev, r_dev); + if (!pulse_data.fsk_f2_est) + r += run_ook_demods(&single_dev, &pulse_data); + else + r += run_fsk_demods(&single_dev, &pulse_data); + list_free_elems(&single_dev, NULL); + } else r += pulse_demod_string(e, r_dev); continue; } // otherwise test all decoders + if (rfraw_check(line)) { + pulse_data_t pulse_data = {0}; + rfraw_parse(&pulse_data, line); + if (!pulse_data.fsk_f2_est) + r += run_ook_demods(&demod->r_devs, &pulse_data); + else + r += run_fsk_demods(&demod->r_devs, &pulse_data); + } else for (void **iter = demod->r_devs.elems; iter && *iter; ++iter) { r_device *r_dev = *iter; if (cfg->verbosity) @@ -1371,6 +1391,14 @@ int main(int argc, char **argv) { // Special case for string test data if (cfg->test_data) { r = 0; + if (rfraw_check(cfg->test_data)) { + pulse_data_t pulse_data = {0}; + rfraw_parse(&pulse_data, cfg->test_data); + if (!pulse_data.fsk_f2_est) + r += run_ook_demods(&demod->r_devs, &pulse_data); + else + r += run_fsk_demods(&demod->r_devs, &pulse_data); + } else for (void **iter = demod->r_devs.elems; iter && *iter; ++iter) { r_device *r_dev = *iter; if (cfg->verbosity) diff --git a/vs15/rtl_433.vcxproj b/vs15/rtl_433.vcxproj index b688946b..bea40b4c 100644 --- a/vs15/rtl_433.vcxproj +++ b/vs15/rtl_433.vcxproj @@ -118,6 +118,7 @@ COPY ..\..\libusb\MS64\dll\libusb*.dll $(TargetDir)</Command> <ClInclude Include="..\include\r_device.h" /> <ClInclude Include="..\include\r_private.h" /> <ClInclude Include="..\include\r_util.h" /> + <ClInclude Include="..\include\rfraw.h" /> <ClInclude Include="..\include\rtl_433.h" /> <ClInclude Include="..\include\rtl_433_devices.h" /> <ClInclude Include="..\include\samp_grab.h" /> @@ -149,6 +150,7 @@ COPY ..\..\libusb\MS64\dll\libusb*.dll $(TargetDir)</Command> <ClCompile Include="..\src\pulse_detect_fsk.c" /> <ClCompile Include="..\src\r_api.c" /> <ClCompile Include="..\src\r_util.c" /> + <ClCompile Include="..\src\rfraw.c" /> <ClCompile Include="..\src\rtl_433.c" /> <ClCompile Include="..\src\samp_grab.c" /> <ClCompile Include="..\src\sdr.c" /> diff --git a/vs15/rtl_433.vcxproj.filters b/vs15/rtl_433.vcxproj.filters index dcb792e0..89c587fc 100644 --- a/vs15/rtl_433.vcxproj.filters +++ b/vs15/rtl_433.vcxproj.filters @@ -178,6 +178,9 @@ <ClCompile Include="..\src\r_util.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\src\rfraw.c"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\src\rtl_433.c"> <Filter>Source Files</Filter> </ClCompile>