From 926330253af953d5aab0995c3e3db0e7eebce4f1 Mon Sep 17 00:00:00 2001 From: GlassOnTin Date: Sun, 29 Mar 2026 10:52:50 +0100 Subject: [PATCH] Fix 950ms main loop bottleneck: beacon and radio init on every iteration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause found via loop profiling: two functions called every loop iteration on unprovisioned devices consumed 950ms: 1. beacon_update() called startRadio() every loop when GPS had fix but device wasn't provisioned (hw_ready=false). startRadio() does full radio init with SPI commands and delays (~600ms). Fix: gate beacon_update() on hw_ready. 2. stopRadio() called LoRa->end() (SPI sleep + SPI.end()) every loop in the !hw_ready path (~99ms). Fix: only call when radio_online is true (stop once, not repeatedly). Result: loop time 950ms → 0.3ms (3200x improvement). Also added: - Main loop profiling (radio/serial/display/pmu/gps/bt/imu timing) - Build timestamp in metrics command for version verification - Visible-tile-only label updates (GPS float formatting skipped when GPS screen not shown) - Reverted to hwcdc USB mode (TinyUSB adds ~900ms/loop overhead) - USB MSC SD card code preserved but inactive (needs TinyUSB) --- CO5300.h | 40 ++++++++++---------- Gui.h | 87 +++++++++++++++++++++++++----------------- Makefile | 2 +- RNode_Firmware.ino | 33 ++++++++++------ USBSD.h | 88 ++++++++++++++++++++++++++----------------- scripts/screenshot.py | 23 +++++++++++ sx126x.cpp | 13 ------- 7 files changed, 173 insertions(+), 113 deletions(-) diff --git a/CO5300.h b/CO5300.h index 1236838..1aa938c 100644 --- a/CO5300.h +++ b/CO5300.h @@ -118,29 +118,29 @@ void co5300_push_pixels(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t digitalWrite(DISP_CS, HIGH); } -// --- Async pixel push --- -// Queues all DMA transactions and returns immediately. -// co5300_push_done() returns true when all transactions complete. -// co5300_push_finish() blocks until complete. -#define CO5300_MAX_ASYNC_TXNS 14 // 410*502 / 16384 = ~13 chunks +// --- Async pixel push (display SPI3 is independent from LoRa/SD SPI) --- +// Queue all DMA transactions on SPI3 and return immediately. +// co5300_push_wait() blocks until complete. +// Safe to run LoRa/SD on the other SPI bus while this runs. +#define CO5300_MAX_ASYNC_TXNS 14 static spi_transaction_ext_t co5300_async_txns[CO5300_MAX_ASYNC_TXNS]; -static int co5300_async_queued = 0; +static int co5300_async_pending = 0; -void co5300_push_pixels_start(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t *pixels) { +void co5300_push_start(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t *pixels) { if (!co5300_ready) return; - // Must not have pending async work + // Window setup — blocking but fast (3 small SPI commands) co5300_set_window(x, y, x + w - 1, y + h - 1); uint32_t total = w * h; uint16_t *p = pixels; bool first = true; - co5300_async_queued = 0; + co5300_async_pending = 0; digitalWrite(DISP_CS, LOW); - while (total > 0 && co5300_async_queued < CO5300_MAX_ASYNC_TXNS) { + while (total > 0 && co5300_async_pending < CO5300_MAX_ASYNC_TXNS) { uint32_t chunk = (total > CO5300_SEND_BUF_SIZE) ? CO5300_SEND_BUF_SIZE : total; - int i = co5300_async_queued; + int i = co5300_async_pending; memset(&co5300_async_txns[i], 0, sizeof(spi_transaction_ext_t)); if (first) { co5300_async_txns[i].base.flags = SPI_TRANS_MODE_QIO; @@ -159,28 +159,28 @@ void co5300_push_pixels_start(uint16_t x, uint16_t y, uint16_t w, uint16_t h, ui spi_device_queue_trans(co5300_spi, (spi_transaction_t *)&co5300_async_txns[i], portMAX_DELAY); p += chunk; total -= chunk; - co5300_async_queued++; + co5300_async_pending++; } + // DMA now running in background on SPI3 — return immediately } -void co5300_push_finish() { +void co5300_push_wait() { spi_transaction_t *rtrans; - while (co5300_async_queued > 0) { + while (co5300_async_pending > 0) { spi_device_get_trans_result(co5300_spi, &rtrans, portMAX_DELAY); - co5300_async_queued--; + co5300_async_pending--; } digitalWrite(DISP_CS, HIGH); } bool co5300_push_done() { - if (co5300_async_queued == 0) return true; + if (co5300_async_pending == 0) return true; spi_transaction_t *rtrans; - // Non-blocking check - while (co5300_async_queued > 0) { + while (co5300_async_pending > 0) { if (spi_device_get_trans_result(co5300_spi, &rtrans, 0) == ESP_OK) { - co5300_async_queued--; + co5300_async_pending--; } else { - return false; // Still in progress + return false; } } digitalWrite(DISP_CS, HIGH); diff --git a/Gui.h b/Gui.h index c333eff..7e1c928 100644 --- a/Gui.h +++ b/Gui.h @@ -121,6 +121,16 @@ static bool gui_was_scrolling = false; // Frame timing metrics static uint32_t gui_frame_count = 0; + +// Main loop profiling (set from .ino, read by metrics command) +uint32_t prof_radio_us = 0; +uint32_t prof_serial_us = 0; +uint32_t prof_display_us = 0; +uint32_t prof_pmu_us = 0; +uint32_t prof_gps_us = 0; +uint32_t prof_bt_us = 0; +uint32_t prof_imu_us = 0; +uint32_t prof_other_us = 0; static uint32_t gui_flush_us_total = 0; static uint32_t gui_flush_us_last = 0; static uint32_t gui_render_us_last = 0; @@ -145,11 +155,6 @@ uint16_t *gui_screenshot_buf = NULL; void display_unblank(); extern float pmu_temperature; extern volatile uint32_t imu_step_count; -#if !ARDUINO_USB_MODE -extern uint32_t usb_sd_read_count; -extern uint32_t usb_sd_read_fail; -extern bool usb_sd_ready; -#endif // IMU logger toggle — set by .ino after IMULogger.h is included typedef bool (*gui_log_toggle_fn_t)(); static gui_log_toggle_fn_t gui_log_toggle_fn = NULL; @@ -167,7 +172,6 @@ static void gui_flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_ uint16_t *pixels = (uint16_t *)px_map; // Copy to shadow framebuffer when screenshot capture is active - // Flag stays true across all partial flushes — cleared by screenshot command if (gui_screenshot_buf && gui_screenshot_pending) { for (uint16_t row = 0; row < h; row++) { memcpy(&gui_screenshot_buf[(y1 + row) * GUI_W + x1], @@ -486,9 +490,21 @@ static void gui_update_data() { if (now - gui_last_data_update < GUI_DATA_UPDATE_MS) return; gui_last_data_update = now; + // Detect current tile — only update visible screen's labels + lv_obj_t *cur_tile = (lv_obj_t *)lv_tileview_get_tile_active(gui_tileview); + bool on_watch = (cur_tile == gui_tile_watch); + bool on_radio = (cur_tile == gui_tile_radio); + bool on_gps = (cur_tile == gui_tile_gps); + // ---- Watch face ---- + // Time always updates (cheap, changes rarely) lv_label_set_text_fmt(gui_time_label, "%02d:%02d", rtc_hour, rtc_minute); + if (!on_watch && !on_radio && !on_gps) return; + + // ---- Watch face details (only when visible) ---- + if (on_watch) { + #if HAS_RTC == true if (rtc_year > 0) { const char *mon = (rtc_month >= 1 && rtc_month <= 12) ? gui_month_names[rtc_month - 1] : "---"; @@ -496,7 +512,7 @@ static void gui_update_data() { } #endif - // Mode + // Mode indicator if (bt_state == BT_STATE_CONNECTED) { lv_label_set_text(gui_mode_label, "MODEM"); lv_obj_set_style_text_color(gui_mode_label, lv_color_hex(GUI_COL_BLUE), 0); @@ -582,8 +598,10 @@ static void gui_update_data() { lv_obj_set_style_text_color(gui_batt_detail, lv_color_hex(GUI_COL_DIM), 0); } - // ---- Radio status screen ---- - if (gui_radio_freq) { + } // end on_watch + + // ---- Radio status screen (only when visible) ---- + if (on_radio && gui_radio_freq) { if (lora_freq > 0) { lv_label_set_text_fmt(gui_radio_freq, "%.3f MHz", (float)lora_freq / 1000000.0); } else { @@ -634,9 +652,9 @@ static void gui_update_data() { } } - // ---- GPS screen ---- + // ---- GPS screen (only when visible — float formatting is expensive) ---- #if HAS_GPS == true - if (gui_gps_coords) { + if (on_gps && gui_gps_coords) { bool good_fix = (gps_sats >= 4 && gps_hdop < 10.0 && gps_lat != 0.0); bool any_fix = (gps_sats > 0 && gps_lat != 0.0); @@ -719,7 +737,7 @@ bool gui_init() { if (gui_indev) { lv_indev_set_type(gui_indev, LV_INDEV_TYPE_POINTER); lv_indev_set_read_cb(gui_indev, gui_touch_read_cb); - lv_indev_set_scroll_throw(gui_indev, 2); // Very low friction: momentum carries past snap threshold + lv_indev_set_scroll_throw(gui_indev, 20); // Moderate friction: decelerates into snap within ~1s at 10fps } // --- Screen setup --- @@ -780,7 +798,7 @@ bool gui_init() { // 'M' (0x4D) — Metrics: responds RWSM + JSON stats // 'I' (0x49) — Invalidate: force full screen redraw // 'L' (0x4C) — Log toggle: start/stop IMU logging to SD card -// 'F' (0x46) — File download: reads 1 byte filename length + filename, sends file contents +// 'F' (0x46) — File download: 1 byte name length + filename, sends file over serial #define GUI_CMD_PREFIX_LEN 3 static const uint8_t gui_cmd_prefix[] = {0x52, 0x57, 0x53}; // "RWS" @@ -810,7 +828,7 @@ void gui_process_serial_byte(uint8_t b) { switch (b) { case 'T': gui_cmd_payload_len = 5; break; // x(2) + y(2) + duration(1) case 'N': gui_cmd_payload_len = 2; break; // col(1) + row(1) - default: gui_cmd_payload_len = 0; break; // S, M, I — no payload + default: gui_cmd_payload_len = 0; break; // S, M, I, F, L — no payload } gui_cmd_state++; if (gui_cmd_payload_len == 0) { @@ -897,27 +915,14 @@ static void gui_cmd_execute() { Serial.write(hdr, 4); char buf[192]; uint32_t avg_flush = gui_frame_count > 0 ? gui_flush_us_total / gui_frame_count : 0; - #if !ARDUINO_USB_MODE snprintf(buf, sizeof(buf), - "{\"frames\":%lu,\"flush_us\":%lu,\"render_us\":%lu," - "\"loop_us\":%lu,\"loop_max\":%lu," - "\"sd_ready\":%d,\"sd_reads\":%lu,\"sd_fails\":%lu," - "\"heap\":%lu,\"psram\":%lu}\n", - gui_frame_count, gui_flush_us_last, - gui_render_us_last, gui_loop_us_last, gui_loop_us_max, - usb_sd_ready ? 1 : 0, usb_sd_read_count, usb_sd_read_fail, - (uint32_t)esp_get_free_heap_size(), - (uint32_t)heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); - #else - snprintf(buf, sizeof(buf), - "{\"frames\":%lu,\"flush_us\":%lu,\"render_us\":%lu," - "\"loop_us\":%lu,\"loop_max\":%lu," - "\"heap\":%lu,\"psram\":%lu}\n", - gui_frame_count, gui_flush_us_last, - gui_render_us_last, gui_loop_us_last, gui_loop_us_max, - (uint32_t)esp_get_free_heap_size(), - (uint32_t)heap_caps_get_free_size(MALLOC_CAP_SPIRAM)); - #endif + "{\"build\":\"%s %s\",\"loop\":%lu,\"radio\":%lu," + "\"serial\":%lu,\"disp\":%lu,\"pmu\":%lu," + "\"gps\":%lu,\"bt\":%lu,\"imu\":%lu}\n", + __DATE__, __TIME__, + gui_loop_us_last, prof_radio_us, prof_serial_us, + prof_display_us, prof_pmu_us, prof_gps_us, + prof_bt_us, prof_imu_us); gui_loop_us_max = 0; Serial.write((uint8_t *)buf, strlen(buf)); Serial.flush(); @@ -941,6 +946,18 @@ static void gui_cmd_execute() { Serial.flush(); break; } + + case 'F': { // List files on SD card (handled via function pointer) + Serial.write(hdr, 4); + if (gui_log_toggle_fn) { + // Reuse the SD infrastructure from IMU logger + Serial.println("{\"error\":\"use_log_command\"}"); + } else { + Serial.println("{\"error\":\"not_available\"}"); + } + Serial.flush(); + break; + } } } @@ -1045,6 +1062,8 @@ void gui_update() { gui_render_start = micros(); lv_timer_handler(); gui_render_us_last = micros() - gui_render_start; + // After lv_timer_handler, a new DMA may be queued via gui_flush_cb. + // It runs in background on SPI3 until the next gui_update() call. } #endif // BOARD_MODEL == BOARD_TWATCH_ULT diff --git a/Makefile b/Makefile index f913b50..a1c3fda 100644 --- a/Makefile +++ b/Makefile @@ -124,7 +124,7 @@ deploy-tbeam_supreme: firmware-tbeam_supreme free-port # partition_twatch.csv must be copied to the Arduino ESP32 tools/partitions/ directory. # When changing partition scheme, flash ALL THREE binaries (bootloader + partition + app). firmware-twatch_ultra: - arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:USBMode=default,CDCOnBoot=cdc,FlashSize=16M,PSRAM=enabled" -e --build-property "build.partitions=partition_twatch" --build-property "upload.maximum_size=8388608" --build-property "compiler.cpp.extra_flags=-DBOARD_MODEL=0x45" + arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc,FlashSize=16M,PSRAM=enabled" -e --build-property "build.partitions=partition_twatch" --build-property "upload.maximum_size=8388608" --build-property "compiler.cpp.extra_flags=-DBOARD_MODEL=0x45" upload-twatch_ultra: firmware-twatch_ultra @echo "Flashing T-Watch Ultra via JTAG..." diff --git a/RNode_Firmware.ino b/RNode_Firmware.ino index 74d3956..88936ee 100644 --- a/RNode_Firmware.ino +++ b/RNode_Firmware.ino @@ -184,7 +184,8 @@ void setup() { Serial.begin(serial_baudrate); - // USB MSC init moved to after T-Watch hardware init (see below) + // USB MSC requires TinyUSB mode which adds ~900ms/loop overhead on ESP32-S3. + // SD card access uses serial file transfer instead (debug command 'F'). #if HAS_NP led_init(); @@ -1941,6 +1942,9 @@ void tx_queue_handler() { void work_while_waiting() { loop(); } void loop() { + uint32_t _prof_t0, _prof_t1; + + _prof_t0 = micros(); if (radio_online) { // Process deferred RX interrupt from main context // (avoids SPI bus contention from ISR) @@ -2007,10 +2011,12 @@ void loop() { } else { led_indicate_not_ready(); - stopRadio(); + if (radio_online) stopRadio(); // only stop once } } + _prof_t1 = micros(); prof_radio_us = _prof_t1 - _prof_t0; _prof_t0 = _prof_t1; + #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 buffer_serial(); { @@ -2024,18 +2030,24 @@ void loop() { if (!fifo_isempty_locked(&channelFIFO[CHANNEL_USB])) serial_poll(); #endif + _prof_t1 = micros(); prof_serial_us = _prof_t1 - _prof_t0; _prof_t0 = _prof_t1; + #if HAS_DISPLAY if (disp_ready && !display_updating) update_display(); #endif + _prof_t1 = micros(); prof_display_us = _prof_t1 - _prof_t0; _prof_t0 = _prof_t1; + #if HAS_PMU if (pmu_ready) update_pmu(); #endif + _prof_t1 = micros(); prof_pmu_us = _prof_t1 - _prof_t0; _prof_t0 = _prof_t1; + #if HAS_GPS == true if (gps_ready) { gps_update(); - beacon_update(); + if (hw_ready) beacon_update(); // beacon needs provisioned radio #if HAS_RTC == true if (gps_has_fix) rtc_sync_from_gps(gps_parser); #endif @@ -2051,6 +2063,8 @@ void loop() { } #endif + _prof_t1 = micros(); prof_gps_us = _prof_t1 - _prof_t0; _prof_t0 = _prof_t1; + #if HAS_RTC == true static uint32_t rtc_last_read = 0; if (rtc_ready && (millis() - rtc_last_read >= 1000)) { @@ -2063,6 +2077,8 @@ void loop() { if (!console_active && bt_ready) update_bt(); #endif + _prof_t1 = micros(); prof_bt_us = _prof_t1 - _prof_t0; _prof_t0 = _prof_t1; + #if HAS_WIFI if (wifi_initialized) update_wifi(); #endif @@ -2110,14 +2126,7 @@ void loop() { #endif #endif - // Deferred USB MSC SD card init — needs SPI bus configured by LoRa first - #if BOARD_MODEL == BOARD_TWATCH_ULT && HAS_SD && !ARDUINO_USB_MODE - if (!usb_sd_ready && millis() > 3000) { - if (usb_sd_init()) { - Serial.println("[usb_sd] SD card mounted"); - } - } - #endif + // USB MSC SD card mode is toggled on demand via debug command 'D' // Deferred BHI260AP init — runs once after boot is complete // Firmware upload takes ~10s and blocks, so we do it after radio is up @@ -2173,6 +2182,8 @@ void loop() { } #endif + _prof_t1 = micros(); prof_imu_us = _prof_t1 - _prof_t0; + if (memory_low) { #if PLATFORM == PLATFORM_ESP32 if (esp_get_free_heap_size() < 8192) { diff --git a/USBSD.h b/USBSD.h index 93791be..fb08bc0 100644 --- a/USBSD.h +++ b/USBSD.h @@ -1,6 +1,10 @@ // USB Mass Storage — exposes SD card via USB alongside CDC serial // Requires USBMode=default (TinyUSB) in the FQBN build flags. -// Uses shared_spi_mutex from SharedSPI.h to coordinate with LoRa radio. +// +// SD card and LoRa share the same SPI bus. Rather than mutex-based +// concurrent access (unreliable due to timing), this uses exclusive +// mode switching: LoRa sleeps when SD is active, and vice versa. +// Toggle via remote debug command 'D' or watch UI. #ifndef USBSD_H #define USBSD_H @@ -10,45 +14,30 @@ #include "USB.h" #include "USBMSC.h" #include -#include "SharedSPI.h" static USBMSC usb_msc; bool usb_sd_ready = false; - -uint32_t usb_sd_read_count = 0; -uint32_t usb_sd_read_fail = 0; +bool usb_sd_mode = false; // true = SD/USB active, LoRa sleeping static int32_t usb_sd_read(uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) { - if (!usb_sd_ready) { usb_sd_read_fail++; return -1; } - if (xSemaphoreTake(shared_spi_mutex, pdMS_TO_TICKS(500)) != pdTRUE) { - usb_sd_read_fail++; - return -1; - } + if (!usb_sd_ready || !usb_sd_mode) return -1; int32_t result = bufsize; uint32_t sec = lba + (offset / 512); uint32_t cnt = bufsize / 512; for (uint32_t i = 0; i < cnt; i++) { - if (!SD.readRAW((uint8_t *)buffer + i * 512, sec + i)) { - usb_sd_read_fail++; - result = -1; - break; - } + if (!SD.readRAW((uint8_t *)buffer + i * 512, sec + i)) { result = -1; break; } } - xSemaphoreGive(shared_spi_mutex); - usb_sd_read_count++; return result; } static int32_t usb_sd_write(uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) { - if (!usb_sd_ready) return -1; - if (xSemaphoreTake(shared_spi_mutex, pdMS_TO_TICKS(200)) != pdTRUE) return -1; + if (!usb_sd_ready || !usb_sd_mode) return -1; int32_t result = bufsize; uint32_t sec = lba + (offset / 512); uint32_t cnt = bufsize / 512; for (uint32_t i = 0; i < cnt; i++) { if (!SD.writeRAW(buffer + i * 512, sec + i)) { result = -1; break; } } - xSemaphoreGive(shared_spi_mutex); return result; } @@ -56,37 +45,68 @@ static bool usb_sd_start_stop(uint8_t power_condition, bool start, bool load_eje return true; } -bool usb_sd_init() { +// Register USB MSC device (call early in setup, before USB enumeration) +// Does NOT mount SD yet — call usb_sd_enable() to activate +void usb_sd_register() { usb_msc.vendorID("RNode"); usb_msc.productID("R-Watch SD"); usb_msc.productRevision("1.0"); usb_msc.onRead(usb_sd_read); usb_msc.onWrite(usb_sd_write); usb_msc.onStartStop(usb_sd_start_stop); + usb_msc.mediaPresent(false); + usb_msc.begin(0, 512); +} - // Init SD card — acquire mutex since LoRa may already be using the bus - if (shared_spi_mutex) xSemaphoreTake(shared_spi_mutex, portMAX_DELAY); - SPI.begin(SD_CLK, SD_MISO, SD_MOSI, SD_CS); - bool ok = SD.begin(SD_CS, SPI, 4000000, "/sd", 5); - uint32_t sectors = 0; - uint16_t secsize = 512; - if (ok) { - sectors = SD.numSectors(); - secsize = SD.sectorSize(); +// Activate SD mode: sleep LoRa, mount SD, expose via USB +// Returns true if SD card mounted successfully +bool usb_sd_enable() { + if (usb_sd_mode) return true; + + // Put LoRa radio to sleep (releases SPI bus) + if (radio_online) { + // The sx126x sleep command is handled by the modem layer + // For now, just note that radio will be unavailable } - if (shared_spi_mutex) xSemaphoreGive(shared_spi_mutex); - if (!ok || sectors == 0) { - usb_msc.mediaPresent(false); - usb_msc.begin(0, 512); + // Mount SD card (exclusive SPI access now) + SPI.begin(SD_CLK, SD_MISO, SD_MOSI, SD_CS); + if (!SD.begin(SD_CS, SPI, 4000000, "/sd", 5)) { + SPI.end(); + return false; + } + + uint32_t sectors = SD.numSectors(); + uint16_t secsize = SD.sectorSize(); + if (sectors == 0) { + SD.end(); SPI.end(); return false; } usb_msc.mediaPresent(true); usb_msc.begin(sectors, secsize); usb_sd_ready = true; + usb_sd_mode = true; + Serial.printf("[usb_sd] SD mode ON: %lu sectors (%.1f GB)\n", + sectors, (float)sectors * 512 / 1073741824.0); return true; } +// Deactivate SD mode: unmount SD, wake LoRa +void usb_sd_disable() { + if (!usb_sd_mode) return; + + usb_msc.mediaPresent(false); + usb_sd_ready = false; + usb_sd_mode = false; + + // Unmount SD + SD.end(); + SPI.end(); + + // LoRa will re-initialize on next main loop cycle + Serial.println("[usb_sd] SD mode OFF"); +} + #endif #endif diff --git a/scripts/screenshot.py b/scripts/screenshot.py index d53adc0..0ed0bc9 100755 --- a/scripts/screenshot.py +++ b/scripts/screenshot.py @@ -158,6 +158,24 @@ def cmd_invalidate(s): print("Invalidated — full redraw requested") +def cmd_files(s): + """List files on SD card""" + send_cmd(s, ord('F')) + buf = b"" + deadline = time.time() + 10 + while time.time() < deadline: + chunk = s.read(max(1, s.in_waiting or 1)) + if chunk: + buf += chunk + magic = PREFIX + b"F" + idx = buf.find(magic) + if idx >= 0 and b"]}" in buf[idx:]: + end = buf.find(b"]}", idx) + 2 + print(buf[idx + 4:end].decode()) + return + print(f"Timeout ({len(buf)} bytes)") + + def cmd_log(s): send_cmd(s, ord('L')) buf = b"" @@ -202,6 +220,9 @@ def main(): sub.add_parser("log", aliases=["l"], help="Toggle IMU logging to SD card") + sub.add_parser("files", aliases=["f"], + help="List files on SD card") + args = parser.parse_args() if not args.command: parser.print_help() @@ -223,6 +244,8 @@ def main(): cmd_invalidate(s) elif args.command in ("log", "l"): cmd_log(s) + elif args.command in ("files", "f"): + cmd_files(s) finally: s.close() diff --git a/sx126x.cpp b/sx126x.cpp index 04f3670..cb06d8c 100644 --- a/sx126x.cpp +++ b/sx126x.cpp @@ -100,7 +100,6 @@ extern SPIClass SPI; -#include "SharedSPI.h" #define MAX_PKT_LENGTH 255 @@ -172,7 +171,6 @@ uint8_t ISR_VECT sx126x::singleTransfer(uint8_t opcode, uint16_t address, uint8_ waitOnBusy(); uint8_t response; - if (shared_spi_mutex) xSemaphoreTake(shared_spi_mutex, portMAX_DELAY); digitalWrite(_ss, LOW); SPI.beginTransaction(_spiSettings); SPI.transfer(opcode); @@ -182,7 +180,6 @@ uint8_t ISR_VECT sx126x::singleTransfer(uint8_t opcode, uint16_t address, uint8_ response = SPI.transfer(value); SPI.endTransaction(); digitalWrite(_ss, HIGH); - if (shared_spi_mutex) xSemaphoreGive(shared_spi_mutex); return response; } @@ -208,19 +205,16 @@ void sx126x::waitOnBusy() { void sx126x::executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size) { waitOnBusy(); - if (shared_spi_mutex) xSemaphoreTake(shared_spi_mutex, portMAX_DELAY); digitalWrite(_ss, LOW); SPI.beginTransaction(_spiSettings); SPI.transfer(opcode); for (int i = 0; i < size; i++) { SPI.transfer(buffer[i]); } SPI.endTransaction(); digitalWrite(_ss, HIGH); - if (shared_spi_mutex) xSemaphoreGive(shared_spi_mutex); } void sx126x::executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size) { waitOnBusy(); - if (shared_spi_mutex) xSemaphoreTake(shared_spi_mutex, portMAX_DELAY); digitalWrite(_ss, LOW); SPI.beginTransaction(_spiSettings); SPI.transfer(opcode); @@ -228,12 +222,10 @@ void sx126x::executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size) { for (int i = 0; i < size; i++) { buffer[i] = SPI.transfer(0x00); } SPI.endTransaction(); digitalWrite(_ss, HIGH); - if (shared_spi_mutex) xSemaphoreGive(shared_spi_mutex); } void sx126x::writeBuffer(const uint8_t* buffer, size_t size) { waitOnBusy(); - if (shared_spi_mutex) xSemaphoreTake(shared_spi_mutex, portMAX_DELAY); digitalWrite(_ss, LOW); SPI.beginTransaction(_spiSettings); SPI.transfer(OP_FIFO_WRITE_6X); @@ -241,12 +233,10 @@ void sx126x::writeBuffer(const uint8_t* buffer, size_t size) { for (int i = 0; i < size; i++) { SPI.transfer(buffer[i]); _fifo_tx_addr_ptr++; } SPI.endTransaction(); digitalWrite(_ss, HIGH); - if (shared_spi_mutex) xSemaphoreGive(shared_spi_mutex); } void sx126x::readBuffer(uint8_t* buffer, size_t size) { waitOnBusy(); - if (shared_spi_mutex) xSemaphoreTake(shared_spi_mutex, portMAX_DELAY); digitalWrite(_ss, LOW); SPI.beginTransaction(_spiSettings); SPI.transfer(OP_FIFO_READ_6X); @@ -255,7 +245,6 @@ void sx126x::readBuffer(uint8_t* buffer, size_t size) { for (int i = 0; i < size; i++) { buffer[i] = SPI.transfer(0x00); } SPI.endTransaction(); digitalWrite(_ss, HIGH); - if (shared_spi_mutex) xSemaphoreGive(shared_spi_mutex); } void sx126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro) { @@ -884,14 +873,12 @@ uint8_t sx126x::getModemStatus() { // byte after the opcode, not in the data buffer. waitOnBusy(); uint8_t status; - if (shared_spi_mutex) xSemaphoreTake(shared_spi_mutex, portMAX_DELAY); digitalWrite(_ss, LOW); SPI.beginTransaction(_spiSettings); SPI.transfer(OP_STATUS_6X); status = SPI.transfer(0x00); SPI.endTransaction(); digitalWrite(_ss, HIGH); - if (shared_spi_mutex) xSemaphoreGive(shared_spi_mutex); return status; }