mirror of
https://github.com/markqvist/RNode_Firmware.git
synced 2026-04-28 09:43:08 +00:00
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)
112 lines
3.3 KiB
C
112 lines
3.3 KiB
C
// USB Mass Storage — exposes SD card via USB alongside CDC serial
|
|
// Requires USBMode=default (TinyUSB) in the FQBN build flags.
|
|
//
|
|
// 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
|
|
|
|
#if BOARD_MODEL == BOARD_TWATCH_ULT && HAS_SD && !ARDUINO_USB_MODE
|
|
|
|
#include "USB.h"
|
|
#include "USBMSC.h"
|
|
#include <SD.h>
|
|
|
|
static USBMSC usb_msc;
|
|
bool usb_sd_ready = false;
|
|
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_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)) { result = -1; break; }
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static int32_t usb_sd_write(uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
|
|
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; }
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static bool usb_sd_start_stop(uint8_t power_condition, bool start, bool load_eject) {
|
|
return true;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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
|