From 59a236effb231fd4240d7cbffd9d287a3839fc25 Mon Sep 17 00:00:00 2001 From: JQ Date: Tue, 27 May 2025 21:38:48 -0700 Subject: [PATCH 1/2] add GPS support to thinknode M1 --- variants/thinknode_m1/platformio.ini | 3 + variants/thinknode_m1/target.cpp | 92 +++++++++++++++++++++++++++- variants/thinknode_m1/target.h | 21 ++++++- variants/thinknode_m1/variant.h | 10 +-- 4 files changed, 119 insertions(+), 7 deletions(-) diff --git a/variants/thinknode_m1/platformio.ini b/variants/thinknode_m1/platformio.ini index 9bad98e2..846c96ec 100644 --- a/variants/thinknode_m1/platformio.ini +++ b/variants/thinknode_m1/platformio.ini @@ -25,6 +25,9 @@ build_src_filter = ${nrf52840_thinknode_m1.build_src_filter} + + +<../variants/thinknode_m1> +lib_deps = + ${nrf52840_thinknode_m1.lib_deps} + stevemarple/MicroNMEA @ ^2.0.6 debug_tool = jlink upload_protocol = nrfutil diff --git a/variants/thinknode_m1/target.cpp b/variants/thinknode_m1/target.cpp index 5a09eb9a..c88ab848 100644 --- a/variants/thinknode_m1/target.cpp +++ b/variants/thinknode_m1/target.cpp @@ -1,6 +1,7 @@ #include #include "target.h" #include +#include ThinkNodeM1Board board; @@ -10,7 +11,8 @@ WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); -SensorManager sensors; +MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); +ThinkNodeM1SensorManager sensors = ThinkNodeM1SensorManager(nmea); #ifdef DISPLAY_CLASS DISPLAY_CLASS display; @@ -72,3 +74,91 @@ mesh::LocalIdentity radio_new_identity() { RadioNoiseListener rng(radio); return mesh::LocalIdentity(&rng); // create new random identity } + +void ThinkNodeM1SensorManager::start_gps() { + if (!gps_active) { + gps_active = true; + _location->begin(); + } +} + +void ThinkNodeM1SensorManager::stop_gps() { + if (gps_active) { + gps_active = false; + _location->stop(); + } +} + +bool ThinkNodeM1SensorManager::begin() { + Serial1.begin(9600); + + // Try to detect if GPS is physically connected to determine if we should expose the setting + pinMode(GPS_EN, OUTPUT); + digitalWrite(GPS_EN, HIGH); // Power on GPS + + // Give GPS a moment to send data if it's physically connected and powered + delay(1500); + + // We'll consider GPS detected if we see any data on Serial1 + gps_detected = (Serial1.available() > 0); + + if (gps_detected) { + MESH_DEBUG_PRINTLN("GPS detected"); + digitalWrite(GPS_EN, LOW); // Power off GPS until the setting is changed + } else { + MESH_DEBUG_PRINTLN("No GPS detected"); + digitalWrite(GPS_EN, LOW); + } + + return true; +} + +bool ThinkNodeM1SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { + if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? + telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); + } + return true; +} + +void ThinkNodeM1SensorManager::loop() { + static long next_gps_update = 0; + + _location->loop(); + + if (millis() > next_gps_update) { + if (_location->isValid()) { + node_lat = ((double)_location->getLatitude())/1000000.; + node_lon = ((double)_location->getLongitude())/1000000.; + node_altitude = ((double)_location->getAltitude()) / 1000.0; + MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); + } + next_gps_update = millis() + 1000; + } +} + +int ThinkNodeM1SensorManager::getNumSettings() const { + return gps_detected ? 1 : 0; // only show GPS setting if GPS is detected +} + +const char* ThinkNodeM1SensorManager::getSettingName(int i) const { + return (gps_detected && i == 0) ? "gps" : NULL; +} + +const char* ThinkNodeM1SensorManager::getSettingValue(int i) const { + if (gps_detected && i == 0) { + return gps_active ? "1" : "0"; + } + return NULL; +} + +bool ThinkNodeM1SensorManager::setSettingValue(const char* name, const char* value) { + if (gps_detected && strcmp(name, "gps") == 0) { + if (strcmp(value, "0") == 0) { + stop_gps(); + } else { + start_gps(); + } + return true; + } + return false; // not supported +} diff --git a/variants/thinknode_m1/target.h b/variants/thinknode_m1/target.h index c958d0e3..7f7a1055 100644 --- a/variants/thinknode_m1/target.h +++ b/variants/thinknode_m1/target.h @@ -7,14 +7,33 @@ #include #include #include +#include #ifdef DISPLAY_CLASS #include #endif +class ThinkNodeM1SensorManager : public SensorManager { + bool gps_active = false; + bool gps_detected = false; + LocationProvider* _location; + + void start_gps(); + void stop_gps(); +public: + ThinkNodeM1SensorManager(LocationProvider &location): _location(&location) { } + bool begin() override; + bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; + void loop() override; + int getNumSettings() const override; + const char* getSettingName(int i) const override; + const char* getSettingValue(int i) const override; + bool setSettingValue(const char* name, const char* value) override; +}; + extern ThinkNodeM1Board board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; -extern SensorManager sensors; +extern ThinkNodeM1SensorManager sensors; #ifdef DISPLAY_CLASS extern DISPLAY_CLASS display; diff --git a/variants/thinknode_m1/variant.h b/variants/thinknode_m1/variant.h index 3f35ace0..8e4e90bf 100644 --- a/variants/thinknode_m1/variant.h +++ b/variants/thinknode_m1/variant.h @@ -40,8 +40,8 @@ //////////////////////////////////////////////////////////////////////////////// // UART pin definition -#define PIN_SERIAL1_RX (41) // GPS TX -#define PIN_SERIAL1_TX (40) // GPS RX +#define PIN_SERIAL1_RX PIN_GPS_TX +#define PIN_SERIAL1_TX PIN_GPS_RX //////////////////////////////////////////////////////////////////////////////// // I2C pin definition @@ -125,9 +125,9 @@ extern const int SCK; //////////////////////////////////////////////////////////////////////////////// // GPS -#define PIN_GPS_RX (41) -#define PIN_GPS_TX (40) -#define PIN_GPS_WAKEUP (34) +#define PIN_GPS_RX (40) +#define PIN_GPS_TX (41) +#define GPS_EN (34) #define PIN_GPS_RESET (37) #define PIN_GPS_PPS (36) #define PIN_GPS_STANDBY (34) From 1072da0eeb366a9579af3405e338bcafaa105dd9 Mon Sep 17 00:00:00 2001 From: JQ Date: Tue, 27 May 2025 23:24:08 -0700 Subject: [PATCH 2/2] handle gps switch --- variants/thinknode_m1/target.cpp | 55 +++++++++++++++++++++----------- variants/thinknode_m1/target.h | 2 +- variants/thinknode_m1/variant.h | 1 + 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/variants/thinknode_m1/target.cpp b/variants/thinknode_m1/target.cpp index c88ab848..70b5c61e 100644 --- a/variants/thinknode_m1/target.cpp +++ b/variants/thinknode_m1/target.cpp @@ -92,22 +92,16 @@ void ThinkNodeM1SensorManager::stop_gps() { bool ThinkNodeM1SensorManager::begin() { Serial1.begin(9600); - // Try to detect if GPS is physically connected to determine if we should expose the setting + // Initialize GPS switch pin + pinMode(PIN_GPS_SWITCH, INPUT); + last_gps_switch_state = digitalRead(PIN_GPS_SWITCH); + + // Initialize GPS power pin pinMode(GPS_EN, OUTPUT); - digitalWrite(GPS_EN, HIGH); // Power on GPS - // Give GPS a moment to send data if it's physically connected and powered - delay(1500); - - // We'll consider GPS detected if we see any data on Serial1 - gps_detected = (Serial1.available() > 0); - - if (gps_detected) { - MESH_DEBUG_PRINTLN("GPS detected"); - digitalWrite(GPS_EN, LOW); // Power off GPS until the setting is changed - } else { - MESH_DEBUG_PRINTLN("No GPS detected"); - digitalWrite(GPS_EN, LOW); + // Check initial switch state to determine if GPS should be active + if (last_gps_switch_state == HIGH) { // Switch is HIGH when ON + start_gps(); } return true; @@ -122,6 +116,31 @@ bool ThinkNodeM1SensorManager::querySensors(uint8_t requester_permissions, Cayen void ThinkNodeM1SensorManager::loop() { static long next_gps_update = 0; + static long last_switch_check = 0; + + // Check GPS switch state every second + if (millis() - last_switch_check > 1000) { + bool current_switch_state = digitalRead(PIN_GPS_SWITCH); + + // Detect switch state change + if (current_switch_state != last_gps_switch_state) { + last_gps_switch_state = current_switch_state; + + if (current_switch_state == HIGH) { // Switch is ON + MESH_DEBUG_PRINTLN("GPS switch ON"); + start_gps(); + } else { // Switch is OFF + MESH_DEBUG_PRINTLN("GPS switch OFF"); + stop_gps(); + } + } + + last_switch_check = millis(); + } + + if (!gps_active) { + return; // GPS is not active, skip further processing + } _location->loop(); @@ -137,22 +156,22 @@ void ThinkNodeM1SensorManager::loop() { } int ThinkNodeM1SensorManager::getNumSettings() const { - return gps_detected ? 1 : 0; // only show GPS setting if GPS is detected + return 1; // always show GPS setting } const char* ThinkNodeM1SensorManager::getSettingName(int i) const { - return (gps_detected && i == 0) ? "gps" : NULL; + return (i == 0) ? "gps" : NULL; } const char* ThinkNodeM1SensorManager::getSettingValue(int i) const { - if (gps_detected && i == 0) { + if (i == 0) { return gps_active ? "1" : "0"; } return NULL; } bool ThinkNodeM1SensorManager::setSettingValue(const char* name, const char* value) { - if (gps_detected && strcmp(name, "gps") == 0) { + if (strcmp(name, "gps") == 0) { if (strcmp(value, "0") == 0) { stop_gps(); } else { diff --git a/variants/thinknode_m1/target.h b/variants/thinknode_m1/target.h index 7f7a1055..550ee62a 100644 --- a/variants/thinknode_m1/target.h +++ b/variants/thinknode_m1/target.h @@ -14,7 +14,7 @@ class ThinkNodeM1SensorManager : public SensorManager { bool gps_active = false; - bool gps_detected = false; + bool last_gps_switch_state = false; LocationProvider* _location; void start_gps(); diff --git a/variants/thinknode_m1/variant.h b/variants/thinknode_m1/variant.h index 8e4e90bf..2b58e341 100644 --- a/variants/thinknode_m1/variant.h +++ b/variants/thinknode_m1/variant.h @@ -131,3 +131,4 @@ extern const int SCK; #define PIN_GPS_RESET (37) #define PIN_GPS_PPS (36) #define PIN_GPS_STANDBY (34) +#define PIN_GPS_SWITCH (33)