diff --git a/.gitignore b/.gitignore index 89cc49c..beaaf8a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .vscode/c_cpp_properties.json .vscode/launch.json .vscode/ipch +.vscode/extensions.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json index e80666b..080e70d 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,5 +3,8 @@ // for the documentation about the extensions.json format "recommendations": [ "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" ] } diff --git a/main/main.cpp b/main/main.cpp index 449250b..4b6fb09 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -192,6 +192,10 @@ void build_mapper_packet() { txBuffer[10] = sats & 0xFF; } +// Helium requires a FCount reset sometime before hitting 0xFFFF +// 50,000 makes it obvious it was intentional +#define MAX_FCOUNT 50000 + boolean send_uplink(uint8_t *txBuffer, uint8_t length, uint8_t fport, boolean confirmed) { if (confirmed) { Serial.println("ACK requested"); @@ -206,6 +210,21 @@ boolean send_uplink(uint8_t *txBuffer, uint8_t length, uint8_t fport, boolean co Serial.println("Surprise send failure!"); return false; } + + // Helium requires a re-join / reset of count to avoid 16bit count rollover + // Hopefully a device reboot every 50k uplinks is no problem. + if (ttn_get_count() > MAX_FCOUNT) { + Serial.println("FCount Rollover!"); + + // I don't understand why this doesn't show at all + screen_print("\n\nRollover Reset!\n"); + screen_update(); + delay(1000); // Give some time to read the screen + + ttn_erase_prefs(); + ESP.restart(); + } + return true; } @@ -639,12 +658,12 @@ void axp192Init() { // Configure REG 36H: PEK press key parameter set. Index values for // argument! - axp.setStartupTime(2); // "Power on time": 512mS - axp.setlongPressTime(2); // "Long time key press time": 2S - axp.setShutdownTime(2); // "Power off time" = 8S - axp.setTimeOutShutdown(1); // "When key press time is longer than power off time, auto power off" - axp.setVWarningLevel1(2950); // These warning IRQs do not clear until charged, and inhibit other IRQs! - axp.setVWarningLevel2(2900); // We effectively disable them by setting them lower than we'd run + axp.setStartupTime(2); // "Power on time": 512mS + axp.setlongPressTime(2); // "Long time key press time": 2S + axp.setShutdownTime(2); // "Power off time" = 8S + axp.setTimeOutShutdown(1); // "When key press time is longer than power off time, auto power off" + axp.setVWarningLevel1(2950); // These warning IRQs do not clear until charged, and inhibit other IRQs! + axp.setVWarningLevel2(2900); // We effectively disable them by setting them lower than we'd run // Serial.printf("AC IN: %fv\n", axp.getAcinVoltage()); // Serial.printf("Vbus: %fv\n", axp.getVbusVoltage()); @@ -686,7 +705,7 @@ void axp192Init() { // Low battery also seems to inhibit the USB present/lost signal we use to wake up. axp.enableIRQ(APX202_APS_LOW_VOL_LEVEL1_IRQ, 0); axp.enableIRQ(AXP202_APS_LOW_VOL_LEVEL2_IRQ, 0); - + // The Charging Current available is less than requested for battery charging. // Another Persistent IRQ. Clear it after showing it once? // TODO: Show it every X minutes? Adjust charge current request? @@ -718,7 +737,7 @@ void setup() { wakeup(); // Make sure WiFi and BT are off - //WiFi.disconnect(true); + // WiFi.disconnect(true); WiFi.mode(WIFI_MODE_NULL); btStop(); @@ -837,7 +856,7 @@ void low_power_sleep(uint32_t seconds) { // screen_setup(); } - delay(100); // GPS doesn't respond right away.. not ready for baud-rate test. + delay(100); // GPS doesn't respond right away.. not ready for baud-rate test. gps_setup(false); // Resync with GPS } @@ -1178,7 +1197,7 @@ void menu_change_sf(void) { struct menu_entry menu[] = { {"Send Now", menu_send_now}, {"Power Off", menu_power_off}, {"Distance +", menu_distance_plus}, {"Distance -", menu_distance_minus}, {"Time +", menu_time_plus}, {"Time -", menu_time_minus}, - {"Change SF", menu_change_sf}, {"Helium ReJoin", menu_flush_prefs}, {"USB GPS", menu_gps_passthrough}, + {"Change SF", menu_change_sf}, {"Full Reset", menu_flush_prefs}, {"USB GPS", menu_gps_passthrough}, {"Deadzone Here", menu_deadzone_here}, {"No Deadzone", menu_no_deadzone}, {"Stay On", menu_stay_on}, {"GPS Reset", menu_gps_reset}, {"Experiment", menu_experiment}}; #define MENU_ENTRIES (sizeof(menu) / sizeof(menu[0])) diff --git a/main/ttn.cpp b/main/ttn.cpp index c956246..fbdd122 100644 --- a/main/ttn.cpp +++ b/main/ttn.cpp @@ -105,7 +105,8 @@ void forceTxSingleChannelDr() { ttn_sf(ttn_tx_sf); } -// DevEUI generator using devices's MAC address - from https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/lorawan.cpp +// DevEUI generator using devices's MAC address - from +// https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/lorawan.cpp void gen_lora_deveui(uint8_t* pdeveui) { uint8_t *p = pdeveui, dmac[6]; int i = 0; @@ -275,7 +276,7 @@ bool ttn_setup() { return (1 == os_init_ex((const void*)&lmic_pins)); } -void ttn_join() { +void ttn_join(void) { // Reset the MAC state. Session and pending data transfers will be discarded. LMIC_reset(); @@ -382,14 +383,16 @@ void ttn_join() { uint32_t netId = p.getUInt("netId", UINT32_MAX); uint32_t devAddr = p.getUInt("devAddr", UINT32_MAX); uint8_t nwkKey[16], artKey[16]; - bool keysgood = p.getBytes("nwkKey", nwkKey, sizeof(nwkKey)) == sizeof(nwkKey) && p.getBytes("artKey", artKey, sizeof(artKey)) == sizeof(artKey); + bool keysgood = devAddr != UINT32_MAX && netId != UINT32_MAX && + p.getBytes("nwkKey", nwkKey, sizeof(nwkKey)) == sizeof(nwkKey) && + p.getBytes("artKey", artKey, sizeof(artKey)) == sizeof(artKey); p.end(); // close our prefs if (!keysgood) { // We have not yet joined a network, start a full join attempt // Make LMiC initialize the default channels, choose a channel, and // schedule the OTAA join - Serial.println("No session saved, joining from scratch"); + Serial.println("Joining from scratch"); screen_print("Joining...\n"); LMIC_startJoining(); } else { @@ -410,7 +413,7 @@ void ttn_get_sf_name(char* b, size_t len) { u1_t sf, bw; sf = getSf(txrps) + 6; // 1 == SF7 bw = getBw(txrps); - + /* snprintf(b, len, "%3d.%02d SF%d BW%d", LMIC.freq / 1000000, @@ -454,9 +457,10 @@ void ttn_write_prefs() { 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) + // 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