diff --git a/main/main.ino b/main/main.ino index 837640f..360c241 100644 --- a/main/main.ino +++ b/main/main.ino @@ -36,9 +36,6 @@ String baChStatus = "No charging"; bool ssd1306_found = false; bool axp192_found = false; -// Message counter, stored in RTC memory, survives deep sleep -RTC_DATA_ATTR uint32_t count = 0; - #if defined(PAYLOAD_USE_FULL) // includes number of satellites and accuracy uint8_t txBuffer[10]; @@ -70,10 +67,7 @@ void send() { bool confirmed = false; #endif - ttn_cnt(count); ttn_send(txBuffer, sizeof(txBuffer), LORAWAN_PORT, confirmed); - - count++; } void sleep() { @@ -170,9 +164,7 @@ void callback(uint8_t message) { } } -uint32_t get_count() { - return count; -} + void scanI2Cdevice(void) { @@ -281,8 +273,8 @@ void setup() { // Init GPS gps_setup(); - // Show logo on first boot - if (0 == count) { + // Show logo on first boot after removing battery + if (ttn_get_count() == 0) { screen_print(APP_NAME " " APP_VERSION, 0, 0); screen_show_logo(); screen_update(); @@ -299,11 +291,7 @@ void setup() { ttn_register(callback); ttn_join(); - ttn_sf(LORAWAN_SF); ttn_adr(LORAWAN_ADR); - if(!LORAWAN_ADR){ - LMIC_setLinkCheckMode(0); // Link check problematic if not using ADR. Must be set after join - } } void loop() { diff --git a/main/screen.ino b/main/screen.ino index 5cd6422..d7cf520 100644 --- a/main/screen.ino +++ b/main/screen.ino @@ -35,7 +35,7 @@ void _screen_header() { char buffer[20]; // Message count - snprintf(buffer, sizeof(buffer), "#%03d", get_count() % 1000); + snprintf(buffer, sizeof(buffer), "#%03d", ttn_get_count() % 1000); display->setTextAlignment(TEXT_ALIGN_LEFT); display->drawString(0, 2, buffer); diff --git a/main/ttn.ino b/main/ttn.ino index c666f33..e059d30 100644 --- a/main/ttn.ino +++ b/main/ttn.ino @@ -27,6 +27,7 @@ along with this program. If not, see . #include #include #include +#include #include "configuration.h" #include "credentials.h" @@ -42,6 +43,10 @@ const lmic_pinmap lmic_pins = { .dio = {DIO0_GPIO, DIO1_GPIO, DIO2_GPIO}, }; + +// Message counter, stored in RTC memory, survives deep sleep. +static RTC_DATA_ATTR uint32_t count = 0; + #ifdef USE_ABP // These callbacks are only used in over-the-air activation, so they are // left empty here (we cannot leave them out completely unless @@ -96,7 +101,9 @@ void onEvent(ev_t event) { // Disable link check validation (automatically enabled // during join, but because slow data rates change max TX // size, we don't use it in this example. - LMIC_setLinkCheckMode(0); + if(!LORAWAN_ADR){ + LMIC_setLinkCheckMode(0); // Link check problematic if not using ADR. Must be set after join + } break; case EV_TXCOMPLETE: Serial.println(F("EV_TXCOMPLETE (inc. RX win. wait)")); @@ -137,7 +144,20 @@ void ttn_response(uint8_t * buffer, size_t len) { } } +// If the value for LORA packet counts is unknown, restore from flash +static void initCount() { + if(count == 0) { + Preferences p; + p.begin("lora", true); + count = p.getUInt("count", 0); + p.end(); + } +} + + bool ttn_setup() { + initCount(); + // SPI interface SPI.begin(SCK_GPIO, MISO_GPIO, MOSI_GPIO, NSS_GPIO); @@ -238,11 +258,31 @@ void ttn_adr(bool enabled) { LMIC_setLinkCheckMode(!enabled); } -void ttn_cnt(uint32_t num) { - LMIC_setSeqnoUp(num); +uint32_t ttn_get_count() { + return count; +} + +static void ttn_set_cnt() { + LMIC_setSeqnoUp(count); + + // We occasionally mirror our count to flash, to ensure that if we lose power we will at least start with a count that is almost correct + // (otherwise the TNN network will discard packets until count once again reaches the value they've seen). We limit these writes to a max rate + // of one write every 5 minutes. Which should let the FLASH last for 300 years (given the ESP32 NVS algoritm) + static uint32_t lastWriteMsec = UINT32_MAX; // Ensure we write at least once + uint32_t now = millis(); + if(now < lastWriteMsec || (now - lastWriteMsec) > 5 * 60 * 1000L) { // write if we roll over (50 days) or 5 mins + lastWriteMsec = now; + + Preferences p; + p.begin("lora", false); + p.putUInt("count", count); + p.end(); + } } void ttn_send(uint8_t * data, uint8_t data_size, uint8_t port, bool confirmed){ + ttn_set_cnt(); // we are about to send using the current packet count + // Check if there is not a current TX/RX job running if (LMIC.opmode & OP_TXRXPEND) { _ttn_callback(EV_PENDING); @@ -254,6 +294,7 @@ void ttn_send(uint8_t * data, uint8_t data_size, uint8_t port, bool confirmed){ LMIC_setTxData2(port, data, data_size, confirmed ? 1 : 0); _ttn_callback(EV_QUEUED); + count++; } void ttn_loop() {