From d44bfcdbe20e765b47199f2e070a27a9869a7d69 Mon Sep 17 00:00:00 2001 From: Sassa NF Date: Sun, 3 Nov 2024 15:52:19 +0000 Subject: [PATCH] Support Wrap with checksum --- .gitignore | 1 + SpectrumScan.py | 38 ++++++++++++- lib/comms/comms.cpp | 130 ++++++++++++++++++++++++++------------------ lib/comms/comms.h | 14 ++++- spectrum_scan.c | 73 +++++++++++++++++++++++-- src/main.cpp | 2 +- 6 files changed, 196 insertions(+), 62 deletions(-) diff --git a/.gitignore b/.gitignore index 89cc49c..3da96e1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .vscode/c_cpp_properties.json .vscode/launch.json .vscode/ipch +out/* diff --git a/SpectrumScan.py b/SpectrumScan.py index 11d1c25..fb17802 100644 --- a/SpectrumScan.py +++ b/SpectrumScan.py @@ -48,6 +48,17 @@ def parse_line(line): _, count, rest = line.split(' ', 2) return int(count), json.loads(rest.replace('(', '[').replace(')', ']')) +POLY = 0x1021 +def crc16(s, c): + for ch in s: + c = c ^ (ord(ch) << 8) + for i in range(8): + if c & 0x8000: + c = ((c << 1) ^ POLY) & 0xffff + else: + c = (c << 1) & 0xffff + + return c def main(): parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description='''\ @@ -81,6 +92,9 @@ def main(): # List of frequencies freq_list = [] + checksum = -1 + so_far = 0 + # Open the COM port with serial.Serial(args.port, args.speed, timeout=None) as com: @@ -94,11 +108,33 @@ def main(): # Read a single line try: - line = com.readline().decode('utf-8').strip() + line = com.readline().decode('utf-8') except UnicodeDecodeError: + errors += 1 + continue + + if 'WRAP ' in line: + try: + _, c, rest = line.split(' ', 2) + checksum = int(c, 16) + so_far = crc16(rest, 0) + except Exception as e: + errors += 1 continue if 'SCAN_RESULT ' in line: + if checksum == -1: + errors += 1 + continue + + c16 = crc16(line, so_far) + if checksum != c16: + errors += 1 + checksum = -1 + continue + + checksum = -1 + lines += 1 try: count, data = parse_line(line) diff --git a/lib/comms/comms.cpp b/lib/comms/comms.cpp index 2576f81..cbf95df 100644 --- a/lib/comms/comms.cpp +++ b/lib/comms/comms.cpp @@ -22,7 +22,7 @@ void _onUsbEvent0(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { if (event_base == ARDUINO_HW_CDC_EVENTS) - { + { // arduino_hw_cdc_event_data_t *data = (arduino_hw_cdc_event_data_t *)event_data; if (event_id == ARDUINO_HW_CDC_RX_EVENT) { @@ -117,6 +117,30 @@ Message *Comms::receive() Message *_parsePacket(String); String _scan_str(ScanTask &); String _scan_result_str(ScanTaskResult &); +String _wrap_str(String); + +#define POLY 0x1021 +uint16_t crc16(String v, uint16_t c) +{ + for (int i = 0; i < v.length(); i++) + { + uint16_t ch = v.charAt(i); + c = c ^ (ch << 8); + for (int j = 0; j < 8; j++) + { + if (c & 0x8000) + { + c = (c << 1) ^ POLY; + } + else + { + c <<= 1; + } + } + } + + return c; +} void ReadlineComms::_onReceive() { @@ -126,10 +150,27 @@ void ReadlineComms::_onReceive() int i = partialPacket.indexOf('\n'); while (i >= 0) { - Message *m = _parsePacket(partialPacket.substring(0, i)); + String pack = partialPacket.substring(0, i); + bool messageOk = true; + + if (wrap != NULL) + { + messageOk = pack.length() == wrap->payload.wrap.length; + if (messageOk) + { + messageOk = crc16(pack, 0) == wrap->payload.wrap.crc; + } + delete wrap; + wrap = NULL; + } + Message *m = messageOk ? _parsePacket(pack) : NULL; if (m != NULL) { - if (!_messageArrived(*m)) + if (m->type == WRAP) + { + wrap = m; + } + else if (!_messageArrived(*m)) { delete m; } @@ -154,53 +195,7 @@ bool ReadlineComms::send(Message &m) break; } - const char *cstr = p.c_str(); - size_t cstr_len = strlen(cstr); - - int loops = 0; - uint64_t t0 = millis(); - uint64_t idle_started = 0; - - for (size_t a = serial.availableForWrite(); a < cstr_len; - a = serial.availableForWrite(), loops++) - { - uint64_t now = millis(); - if (now - t0 > 1000) - { - Serial.printf("Unable to make progress after %d loops; %d bytes available " - "for write, %d chars still to write\n", - loops, a, cstr_len); - break; - } - - if (a == 0) - { - if (idle_started == 0) - { - idle_started = now; - } - - if (now - idle_started > 2) - { - vTaskDelay(pdMS_TO_TICKS(2)); - } - else - { - yield(); - } - continue; - } - - idle_started = 0; - - serial.write(cstr, a); - cstr += a; - cstr_len -= a; - } - serial.println(cstr); - - uint64_t dt = millis() - t0; - Serial.printf("Wrote stuff in %d iterations and %" PRIu64 " ms.\n", loops, dt); + serial.print(_wrap_str(p)); return true; } @@ -218,6 +213,20 @@ int64_t _intParam(String &p, int64_t default_v) return v; } +int64_t _hexParam(String &p, int64_t default_v) +{ + p.trim(); + int i = p.indexOf(' '); + if (i < 0) + { + i = p.length(); + } + + int64_t v = strtol(p.substring(0, i).c_str(), 0, 16); + p = p.substring(i + 1); + return v; +} + Message *_parsePacket(String p) { p.trim(); @@ -239,6 +248,15 @@ Message *_parsePacket(String p) p.trim(); } + if (cmd.equalsIgnoreCase("wrap")) + { + Message *m = new Message(); + m->type = MessageType::WRAP; + m->payload.wrap.crc = _hexParam(p, -1); + m->payload.wrap.length = _intParam(p, -1); + return m; + } + if (cmd.equalsIgnoreCase("scan")) { Message *m = new Message(); @@ -254,12 +272,12 @@ Message *_parsePacket(String p) String _scan_str(ScanTask &t) { - return "SCAN " + String(t.count) + " " + String(t.delay); + return "SCAN " + String(t.count) + " " + String(t.delay) + "\n"; } String _scan_result_str(ScanTaskResult &r) { - String p = "SCAN_RESULT " + String(r.sz) + " ["; + String p = "SCAN_RESULT " + String(r.sz) + " [ "; for (int i = 0; i < r.sz; i++) { @@ -267,5 +285,11 @@ String _scan_result_str(ScanTaskResult &r) ")"; } - return p + " ]"; + return p + " ]\n"; +} + +String _wrap_str(String v) +{ + String r = String(v.length()) + "\n" + v; + return "WRAP " + String(crc16(r, 0), 16) + " " + r; } diff --git a/lib/comms/comms.h b/lib/comms/comms.h index 1c35dd8..a37fe12 100644 --- a/lib/comms/comms.h +++ b/lib/comms/comms.h @@ -6,11 +6,18 @@ enum MessageType { - SCAN = 0, + WRAP = 0, + SCAN, SCAN_RESULT, _MAX_MESSAGE_TYPE = SCAN_RESULT }; +struct Wrapper +{ + int32_t length; + uint16_t crc; +}; + struct ScanTask { int64_t count; @@ -29,6 +36,7 @@ struct Message MessageType type; union { + Wrapper wrap; ScanTask scan; ScanTaskResult dump; } payload; @@ -41,8 +49,10 @@ struct Comms size_t received_sz; size_t received_pos; + Message *wrap; + Comms(Stream &serial) - : serial(serial), received(NULL), received_sz(0), received_pos(0) {}; + : serial(serial), received(NULL), received_sz(0), received_pos(0), wrap(NULL) {}; virtual size_t available(); virtual bool send(Message &) = 0; diff --git a/spectrum_scan.c b/spectrum_scan.c index 4cadba6..aa8c9c9 100644 --- a/spectrum_scan.c +++ b/spectrum_scan.c @@ -3,6 +3,34 @@ #include #include #include +#include + +typedef struct { + uint16_t checksum; + uint16_t so_far; + size_t len; +} wrap_t; + +#define POLY 0x1021 +uint16_t crc16(char *p, char *end, uint16_t c) { + if (end == NULL) { + end = strchr(p, 0); + } + + for (; p != end; p++) { + uint16_t ch = *p; + c = c ^ (ch << 8); + for (int j = 0; j < 8; j++) { + if (c & 0x8000) { + c = (c << 1) ^ POLY; + } else { + c <<= 1; + } + } + } + + return c; +} #define BUFSIZE 102400 #define LOOPS 200 @@ -24,6 +52,9 @@ int main(int argc, char** argv) int progress = 0; int progress_ln = 0; + wrap_t wrapper; + wrapper.len = 0; + while(lines - errors < LOOPS) { if (pos == BUFSIZE) @@ -48,17 +79,49 @@ int main(int argc, char** argv) // assert: n points at the first unused byte in buffer pos = (nl - buffer) + 1; + char *wrap = "WRAP "; + char is_wrap = strncmp(buffer, wrap, strlen(wrap)) == 0; + if (is_wrap) { + char *end; + char *p = buffer + strlen(wrap); + wrapper.checksum = strtol(p, &end, 16); + wrapper.len = 0; + if (end == p) { + is_wrap = 0; + } else { + p = end; + wrapper.len = strtol(p, &end, 10); + if (end == p) { + is_wrap = 0; + } else { + wrapper.so_far = crc16(p+1, end+1, 0); + } + } + } + char *scan_result = "SCAN_RESULT "; char is_scan_result = strncmp(buffer, scan_result, strlen(scan_result)) == 0; if (is_scan_result) { - if ( - !(buffer[pos-2] == ']' || // that's where it should "normally" appear - buffer[pos-3] == ']') // that's where it actually appears - because HWCDC.println produces \r\n - ) + uint16_t c16 = crc16(buffer, buffer + pos, wrapper.so_far); + if (wrapper.len == 0 || wrapper.checksum != c16) { errors++; + if (wrapper.len == 0) { + int n = snprintf(buffer, pos, "E: no wrap"); // string definitely fits + buffer[n] = ' '; + } else { + int n = snprintf(buffer, pos, "E: bad crc"); // string definitely fits + buffer[n] = ' '; + int n1 = snprintf(buffer + n + 1, pos - n - 1, "want: %x, got: %x", wrapper.checksum, c16); + n1 += n + 1; + if (n1 <= pos - n - 1) { + buffer[n1] = ' '; + } + } } + wrapper.len = 0; // ok, used up the wrapper + // assert: pos points at the first byte of the next line write(1, buffer, pos); // printf("Last char is: %c\n", buffer[pos-3]); - wow, HWCDC.println ends up producing \r\n @@ -68,7 +131,7 @@ int main(int argc, char** argv) } else if (strncmp(buffer, "Unable to make ", 15) == 0) { lines--; write(1, buffer, pos); - } else { + } else if (!is_wrap) { errors++; } diff --git a/src/main.cpp b/src/main.cpp index 97dba55..2e9bf97 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -560,7 +560,7 @@ void dumpToCommsTask(void *parameter) int64_t delay = report_scans.delay; if (delay == 0) { - delay = (1 << 63) - 1; + delay = (1ull << 63) - 1; } ulTaskNotifyTake(true, pdMS_TO_TICKS(delay));