This commit is contained in:
Michael A. Cojocari committed 2026-09-05 15:16:56 -04:00
1 parent 3749df2907
commit d4ed6df92e
4 files changed
+96 -5

No files matched your search

+81 -3
View File
@@ -11,9 +11,10 @@
// is exactly the build-fragile dependency patch this repo avoids. So the
// provider is re-owned here: same behaviour line for line (claim/release, the
// time-sync rules from #89's follow-up, GPS_EN/GPS_RESET polarity macros from
// the core header), plus motion(). Boards opt in by constructing this class in
// their target.cpp instead of the core one and defining HAS_GPS_MOTION; the
// wada.sys.gps() binding then reports speed_kmh/course on that board.
// the core header), plus motion() and optional checksum-driven UART baud
// recovery. Boards opt in by constructing this class in their target.cpp
// instead of the core one. HAS_GPS_MOTION exposes speed/course to Lua; passing
// the UART probe arguments enables baud recovery independently.
//
// Kept in lock-step with the core header it mirrors (meshcomod core-v1.17.4);
// if the core provider gains behaviour, port it here too. ONE deliberate
@@ -24,6 +25,7 @@
#include <MicroNMEA.h>
#include <RTClib.h>
#include <helpers/RefCountedDigitalPin.h>
#include "esp32/TouchPrefsStore.h"
#include <limits.h>
class WadaNmeaLocationProvider : public LocationProvider {
@@ -38,7 +40,54 @@ class WadaNmeaLocationProvider : public LocationProvider {
unsigned long next_check = 0;
long time_valid = 0;
unsigned long _last_time_sync = 0;
HardwareSerial* _probe_serial = nullptr;
int8_t _probe_rx = -1;
int8_t _probe_tx = -1;
uint8_t _probe_cursor = 0;
uint32_t _probe_default_baud = 0;
uint32_t _active_baud = 0;
uint32_t _probe_deadline_ms = 0;
bool _stream_locked = false;
static const unsigned long TIME_SYNC_INTERVAL = 1800000; // re-sync every 30 minutes
static const unsigned long BAUD_PROBE_START_MS = 9000;
static const unsigned long BAUD_PROBE_INTERVAL_MS = 5000;
void nudgeReceiver() {
if (!_probe_serial) return;
_probe_serial->write((uint8_t)'\r');
_probe_serial->write((uint8_t)'\n');
_probe_serial->flush();
}
void probeNextBaud() {
if (!_probe_serial || _probe_rx < 0) return;
const uint32_t candidates[] = {
_probe_default_baud, 9600u, 19200u, 38400u, 57600u, 115200u
};
for (size_t attempt = 0; attempt < sizeof(candidates) / sizeof(candidates[0]); ++attempt) {
const uint32_t candidate = candidates[_probe_cursor];
_probe_cursor = (uint8_t)((_probe_cursor + 1) %
(sizeof(candidates) / sizeof(candidates[0])));
if (candidate == 0 || candidate == _active_baud) continue;
_probe_serial->end();
_probe_serial->setPins(_probe_rx, _probe_tx);
_probe_serial->begin(candidate);
nmea.clear();
time_valid = 0;
_active_baud = candidate;
_probe_deadline_ms = millis() + BAUD_PROBE_INTERVAL_MS;
nudgeReceiver();
return;
}
}
void noteValidSentence() {
if (!_probe_serial || _stream_locked) return;
_stream_locked = true;
_probe_deadline_ms = 0;
if (touchPrefsGetGpsBaud(_probe_default_baud) != _active_baud)
(void)touchPrefsSetGpsBaud(_active_baud);
}
public:
WadaNmeaLocationProvider(Stream& ser, mesh::RTCClock* clock = NULL, int pin_reset = GPS_RESET,
@@ -66,6 +115,16 @@ public:
}
}
WadaNmeaLocationProvider(HardwareSerial& ser, mesh::RTCClock* clock,
int pin_reset, int pin_en, int serial_rx, int serial_tx,
uint32_t default_baud)
: WadaNmeaLocationProvider(static_cast<Stream&>(ser), clock, pin_reset, pin_en) {
_probe_serial = &ser;
_probe_rx = (int8_t)serial_rx;
_probe_tx = (int8_t)serial_tx;
_probe_default_baud = default_baud;
}
void claim() {
_claims++;
if (_peripher_power) _peripher_power->claim();
@@ -81,6 +140,13 @@ public:
claim();
if (_pin_en != -1) digitalWrite(_pin_en, GPS_EN_ACTIVE);
if (_pin_reset != -1) digitalWrite(_pin_reset, !GPS_RESET_ACTIVE);
if (_probe_serial) {
_active_baud = touchPrefsGetGpsBaud(_probe_default_baud);
_probe_cursor = 0;
_stream_locked = false;
_probe_deadline_ms = millis() + BAUD_PROBE_START_MS;
nudgeReceiver();
}
}
void reset() override {
@@ -97,6 +163,8 @@ public:
// circuits (see the constructor comment; on the M9 "asserted" = GPIO HIGH
// through R46 into Q16's base = a constant drain while the GPS is off).
if (_pin_reset != -1) digitalWrite(_pin_reset, LOW);
_probe_deadline_ms = 0;
_stream_locked = false;
release();
}
@@ -153,9 +221,19 @@ public:
#ifdef GPS_NMEA_DEBUG
Serial.print(c);
#endif
const bool sentence_end = c == '\r' || c == '\n';
nmea.process(c);
if (sentence_end) {
const char* sentence = nmea.getSentence();
if (sentence && sentence[0] == '$' && MicroNMEA::testChecksum(sentence))
noteValidSentence();
}
}
if (_probe_serial && !_stream_locked && _probe_deadline_ms &&
(int32_t)(millis() - _probe_deadline_ms) >= 0)
probeNextBaud();
if (!isValid()) time_valid = 0;
if ((long)(millis() - next_check) > 0) {
+12
View File
@@ -36644,15 +36644,27 @@ static void refreshChatList(LvChatPanel& p) {
// Avatar: same FNV-1a hue family as the chat-bubble colours (see
// usernameBubbleColors), lifted in value so the disc reads on the dark panel.
#if !defined(HAS_TDECK_PRO)
uint32_t hh = 2166136261u;
for (const char* s2 = name; *s2; ++s2) { hh ^= (uint8_t)*s2; hh *= 16777619u; }
#endif
lv_obj_t* av = lv_obj_create(btn);
lv_obj_remove_style_all(av);
lv_obj_add_flag(av, LV_OBJ_FLAG_IGNORE_LAYOUT);
lv_obj_clear_flag(av, LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_SCROLLABLE); // taps fall through to the row
lv_obj_set_size(av, kThreadAvatar, kThreadAvatar);
lv_obj_set_style_radius(av, LV_RADIUS_CIRCLE, LV_PART_MAIN);
#if defined(HAS_TDECK_PRO)
// Every generated avatar hue falls below the e-paper luminance threshold,
// as does the black initials/emoji ink. Use an outlined paper-white disc
// so the glyph remains visible after RGB565 is reduced to one bit.
lv_obj_set_style_bg_color(av, lv_color_white(), LV_PART_MAIN);
lv_obj_set_style_border_color(av, lv_color_black(), LV_PART_MAIN);
lv_obj_set_style_border_width(av, 2, LV_PART_MAIN);
lv_obj_set_style_border_opa(av, LV_OPA_COVER, LV_PART_MAIN);
#else
lv_obj_set_style_bg_color(av, lv_color_hsv_to_rgb((uint16_t)(hh % 360u), 55, 42), LV_PART_MAIN);
#endif
lv_obj_set_style_bg_opa(av, LV_OPA_COVER, LV_PART_MAIN);
lv_obj_align(av, LV_ALIGN_LEFT_MID, 8, 0);
// Avatar content: a user-chosen emoji for channels (thread sheet -> Chat icon),
+2 -1
View File
@@ -8,7 +8,8 @@ WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
ClockFloorRTC rtc_clock(fallback_clock);
MicroNMEALocationProvider gps(Serial1, &rtc_clock);
WadaNmeaLocationProvider gps(Serial1, &rtc_clock, GPS_RESET, GPS_EN,
PIN_GPS_TX, PIN_GPS_RX, GPS_BAUD_RATE);
EnvironmentSensorManager sensors(gps);
TDeckProDisplay display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
+1 -1
View File
@@ -12,8 +12,8 @@
#include "TDeckProBoard.h"
#include "TDeckProDisplay.h"
#include "../../src/helpers/ClockFloorRTC.h"
#include "../../src/helpers/WadaNmeaLocationProvider.h"
#include "helpers/sensors/EnvironmentSensorManager.h"
#include "helpers/sensors/MicroNMEALocationProvider.h"
extern TDeckProBoard board;
extern WRAPPER_CLASS radio_driver;