Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions examples/simple_repeater/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@
#define ADVERT_LON 0.0
#endif

// GPS defaults for a NEW install. Boards with a permanently-fitted GNSS (and no
// UI to switch it on) override these in their platformio.ini; every other board
// keeps the historical "GPS off, advertise the configured coordinates" defaults.
#ifndef GPS_ENABLED_DEFAULT
#define GPS_ENABLED_DEFAULT 0
#endif
#ifndef ADVERT_LOC_POLICY_DEFAULT
#define ADVERT_LOC_POLICY_DEFAULT ADVERT_LOC_PREFS
#endif

#ifndef ADMIN_PASSWORD
#define ADMIN_PASSWORD "password"
#endif
Expand Down Expand Up @@ -919,9 +929,9 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
StrHelper::strncpy(_prefs.bridge_secret, "LVSITANOS", sizeof(_prefs.bridge_secret));

// GPS defaults
_prefs.gps_enabled = 0;
_prefs.gps_enabled = GPS_ENABLED_DEFAULT;
_prefs.gps_interval = 0;
_prefs.advert_loc_policy = ADVERT_LOC_PREFS;
_prefs.advert_loc_policy = ADVERT_LOC_POLICY_DEFAULT;

_prefs.adc_multiplier = 0.0f; // 0.0f means use default board multiplier

Expand Down
4 changes: 2 additions & 2 deletions examples/simple_room_server/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -670,9 +670,9 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
#endif

// GPS defaults
_prefs.gps_enabled = 0;
_prefs.gps_enabled = GPS_ENABLED_DEFAULT;
_prefs.gps_interval = 0;
_prefs.advert_loc_policy = ADVERT_LOC_PREFS;
_prefs.advert_loc_policy = ADVERT_LOC_POLICY_DEFAULT;

#if defined(USE_SX1262) || defined(USE_SX1268)
#ifdef SX126X_RX_BOOSTED_GAIN
Expand Down
10 changes: 10 additions & 0 deletions examples/simple_room_server/MyMesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@
#define ADVERT_LON 0.0
#endif

// GPS defaults for a NEW install. Boards with a permanently-fitted GNSS (and no
// UI to switch it on) override these in their platformio.ini; every other board
// keeps the historical "GPS off, advertise the configured coordinates" defaults.
#ifndef GPS_ENABLED_DEFAULT
#define GPS_ENABLED_DEFAULT 0
#endif
#ifndef ADVERT_LOC_POLICY_DEFAULT
#define ADVERT_LOC_POLICY_DEFAULT ADVERT_LOC_PREFS
#endif

#ifndef ADMIN_PASSWORD
#define ADMIN_PASSWORD "password"
#endif
Expand Down
53 changes: 53 additions & 0 deletions variants/thinknode_m6/ThinkNodeM6Board.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,62 @@ void ThinkNodeM6Board::begin() {
digitalWrite(P_LORA_TX_LED, LOW);
#endif

// Red LED solid while booting; onBootComplete() hands it over to the heartbeat.
pinMode(PIN_LED_RED, OUTPUT);
digitalWrite(PIN_LED_RED, LED_STATE_ON);
_booting = true;

delay(10); // give sx1262 some time to power up
}

void ThinkNodeM6Board::onBootComplete() {
// Flash both LEDs together a few times. This is the one moment worth being
// loud about: it is how you confirm a freshly flashed node actually came up.
for (uint8_t i = 0; i < BOOT_FLASH_COUNT; i++) {
digitalWrite(PIN_LED_RED, LED_STATE_ON);
#ifdef P_LORA_TX_LED
digitalWrite(P_LORA_TX_LED, HIGH);
#endif
delay(BOOT_FLASH_ON_MS);
digitalWrite(PIN_LED_RED, !LED_STATE_ON);
#ifdef P_LORA_TX_LED
digitalWrite(P_LORA_TX_LED, LOW);
#endif
delay(BOOT_FLASH_OFF_MS);
}

_booting = false;
_status_cycle_start = millis();
digitalWrite(PIN_LED_RED, !LED_STATE_ON);
}

void ThinkNodeM6Board::updateStatusLed(bool gps_fix) {
if (_booting) return; // still solid-on, boot hasn't finished

unsigned long phase = millis() - _status_cycle_start; // wrap-safe
if (phase >= STATUS_LED_PERIOD_MS) {
_status_cycle_start += STATUS_LED_PERIOD_MS;
phase -= STATUS_LED_PERIOD_MS;
// Latch the pattern once per cycle so a fix flapping mid-blink can't
// produce a half-formed pulse.
_status_blinks = gps_fix ? 2 : 1;
if (phase >= STATUS_LED_PERIOD_MS) { // fell far behind (long sleep); resync
_status_cycle_start = millis();
phase = 0;
}
}

bool on = false;
for (uint8_t i = 0; i < _status_blinks; i++) {
unsigned long start = i * (unsigned long)(STATUS_LED_ON_MS + STATUS_LED_GAP_MS);
if (phase >= start && phase < start + STATUS_LED_ON_MS) {
on = true;
break;
}
}
digitalWrite(PIN_LED_RED, on ? LED_STATE_ON : !LED_STATE_ON);
}

uint16_t ThinkNodeM6Board::getBattMilliVolts() {
int adcvalue = 0;

Expand Down
32 changes: 32 additions & 0 deletions variants/thinknode_m6/ThinkNodeM6Board.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,28 @@
#define PIN_VBAT_READ BATTERY_PIN
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)

