Files
MeshCore-Solo/variants/wio-tracker-l2/WioTrackerL2Board.h
T
JakubandClaude Opus 5.5 23caa11f51 feat(ui-lvgl): power saving, review fixes, shared helpers
Power: the UI loop sleeps until something is due (never with packets
queued); screen off puts the CPU at 80 MHz, the GT911 to sleep (unless a
tap wakes the screen) and the LP5814 in standby. GPS off now cuts the
L76K's rail and UART on the L2 (L2GpsProvider). The battery divider is
powered only for a reading (measured: settles at once); readings within
2 s are reused. The SD mount is retried at most every 5 s.

Fixes: WiFi left on after leaving a scan, live tiles' WiFi kept with the
screen off on the map, an ADC read every second for the status bar, touch
polled on every pass while dark, a scan cutting an update's WiFi, relay
count not refreshing in a channel thread, raw @[nick] in room previews.
Labels skip unchanged text (no redraw).

Helpers: scrollList, dimOverlay, settingRow, flexBox, nvs::get/put,
trailFilePath (a second save in the same minute no longer overwrites),
unreadTotal. Dead code removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 00:12:08 +02:00

117 lines
4.6 KiB
C++

#pragma once
#include <Arduino.h>
#include <Wire.h>
#include "helpers/ESP32Board.h"
// ---------------------------------------------------------------------------
// Seeed Wio Tracker L2 Pro (Wio-S3 module: ESP32-S3 + SX1262)
//
// Nearly all peripheral power rails and reset lines are behind a TCA9535
// 16-bit I2C IO expander at address 0x21. Nothing (GNSS, LCD, touch, SD,
// battery ADC, speaker amp) works until the expander is configured, so
// begin() must run before any display / GPS / sensor init.
//
// Battery voltage is read through an ADS1115 16-bit I2C ADC at 0x48,
// channel AIN0, behind a x2 resistive divider (rail gated by expander).
// ---------------------------------------------------------------------------
#define TCA9535_ADDR 0x21
#define ADS1115_ADDR 0x48
// TCA9535 pin numbering: 0..7 = port 0 (P00..P07), 8..15 = port 1 (P10..P17)
#define EXP_PIN_WAKE_BTN 0 // input - WAKE button (top edge)
#define EXP_PIN_I2C_IRQ 1 // input - shared I2C IRQ
#define EXP_PIN_SD_DETECT 2 // input - microSD card detect
#define EXP_PIN_TP_INT 3 // output - touch panel interrupt (driven for reset seq)
#define EXP_PIN_LCD_CS 4 // output - LCD chip select (idle high)
#define EXP_PIN_LCD_EN 5 // output - LCD power enable
#define EXP_PIN_LCD_RST 6 // output - LCD reset
#define EXP_PIN_GROVE_EN 7 // output - Grove port power
#define EXP_PIN_TP_RST 8 // output - touch panel reset
#define EXP_PIN_GNSS_RST 9 // output - GNSS reset (active HIGH)
#define EXP_PIN_USER_LED 10 // output - mesh/user LED (also GNSS wakeup)
#define EXP_PIN_OTG_EN 11 // output - USB OTG power
#define EXP_PIN_PA_EN 12 // output - speaker amp power
#define EXP_PIN_GNSS_EN 13 // output - GNSS power
#define EXP_PIN_TF_EN 14 // output - microSD power
#define EXP_PIN_BAT_ADC_EN 15 // output - battery ADC divider enable
class WioTrackerL2Board : public ESP32Board {
public:
void begin();
uint16_t getBattMilliVolts() override;
const char* getManufacturerName() const override {
return "Seeed Wio Tracker L2 Pro";
}
void onBeforeTransmit() override { setLed(true); }
void onAfterTransmit() override { setLed(false); }
// Mesh/user LED lives on the IO expander, not a GPIO
void setLed(bool on);
// speaker amplifier power (expander P12); off when idle to keep the GNSS
// antenna away from class-D switching noise and to save battery
void setSpeakerAmp(bool on) { expWritePin(EXP_PIN_PA_EN, on); }
// GNSS rail: off saves the whole receiver when GPS is disabled; on re-runs
// the power-up reset so the module comes back cleanly
void setGnssPower(bool on) {
if (on) {
expWritePin(EXP_PIN_GNSS_EN, HIGH);
delay(10);
gnssReset();
} else {
expWritePin(EXP_PIN_GNSS_EN, LOW);
}
}
// Grove expansion port rail (nothing on-board depends on it)
void setGrovePower(bool on) { expWritePin(EXP_PIN_GROVE_EN, on); }
bool gnssPowered() const { return (out_shadow[EXP_PIN_GNSS_EN >> 3] >> (EXP_PIN_GNSS_EN & 7)) & 1; }
// hardware reset pulse to the L76K GNSS (active HIGH on this board); the
// module keeps almanac/ephemeris across it, so this is a warm restart
void gnssReset() {
expWritePin(EXP_PIN_GNSS_RST, HIGH);
delay(10);
expWritePin(EXP_PIN_GNSS_RST, LOW);
}
// WAKE button on expander P00: pressed = level differs from boot baseline
bool readWakeButton();
// GT911 touch controller: sleep (a few mA -> tens of uA) while the screen is
// off and a touch shouldn't wake it; wake with a pulse on its INT line.
void touchSleep();
void touchWake();
// 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; }
private:
uint8_t out_shadow[2] = { 0xFF, 0xFF }; // TCA9535 output regs default high
uint8_t cfg_shadow[2] = { 0xFF, 0xFF }; // 1 = input (power-on default)
bool expander_ok = false;
bool aw_ok = false; // AW35615 USB-C controller responded at probe
uint8_t wake_btn_baseline = 0; // idle level of P00, captured at init
uint16_t batt_mv_last = 0; // last good battery reading (a failed read keeps it)
uint32_t batt_read_ms = 0; // when it was taken (reads closer together reuse it)
int expReadInputs(); // 16-bit input register pair, -1 on error
bool expWriteReg(uint8_t reg, uint8_t val);
void expSetOutput(uint8_t pin, bool initial_level);
void expSetInput(uint8_t pin);
void expWritePin(uint8_t pin, bool level);
bool initExpander();
int16_t adsReadRaw();
};