From f849ee0b0037256f3f363a16f2c4036ac3625e6e Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Sat, 26 Sep 2026 22:12:05 +0200 Subject: [PATCH] fix(wio-tracker-l2): USB power detection works - charge bolt, Power row, GPS hint - The AW35615 USB-C controller (FUSB302-style registers, ID 0x91) only reports VBUSOK with its measure block on; POWER resets to bandgap only, so isExternalPowered() was always false. Board init turns it on - Status bar shows a charge bolt on the cable, Diagnostics > Live has a Power row, the GPS screen notes that charging disturbs GPS, and the low-battery warning is skipped on USB as intended - Roadmap: USB detection closed; GPS indoors still worse than the L1 even on battery, left open for later Co-Authored-By: Claude Opus 5.5 --- docs/development/l2-roadmap.md | 18 ++++++----- examples/companion_radio/ui-lvgl/DiagScreen.h | 3 +- examples/companion_radio/ui-lvgl/GpsScreen.h | 6 +++- examples/companion_radio/ui-lvgl/UITask.cpp | 2 +- variants/wio-tracker-l2/WioTrackerL2Board.cpp | 31 +++++++++++++++---- variants/wio-tracker-l2/WioTrackerL2Board.h | 1 + 6 files changed, 45 insertions(+), 16 deletions(-) diff --git a/docs/development/l2-roadmap.md b/docs/development/l2-roadmap.md index 9ac90eb0..d9c69e98 100644 --- a/docs/development/l2-roadmap.md +++ b/docs/development/l2-roadmap.md @@ -196,13 +196,12 @@ this roadmap is done; the Cardputer follows whatever the spike shows. ## Backlog (found along the way) -- [ ] USB power detection: `WioTrackerL2Board::isExternalPowered()` reads - STATUS0 (0x40) bit 7 of the chip at I2C 0x22 and always gets 0 with - USB plugged in (0x40 reads 0x01). Needed for a charging indicator and - for skipping the low-battery shutdown on the cable. Find the right - chip / register (devices on the bus: 0x14, 0x18, 0x21, 0x22, 0x2c, - 0x34, 0x48, 0x5d). Found 2026-09-26. Also wanted for a hint on the - GPS screen while on the cable (see below). +- [x] USB power detection (fixed 2026-09-26): the AW35615 at 0x22 has a + FUSB302-style register map (device ID 0x91); VBUSOK (STATUS0 bit 7) + needs the measure block on, and POWER (0x0B) resets to 0x01. Board + init sets PWR[1..2]; STATUS0 then reads 0x80 on USB. Used by the + status bar (charge bolt), Diagnostics > Live "Power", the GPS screen + hint and the low-battery warning (skipped on the cable). - [x] GPS screen (2026-09-26): Home > GPS and Settings > System > GPS details -- sky plot, C/N0 bar per satellite, fix / TTFF / DOPs, per-constellation counts (helpers/sensors/GpsSky.h, -D GPS_SKYVIEW; @@ -214,6 +213,11 @@ this roadmap is done; the Cardputer follows whatever the spike shows. seconds, first fix after 377 s. Screen, WiFi, Bluetooth and LoRa TX were ruled out. Cause: noise from USB power / the charger -- a board property, not fixable in firmware. Test GPS on battery. +- [ ] GPS indoors, still open (user, 2026-09-26): even on battery the L2 + does worse than the L1 with the same L76K -- first fix after 377 s by + a window, 4 of 22 satellites used, the fix drops and comes back. + Something is still off (antenna / placement / another noise source); + look again later with the GPS screen, e.g. side by side with the L1. Ideas to come back to (2026-09-26): diff --git a/examples/companion_radio/ui-lvgl/DiagScreen.h b/examples/companion_radio/ui-lvgl/DiagScreen.h index 7edd0b41..beec19e7 100644 --- a/examples/companion_radio/ui-lvgl/DiagScreen.h +++ b/examples/companion_radio/ui-lvgl/DiagScreen.h @@ -10,7 +10,7 @@ namespace diagview { enum : uint8_t { TAB_LIVE, TAB_SYSTEM, TAB_FONT, TAB_COUNT }; static uint8_t s_tab = TAB_LIVE; // kept across visits static lv_obj_t* s_list = nullptr; -static const int EXTRA = 3; // GPS, last reset, last crash (L2 only) +static const int EXTRA = 4; // GPS, power, last reset, last crash (L2 only) static lv_obj_t* s_vals[diag::MAX_ROWS + EXTRA]; static int s_rows = 0; @@ -34,6 +34,7 @@ static int allRows(diag::Row* rows, bool gps_on) { if (!gps_on) extraRow(rows, n, "GPS", "off"); else if (!data) extraRow(rows, n, "GPS", "no data (%lu B)", (unsigned long)c); else extraRow(rows, n, "GPS", "%s, %ld sats", gps.isValid() ? "fix" : "no fix", gps.satellitesCount()); + extraRow(rows, n, "Power", "%s", board.isExternalPowered() ? "USB" : "battery"); #else (void)gps_on; #endif diff --git a/examples/companion_radio/ui-lvgl/GpsScreen.h b/examples/companion_radio/ui-lvgl/GpsScreen.h index f84c6b79..cb8db698 100644 --- a/examples/companion_radio/ui-lvgl/GpsScreen.h +++ b/examples/companion_radio/ui-lvgl/GpsScreen.h @@ -348,7 +348,7 @@ void UITask::refreshGps() { if (off) lv_obj_remove_flag(s_on_btn, LV_OBJ_FLAG_HIDDEN); else lv_obj_add_flag(s_on_btn, LV_OBJ_FLAG_HIDDEN); - char used[48] = "", info[200] = ""; + char used[48] = "", info[240] = ""; if (!g) { lv_label_set_text(s_status, "Not available"); lv_obj_set_style_text_color(s_status, lv_color_hex(theme::TEXT_MUTED), 0); @@ -387,6 +387,10 @@ void UITask::refreshGps() { o += snprintf(info + o, sizeof(info) - o, "%.0f m - %.1f km/h\n", g->alt_m, g->speed_kmh); if (g->utc_valid) o += snprintf(info + o, sizeof(info) - o, "UTC %02u:%02u:%02u", g->utc_h, g->utc_m, g->utc_s); } + if (g && !off && _board->isExternalPowered()) { // measured: on the cable the L76K never decodes indoors + size_t o = strlen(info); + snprintf(info + o, sizeof(info) - o, "%sOn USB power: charging disturbs GPS", o ? "\n" : ""); + } lv_label_set_text(s_used, used); lv_label_set_text(s_info, info); diff --git a/examples/companion_radio/ui-lvgl/UITask.cpp b/examples/companion_radio/ui-lvgl/UITask.cpp index f184efe7..23dcc9c6 100644 --- a/examples/companion_radio/ui-lvgl/UITask.cpp +++ b/examples/companion_radio/ui-lvgl/UITask.cpp @@ -616,7 +616,7 @@ void UITask::refreshStatusBar() { case battery::VOLTAGE: snprintf(level, sizeof(level), " %u.%02u V", mv / 1000, (mv % 1000) / 10); break; default: break; } - lv_label_set_text_fmt(_status_batt, "%s%s", batt, level); + lv_label_set_text_fmt(_status_batt, "%s%s%s", _board->isExternalPowered() ? LV_SYMBOL_CHARGE " " : "", batt, level); // Status icons, as the original's status bar (ui-new): Bluetooth (bright // when the app is connected), GPS (green with a fix), the alarm, mute, then diff --git a/variants/wio-tracker-l2/WioTrackerL2Board.cpp b/variants/wio-tracker-l2/WioTrackerL2Board.cpp index ecdc25a7..0560fa3f 100644 --- a/variants/wio-tracker-l2/WioTrackerL2Board.cpp +++ b/variants/wio-tracker-l2/WioTrackerL2Board.cpp @@ -125,6 +125,20 @@ void WioTrackerL2Board::begin() { Wire.beginTransmission(0x22); aw_ok = Wire.endTransmission() == 0; + if (aw_ok) { + // AW35615 = FUSB302-style register map. VBUSOK (STATUS0 bit 7) only + // works with the measure block powered: POWER (0x0B) resets to 0x01 + // (bandgap only), which reads "no USB" forever. Add the receiver / + // current references and the measure block (PWR[1..2]). + // Verified on hardware: device ID 0x91; STATUS0 0x01 -> 0x80 on USB. + int pw = awRead(0x0B); + if (pw >= 0) { + Wire.beginTransmission(0x22); + Wire.write((uint8_t)0x0B); + Wire.write((uint8_t)(pw | 0x07)); + Wire.endTransmission(); + } + } MESH_DEBUG_PRINTLN("WioTrackerL2Board: init done"); esp_reset_reason_t reason = esp_reset_reason(); @@ -156,13 +170,18 @@ int WioTrackerL2Board::expReadInputs() { return lo | (hi << 8); } -bool WioTrackerL2Board::isExternalPowered() { - if (!aw_ok) return false; +int WioTrackerL2Board::awRead(uint8_t reg) { + if (!aw_ok) return -1; Wire.beginTransmission(0x22); - Wire.write((uint8_t)0x40); // STATUS0 - if (Wire.endTransmission() != 0) return false; - if (Wire.requestFrom(0x22, 1) != 1) return false; - return (Wire.read() & 0x80) != 0; // VBUSOK bit + Wire.write(reg); + if (Wire.endTransmission() != 0) return -1; + if (Wire.requestFrom(0x22, 1) != 1) return -1; + return Wire.read(); +} + +bool WioTrackerL2Board::isExternalPowered() { + int st0 = awRead(0x40); // STATUS0 + return st0 >= 0 && (st0 & 0x80) != 0; // VBUSOK } bool WioTrackerL2Board::readWakeButton() { diff --git a/variants/wio-tracker-l2/WioTrackerL2Board.h b/variants/wio-tracker-l2/WioTrackerL2Board.h index 47ce561f..60ef6e6e 100644 --- a/variants/wio-tracker-l2/WioTrackerL2Board.h +++ b/variants/wio-tracker-l2/WioTrackerL2Board.h @@ -84,6 +84,7 @@ public: // VBUS presence via the AW35615 USB-C controller (I2C 0x22) bool isExternalPowered() override; + int awRead(uint8_t reg); // AW35615 register, -1 on error bool expanderOK() const { return expander_ok; }