// Status LED (PIN_LED_RED, the enclosure's power LED) heartbeat timings.
// The M6 is a sealed outdoor box: a slow blink is the only way to tell a live
// node from a dead one, and to see whether the GNSS has a fix, without opening
// it up or attaching a laptop. Duty cycle is ~1% so it costs nothing on solar.
// The LEDs sit on the bottom face of the enclosure next to the USB-C port, so
// they are read at arm's length in daylight -- a blink has to be long enough to
// actually catch the eye. 150ms is comfortably visible and still only ~3% duty.
#define STATUS_LED_PERIOD_MS 5000 // one heartbeat every 5s
#define STATUS_LED_ON_MS 150 // length of each blink
#define STATUS_LED_GAP_MS 200 // dark gap between blinks of a double-blink

// Unmistakable "firmware is alive" signature at the end of setup(), so a fresh
// flash can be confirmed without a serial console.
#define BOOT_FLASH_COUNT 3
#define BOOT_FLASH_ON_MS 120
#define BOOT_FLASH_OFF_MS 120

class ThinkNodeM6Board : public NRF52BoardDCDC {
bool _booting = true;
unsigned long _status_cycle_start = 0;
uint8_t _status_blinks = 1;

protected:
#if NRF52_POWER_MANAGEMENT
void initiateShutdown(uint8_t reason) override;
Expand All @@ -23,6 +44,16 @@ class ThinkNodeM6Board : public NRF52BoardDCDC {
void begin();
uint16_t getBattMilliVolts() override;

// Boot indicator: red LED stays solid from begin() until the sketch reports
// that setup() finished, so a boot loop is visible as a flickering LED.
void onBootComplete() override;

// Drives the red LED heartbeat. Called every iteration from the variant's
// sensor manager, which is the one place that knows the live GNSS state:
// 1 blink / 5s -> running, no GPS fix (yet)
// 2 blinks / 5s -> running, GPS fix acquired
void updateStatusLed(bool gps_fix);

#if defined(P_LORA_TX_LED)
void onBeforeTransmit() override {
digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED on
Expand All @@ -42,6 +73,7 @@ class ThinkNodeM6Board : public NRF52BoardDCDC {
#ifdef P_LORA_TX_LED
digitalWrite(P_LORA_TX_LED, LOW);
#endif
digitalWrite(PIN_LED_RED, LOW);

// power off board
NRF52Board::powerOff();
Expand Down
17 changes: 17 additions & 0 deletions variants/thinknode_m6/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ build_flags =
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D MAX_NEIGHBOURS=50
; The L76K GNSS is soldered to the M6 and the enclosure is sealed, so there is
; no button or screen to switch GPS on with. Skip the 1s "is a GPS attached?"
; probe (it gates the 'gps' setting, and losing that race leaves GPS
; unreachable until reboot), enable GPS for new installs, and advertise the
; position the GNSS actually reports instead of the fixed 0,0 above.
; All of it stays changeable at runtime over the serial CLI: 'gps on'/'gps off',
; 'gps advert prefs|share|none', and bare 'gps' to print fix + satellite count.
-D ENV_SKIP_GPS_DETECT=1
-D GPS_ENABLED_DEFAULT=1
-D ADVERT_LOC_POLICY_DEFAULT=ADVERT_LOC_SHARE
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
; -D GPS_NMEA_DEBUG=1
Expand All @@ -64,6 +74,13 @@ build_flags =
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
; Same reasoning as the repeater env above: the L76K is soldered on and the
; enclosure is sealed, so GPS has to come up enabled and advertise the position
; the GNSS actually reports. Runtime CLI still wins ('gps on'/'gps off',
; 'gps advert prefs|share|none').
-D ENV_SKIP_GPS_DETECT=1
-D GPS_ENABLED_DEFAULT=1
-D ADVERT_LOC_POLICY_DEFAULT=ADVERT_LOC_SHARE
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${ThinkNode_M6.build_src_filter}
Expand Down
14 changes: 12 additions & 2 deletions variants/thinknode_m6/target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,19 @@ VolatileRTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifdef ENV_INCLUDE_GPS
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock);
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
ThinkNodeM6SensorManager sensors = ThinkNodeM6SensorManager(nmea);

void ThinkNodeM6SensorManager::loop() {
EnvironmentSensorManager::loop();
board.updateStatusLed(gps_active && _location != NULL && _location->isValid());
}
#else
EnvironmentSensorManager sensors = EnvironmentSensorManager();
ThinkNodeM6SensorManager sensors = ThinkNodeM6SensorManager();

void ThinkNodeM6SensorManager::loop() {
EnvironmentSensorManager::loop();
board.updateStatusLed(false);
}
#endif

#ifdef DISPLAY_CLASS
Expand Down
20 changes: 19 additions & 1 deletion variants/thinknode_m6/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,28 @@
#include <helpers/ui/MomentaryButton.h>
#endif

// Wraps the stock environment sensor manager purely to drive the status LED.
// Its loop() is already called every iteration by every example sketch, and it
// is the only place holding the live GNSS state, so it is where the board gets
// told whether to blink once (no fix) or twice (fix).
#ifdef ENV_INCLUDE_GPS
class ThinkNodeM6SensorManager : public EnvironmentSensorManager {
public:
ThinkNodeM6SensorManager(LocationProvider& location) : EnvironmentSensorManager(location) { }
void loop() override;
};
#else
class ThinkNodeM6SensorManager : public EnvironmentSensorManager {
public:
ThinkNodeM6SensorManager() : EnvironmentSensorManager() { }
void loop() override;
};
#endif

extern ThinkNodeM6Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern EnvironmentSensorManager sensors;
extern ThinkNodeM6SensorManager sensors;

#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
Expand Down