From 08c5fbdde554083bbeb7eb44113201afd39d0934 Mon Sep 17 00:00:00 2001 From: Sassa NF Date: Sun, 15 Dec 2024 21:19:36 +0000 Subject: [PATCH] Factor out scan configuration --- lib/config/config.cpp | 175 ++++++++++++++++++++++++++++++++++++++++++ lib/config/config.h | 14 ++++ src/main.cpp | 153 +++++++++++++++++------------------- 3 files changed, 259 insertions(+), 83 deletions(-) diff --git a/lib/config/config.cpp b/lib/config/config.cpp index 52a68cc..1221072 100644 --- a/lib/config/config.cpp +++ b/lib/config/config.cpp @@ -124,6 +124,12 @@ Config Config::init() continue; } + if (r.key.equalsIgnoreCase("detection_strategy")) + { + c.configureDetectionStrategy(r.value); + continue; + } + Serial.printf("Unknown key '%s' will be ignored\n", r.key); } @@ -131,6 +137,173 @@ Config Config::init() return c; } +String detectionStrategyToStr(Config &c) +{ + String res = c.detection_strategy; + if (c.scan_ranges_sz > 0) + { + res += ":"; + for (int i = 0; i < c.scan_ranges_sz; i++) + { + if (i > 0) + { + res += ","; + } + + res += String(c.scan_ranges[i].start_khz); + int s = c.scan_ranges[i].end_khz - c.scan_ranges[i].start_khz; + if (s > 0) + { + res += ".." + String(c.scan_ranges[i].end_khz); + if (c.scan_ranges[i].step_khz < s) + { + res += ":" + String(c.scan_ranges[i].step_khz); + } + } + } + } + return res; +} + +// findSepa looks for a sepa in s from position begin, and does two things: +// updates end with the index of the end of the string between begin and +// separator or end of string, and returns index of the next search position +// or -1 to stop the search. +// +// So you can do something like this: +// for (int i = 0, j = 0, k = 0; (i = findSepa(s, sepa, j, k)) >= 0; j = i) +// ...s.substring(j, k) +int findSepa(String s, String sepa, int begin, int &end) +{ + int i = s.indexOf(sepa, begin); + if (i < 0) + { + end = s.length(); + return begin == end ? -1 : end; + } + + end = i; + return i + sepa.length(); +} + +uint64_t toUint64(String s) +{ + String v = s.substring(0, s.length() % 15); + s = s.substring(v.length()); + uint64_t r = v.toInt(); + + while (s.length() > 0) + { + r = r * ((uint64_t)1000000000000000ll) + s.substring(0, 15).toInt(); + s = s.substring(15); + } + return r; +} + +ScanRange parseScanRange(String &cfg, int &begin) +{ + ScanRange res; + int end; + int i = findSepa(cfg, ",", begin, end); + + String r = cfg.substring(begin, end); + begin = i; + + if (i < 0) + { + res.start_khz = -1; + res.end_khz = -1; + res.step_khz = -1; + return res; + } + + i = r.indexOf(".."); + if (i < 0) + { + i = r.length(); + } + + res.start_khz = toUint64(r.substring(0, i)); + if (i == r.length()) + { + res.end_khz = res.start_khz; + res.step_khz = 0; + return res; + } + + r = r.substring(i + 2); + i = r.indexOf("+"); + if (i < 0) + { + i = r.indexOf("/"); + if (i < 0) + i = r.length(); + } + + res.end_khz = toUint64(r.substring(0, i)); + if (i == r.length()) + { + res.step_khz = res.end_khz - res.start_khz; + } + else + { + res.step_khz = toUint64(r.substring(i + 1)); + if (r.charAt(i) == '/') + { + // then it is not a literal increment, it is the number of steps + if (res.step_khz == 0) + res.step_khz = 1; + res.step_khz = round(((double)(res.end_khz - res.start_khz)) / res.step_khz); + } + } + + return res; +} + +void Config::configureDetectionStrategy(String cfg) +{ + if (scan_ranges_sz > 0) + delete[] scan_ranges; + scan_ranges = NULL; + + String method = cfg; + int i = cfg.indexOf(":"); + if (i >= 0) + { + method = cfg.substring(0, i); + cfg = cfg.substring(i + 1); + } + else + { + cfg = ""; + } + + samples = 0; + i = method.indexOf(","); + if (i >= 0) + { + samples = method.substring(i + 1).toInt(); + method = method.substring(0, i); + } + detection_strategy = method; + + scan_ranges_sz = 0; + for (int i = 0, k = 0; (i = findSepa(cfg, ",", i, k)) >= 0; scan_ranges_sz++) + ; + + if (scan_ranges_sz == 0) + { + return; + } + + scan_ranges = new ScanRange[scan_ranges_sz]; + + for (int i = 0, j = 0; i < scan_ranges_sz; i++) + { + scan_ranges[i] = parseScanRange(cfg, j); + } +} + bool Config::write_config(const char *path) { File f = SD.open(path, FILE_WRITE, /*create = */ true); @@ -145,6 +318,8 @@ bool Config::write_config(const char *path) f.println("listen_on_serial1 = " + listen_on_serial1); f.println("listen_on_usb = " + listen_on_usb); + f.println("detection_strategy = " + detectionStrategyToStr(*this)); + f.close(); return true; } diff --git a/lib/config/config.h b/lib/config/config.h index 1ef765a..a2d9003 100644 --- a/lib/config/config.h +++ b/lib/config/config.h @@ -3,11 +3,22 @@ #include +struct ScanRange +{ + uint64_t start_khz; + uint64_t end_khz; + uint64_t step_khz; +}; + #define CREATE_MISSING_CONFIG true struct Config { bool create_missing_config; bool print_profile_time; + String detection_strategy; + int samples; + int scan_ranges_sz; + ScanRange *scan_ranges; int log_data_json_interval; String listen_on_serial0; String listen_on_serial1; @@ -15,11 +26,14 @@ struct Config Config() : create_missing_config(CREATE_MISSING_CONFIG), print_profile_time(false), + detection_strategy("RSSI"), samples(0), scan_ranges_sz(0), scan_ranges(NULL), log_data_json_interval(1000), listen_on_serial0(String("none")), listen_on_serial1(String("readline")), listen_on_usb("readline") {}; bool write_config(const char *path); static Config init(); + + void configureDetectionStrategy(String cfg); }; struct ParseResult diff --git a/src/main.cpp b/src/main.cpp index 111b46d..a1372c6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -151,8 +151,8 @@ typedef enum // constexpr int RSSI_OUTPUT_FORMULA = 2; // Feature to scan diapasones. Other frequency settings will be ignored. -// int SCAN_RANGES[] = {850890, 920950}; -int SCAN_RANGES[] = {}; +// String SCAN_RANGES = String("850..890,920..950"); +String SCAN_RANGES = ""; // MHZ per page // to put everything into one page set RANGE_PER_PAGE = FREQ_END - 800 @@ -759,6 +759,42 @@ void logToSerialTask(void *parameter) void drone_sound_alarm(void *arg, Event &e); +void configureDetection() +{ + if (config.scan_ranges_sz == 0) + { + config.scan_ranges_sz = 1; + config.scan_ranges = new ScanRange[1]; + config.scan_ranges[0].start_khz = FREQ_BEGIN * 1000; + config.scan_ranges[0].end_khz = FREQ_END * 1000; + config.scan_ranges[0].step_khz = + (float)(FREQ_END - FREQ_BEGIN) * 1000 / (STEPS * SCAN_RBW_FACTOR); + } + + if (config.samples <= 0) + { + config.samples = SAMPLES_RSSI; + } + + CONF_SAMPLES = config.samples; + + CONF_FREQ_BEGIN = config.scan_ranges[0].start_khz / 1000; + CONF_FREQ_END = config.scan_ranges[0].end_khz / 1000; + for (int i = 0; i < config.scan_ranges_sz; i++) + { + CONF_FREQ_BEGIN = min(CONF_FREQ_BEGIN, config.scan_ranges[i].start_khz / 1000); + CONF_FREQ_END = max(CONF_FREQ_END, config.scan_ranges[i].end_khz / 1000); + } + + median_frequency = (CONF_FREQ_BEGIN + CONF_FREQ_END) / 2; + + samples = CONF_SAMPLES; + + RANGE_PER_PAGE = CONF_FREQ_END - CONF_FREQ_BEGIN; // FREQ_END - CONF_FREQ_BEGIN + RANGE = (int)(CONF_FREQ_END - CONF_FREQ_BEGIN); + range = RANGE; +} + void readConfigFile() { // writeFile(LittleFS, "/text.txt", "{WIFI:{name:\"sdfsdf\", @@ -784,27 +820,22 @@ void readConfigFile() smpls = readParameterFromParameterFile("samples"); Serial.println("SAMPLES: " + smpls); - CONF_SAMPLES = (smpls == "") ? samples : atoi(smpls.c_str()); - samples = CONF_SAMPLES; - CONF_FREQ_BEGIN = (fstart == "") ? FREQ_BEGIN : atoi(fstart.c_str()); - CONF_FREQ_END = (fend == "") ? FREQ_END : atoi(fend.c_str()); + String detection = String("RSSI"); + if (smpls.length() > 0) + detection += "," + smpls; + if (fstart.length() == 0) + fstart = String(FREQ_BEGIN * 1000); + if (fend.length() == 0) + fend = String(FREQ_END * 1000); + + detection += ":" + fstart + ".." + fend + "/" + String(STEPS * SCAN_RBW_FACTOR); + + config.configureDetectionStrategy(detection); + configureDetection(); both.println("C FREQ BEGIN:" + String(CONF_FREQ_BEGIN)); both.println("C FREQ END:" + String(CONF_FREQ_END)); both.println("C SAMPLES:" + String(CONF_SAMPLES)); - - RANGE_PER_PAGE = CONF_FREQ_END - CONF_FREQ_BEGIN; // FREQ_END - CONF_FREQ_BEGIN - - RANGE = (int)(CONF_FREQ_END - CONF_FREQ_BEGIN); - - SINGLE_STEP = (float)(RANGE / (STEPS * SCAN_RBW_FACTOR)); - - range = (int)(CONF_FREQ_END - CONF_FREQ_BEGIN); - - iterations = RANGE / RANGE_PER_PAGE; - - // uint64_t range_frequency = FREQ_END - CONF_FREQ_BEGIN; - median_frequency = (CONF_FREQ_BEGIN + CONF_FREQ_END) / 2; } void setup(void) @@ -918,24 +949,19 @@ void setup(void) initLittleFS(); readConfigFile(); - #endif #ifndef WEB_SERVER - CONF_SAMPLES = samples; - CONF_FREQ_BEGIN = FREQ_BEGIN; - CONF_FREQ_END = FREQ_END; + if (config.scan_ranges_sz == 0 && SCAN_RANGES.length() > 0) + { + config.configureDetectionStrategy(config.detection_strategy + ":" + SCAN_RANGES); + } + + configureDetection(); both.println("FREQ BEGIN:" + String(CONF_FREQ_BEGIN)); both.println("FREQ END:" + String(CONF_FREQ_END)); both.println("SAMPLES:" + String(CONF_SAMPLES)); - - RANGE_PER_PAGE = CONF_FREQ_END - CONF_FREQ_BEGIN; // FREQ_END - CONF_FREQ_BEGIN - RANGE = (int)(CONF_FREQ_END - CONF_FREQ_BEGIN); - SINGLE_STEP = (float)(RANGE / (STEPS * SCAN_RBW_FACTOR)); - range = (int)(CONF_FREQ_END - CONF_FREQ_BEGIN); - iterations = RANGE / RANGE_PER_PAGE; - median_frequency = (CONF_FREQ_BEGIN + CONF_FREQ_END) / 2; #endif init_radio(); @@ -1249,29 +1275,6 @@ bool is_new_x_pixel(int x) return false; } -void check_ranges() -{ - if (RANGE_PER_PAGE == range) - { - single_page_scan = true; - } - else - { - single_page_scan = false; - } - - for (int range : SCAN_RANGES) - { - ranges_count++; - } - - if (ranges_count > 0) - { - iterations = ranges_count; - single_page_scan = false; - } -} - void checkComms() { while (HostComms->available() > 0) @@ -1374,35 +1377,11 @@ void loop(void) r.fr_begin = CONF_FREQ_BEGIN; r.fr_end = r.fr_begin; - // 50 is a single-screen range - // TODO: Make 50 a variable with the option to show the full range - iterations = range / RANGE_PER_PAGE; - -#if 0 // disabled code - if (range % RANGE_PER_PAGE != 0) + for (range_item = 0; range_item < config.scan_ranges_sz; range_item++) { - // add more scan - //++; - } -#endif - - check_ranges(); - - // Iterating by small ranges by 50 Mhz each pixel is 0.4 Mhz - for (range_item = 0; range_item < iterations; range_item++) - { - range = RANGE_PER_PAGE; - if (ranges_count == 0) - { - r.fr_begin = (range_item == 0) ? r.fr_begin : r.fr_begin + range; - r.fr_end = r.fr_begin + RANGE_PER_PAGE; - } - else - { - r.fr_begin = SCAN_RANGES[range_item] / 1000; - r.fr_end = SCAN_RANGES[range_item] % 1000; - range = r.fr_end - r.fr_begin; - } + r.fr_begin = config.scan_ranges[range_item].start_khz / 1000; + r.fr_end = config.scan_ranges[range_item].end_khz / 1000; + range = r.fr_end - r.fr_begin; #ifdef DISABLED_CODE if (!ANIMATED_RELOAD || !single_page_scan) @@ -1422,8 +1401,16 @@ void loop(void) // horizontal (x axis) Frequency loop osd_x = 1, osd_y = 2, col = 0, max_bin = 0; + + ScanRange scan_range = config.scan_ranges[range_item]; + int steps = 1; + if (scan_range.step_khz > 0) + steps = 1 + (scan_range.end_khz - scan_range.start_khz) / scan_range.step_khz; + if (steps == 0) + steps = 1; + // x loop - for (x = 0; x < STEPS * SCAN_RBW_FACTOR; x++) + for (x = 0; x < steps; x++) { new_pixel = is_new_x_pixel(x); if (ANIMATED_RELOAD && SCAN_RBW_FACTOR == 1) @@ -1442,7 +1429,7 @@ void loop(void) // Because of the SCAN_RBW_FACTOR x is not a display coordinate anymore // x > STEPS on SCAN_RBW_FACTOR int display_x = x / SCAN_RBW_FACTOR; - float step = (range * ((float)x / (STEPS * SCAN_RBW_FACTOR))); + float step = (float)x * scan_range.step_khz / 1000.0; r.current_frequency = r.fr_begin + step; LOG("setFrequency:%f\n", r.current_frequency);