init

Dependencies:   aconno_I2C Lis2dh12 WatchdogTimer

Files at this revision

API Documentation at this revision

Comitter:
pathfindr
Date:
Thu May 23 11:39:28 2019 +0000
Parent:
50:a94e70c00fff
Child:
52:bd7678eade77
Commit message:
init

Changed in this revision

NRFuart.cpp Show annotated file Show diff for this revision Revisions of this file
README.md Show diff for this revision Revisions of this file
_CHANGES.md Show annotated file Show diff for this revision Revisions of this file
_PRE-DEPLOY_TESTS.md Show annotated file Show diff for this revision Revisions of this file
app_data.cpp Show annotated file Show diff for this revision Revisions of this file
board.h Show annotated file Show diff for this revision Revisions of this file
common.cpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
main.h Show annotated file Show diff for this revision Revisions of this file
modem.cpp Show annotated file Show diff for this revision Revisions of this file
modem.h Show annotated file Show diff for this revision Revisions of this file
states.h Show annotated file Show diff for this revision Revisions of this file
--- a/NRFuart.cpp	Thu May 16 12:31:44 2019 +0000
+++ b/NRFuart.cpp	Thu May 23 11:39:28 2019 +0000
@@ -17,9 +17,9 @@
         NRF_UART0->TASKS_STARTTX = 1;
         //NRF_UART0->INTENCLR = 0xffffffffUL;
         //NRF_UART0->INTENSET = UART_INTENSET_RXDRDY_Msk; //or
-        /*NRF_UART0->INTENSET = (UART_INTENSET_RXDRDY_Set << UART_INTENSET_RXDRDY_Pos) |
-                              (UART_INTENSET_TXDRDY_Set << UART_INTENSET_TXDRDY_Pos) |
-                              (UART_INTENSET_ERROR_Set << UART_INTENSET_ERROR_Pos);*/    
+        //NRF_UART0->INTENSET = (UART_INTENSET_RXDRDY_Set << UART_INTENSET_RXDRDY_Pos) |
+        //                      (UART_INTENSET_TXDRDY_Set << UART_INTENSET_TXDRDY_Pos) |
+        //                      (UART_INTENSET_ERROR_Set << UART_INTENSET_ERROR_Pos); 
         //NVIC_ClearPendingIRQ(UART0_IRQn);
         //NVIC_SetPriority(UART0_IRQn, 1); //3
         //NVIC_EnableIRQ(UART0_IRQn);
@@ -45,9 +45,9 @@
         NRF_UART0->TASKS_STARTTX = 1;
         //NRF_UART0->INTENCLR = 0xffffffffUL;
         //NRF_UART0->INTENSET = UART_INTENSET_RXDRDY_Msk; //or
-        /*NRF_UART0->INTENSET = (UART_INTENSET_RXDRDY_Set << UART_INTENSET_RXDRDY_Pos) |
-                              (UART_INTENSET_TXDRDY_Set << UART_INTENSET_TXDRDY_Pos) |
-                              (UART_INTENSET_ERROR_Set << UART_INTENSET_ERROR_Pos);*/    
+        //NRF_UART0->INTENSET = (UART_INTENSET_RXDRDY_Set << UART_INTENSET_RXDRDY_Pos) |
+        //                      (UART_INTENSET_TXDRDY_Set << UART_INTENSET_TXDRDY_Pos) |
+        //                      (UART_INTENSET_ERROR_Set << UART_INTENSET_ERROR_Pos);   
         //NVIC_ClearPendingIRQ(UART0_IRQn);
         //NVIC_SetPriority(UART0_IRQn, 1); //3
         //NVIC_EnableIRQ(UART0_IRQn);
@@ -136,12 +136,10 @@
 };
 void NRFuart_flush() {
     if (!NRF_UART0->ENABLE) NRFuart_init_nohwfc();
-    //THIS HASNT BEEN TESTED
-    char char1;
     uint32_t safetycounter = 0;
     while (NRFuart_readable() && safetycounter < 10000) {
         safetycounter ++;
-        char1 = NRFuart_getc();
+        char char1 = NRFuart_getc();
     }
 };
 bool NRFuart_readable() {
--- a/README.md	Thu May 16 12:31:44 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-TO DO!!!!!!
-
-1) Add watchdog kicks to modem functions
-2) USSDmessage index needs to work
-3) clean up timeouts, do we hard code them or send as vars particlulary connectivity ones
-4) check LNA power on GPS
-5) improve gps fix quality logic
-6) sometimes its setting back to srtate 0 and getting stuck in loop 
-7) what happens if the setup fails, it should sleep for x hrs and then try again, need to check that and make its o
-8) should we use 2g when possible - YES
-9) does 3g use less power - NO 2G uses much less power.
-10) add model version details of board to the setup tx
-11) add validation to each settings in 
-12) temp sensor not working
-13) make activity broadcast an option in normal lcoation one just total hours
-14) does enabling handshaking and auto sleep on the modem save power
-15) swap motion_g so that it is actually a mg value
-16) test motion start stop times exactly
-17) add extra 0.5cm to gsm antenna?
-18) errors while sending causes need to double send ussd command, adds on 5-10 seconds
-19) check voltage calibation
-21) when setup fails it does not go into dormant mode, could be ram retention
-22) force CL locations to 6 decimal - needs to be done on web api
-
-//BOARD NOTES
-1) increase power trace width to mcu and gps
-2) add bigger cap to mcu?
-3) uart broken out
-4) make battery backup line to modem with jumper
-5) remove flash
-5) ext timer/watchdog/eeprom?
-6) cut notch into board
-7) breakout i2c on same row
-8) make spi breakouts, through hole
-9) need to add sim card holder
-10) make serial normally connected 
-11) swap humidity sensor for bmp680??? is it factory calibrated
-
-
-RESOLVED - TO BE TESTED AGAIN...
-20) location accuracy 0 does not seem to work
-23) 3g cell tower data is not being recognised and converted to location by server (fix was to convert hex to decimal on server)
-
-TEST RESULTS:
-CE3165 - ID 109
-
-RUN 1.   GPS with 10 seconds fix hold, 2G priority, receipts everytime, 1m interval.
-Starting battery 3.19v,  End battery 2.5v
-Post time average (excluding reciept): 39 seconds
-Post count: 3569 (last record id 5540)
-
-RUN 2.   GPS with 10 second fix hold, 2g priority, receipts every 24hrs.
-Starting battery 3.19v,  End battery 2.5v
-Post cound: 4207
-
-
-DA98C4 - ID 43
-RUN 1.   GPS with 10 seconds fix hold, 3G priority, receipts everytime, 1m interval.
-Starting battery 3.22
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_CHANGES.md	Thu May 23 11:39:28 2019 +0000
@@ -0,0 +1,4 @@
+CHANGES
+
+Logging Disables after 10 mins, Press of button to re-enable for 10 mins:  pass
+Updated modem lib. removed low power timers as these were causing issues with 399ua power draw at sleep, improved ussd send logic
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_PRE-DEPLOY_TESTS.md	Thu May 23 11:39:28 2019 +0000
@@ -0,0 +1,19 @@
+TESTS
+
+NON-BOOTLOADER BUILD...
+Check Sleep Current: 17ua
+Test 1 button Press:√
+Test 3 Button Press:√
+Test 5 Button Press:√
+Test Button Off: √
+Test Button On: x
+
+BOOTLOADER BUILD...
+OTA update to this version:
+Cycle power to check FW starts again and not bootloader:
+Check Sleep Current:
+Test 1 button Press:
+Test 3 Button Press:
+Test 5 Button Press:
+Test Button Off:
+Test Button On: 
\ No newline at end of file
--- a/app_data.cpp	Thu May 16 12:31:44 2019 +0000
+++ b/app_data.cpp	Thu May 23 11:39:28 2019 +0000
@@ -75,10 +75,12 @@
 {
     bool pass = false;
     int8_t error = 0;       //used to catch errors in the flash operations
+    debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "Flash - Init 1");debug_exe();
     error = flash.init();
     if(error != 0) 
     {
         //DEBUG(DEBUG_THIS, "ERROR: flash init %d \r\n", error);
+        debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "ERROR: flash init %d",error);debug_exe();
         return false;
     }
     const uint32_t page_size = flash.get_page_size();
@@ -86,17 +88,21 @@
     uint32_t addr = APPDATA_START;
     uint32_t value[1] = {0};
     uint32_t val = 0;
-    uint8_t setting = 1;  
+    uint8_t setting = 1;
+    debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "Flash - Init 2");debug_exe();
     flash.init();  
     // DEBUGGING APP DATA MEMORY CRASH
-    error = flash.erase(addr, flash.get_sector_size(addr)); 
+    debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "Flash - Erase");debug_exe();
+    error = flash.erase(addr, flash.get_sector_size(addr));
     if(error != 0) 
     {
         //DEBUG(DEBUG_THIS, "ERROR: flash erase %d \r\n", error);
+        debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "ERROR: flash erase %d",error);debug_exe();
         return false;
     }  
     
     //DEBUG(DEBUG_THIS, "WRITE VALUES FROM RAM TO FLASH... \r\n\n"); 
+    debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "Flash - Write 1");debug_exe();
     for(setting=1; setting<=N_SETTINGS; setting++)
     {
         switch(setting)
@@ -124,10 +130,12 @@
         page_buffer[3] = (char)((val & 0xFF000000) >> 24);            
                 
         //transfer the page buffer to the flash memory
+        debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "Flash - Write 2");debug_exe();
         error = flash.program(page_buffer, addr, page_size); 
         if(error != 0) 
         {
             //DEBUG(DEBUG_THIS, "ERROR: flash program %d \r\n", error);
+            debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "ERROR: flash program %d",error);debug_exe();
             return false;
         }    
         //for debug check read back the value...
@@ -138,13 +146,16 @@
         addr += page_size;
     }
 
+    debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "Flash - Deinit");debug_exe();
     error = flash.deinit();  
     if(error != 0) 
     {
         //DEBUG(DEBUG_THIS, "ERROR: flash deinit %d \r\n", error);
+        debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "ERROR: flash deinit %d",error);debug_exe();
         return false;
     }  
     //DEBUG(DEBUG_THIS, "DONE \r\n");      
+    debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "Flash - Done");debug_exe();
     return pass; 
 }
 //------------------------------------------------------------------------------
--- a/board.h	Thu May 16 12:31:44 2019 +0000
+++ b/board.h	Thu May 23 11:39:28 2019 +0000
@@ -37,4 +37,5 @@
 //#define BD_PAGE_ADDRESS 0x5d000 //380928
 
 #define USERDATA_START          0x7E000 // - 8k for user data
-#define APPDATA_START           0x3D000 // - 4k for app data
\ No newline at end of file
+//#define APPDATA_START           0x40000 // - 4k for app data - DEVELOPMENT
+#define APPDATA_START           0x3D000 // - 4k for app data - PRODUCTION
\ No newline at end of file
--- a/common.cpp	Thu May 16 12:31:44 2019 +0000
+++ b/common.cpp	Thu May 23 11:39:28 2019 +0000
@@ -30,9 +30,6 @@
     led1 = 1;
     GLOBAL_LEDSequenceinProgress = false;
 }
-void LED1blinkRTC(int count) {
-    RTCtick_ledflash_count = count;
-}
 void LED1errorCode(int pattern, int count) {
     GLOBAL_LEDSequenceinProgress = true;
     for (int i = 0; i < count; i++) {
@@ -49,6 +46,5 @@
 }
 void LED1off() {
     led1 = 1;
-    RTCtick_ledflash_count = 0;
     GLOBAL_LEDSequenceinProgress = false;
 }
\ No newline at end of file
--- a/main.cpp	Thu May 16 12:31:44 2019 +0000
+++ b/main.cpp	Thu May 23 11:39:28 2019 +0000
@@ -1,15 +1,29 @@
 #include "main.h"
+// MUST USE MBED 5.10.4   2fd0c5cfbd
+
+/*
+PRE DEPLOYMENT CHECKS!!
+• Ensure APP DATA address is correct
+*/
+
+
+/*
+TO DO
+STOP FRASH WRITE FROM CRASHING IF THERE IS A PROBLEM
+
+*/
+
 
 //------------------------------------------------------------------------------
 //FUNCTION PROTOTYPES - NEED TO ADD ALL OF THE MISSING ONES
 //------------------------------------------------------------------------------ 
 //should really add these - will just add as and when needed for now
 void event_activity_tx();
-void event_location_tx();
+void event_location_tx(bool failsafe);
 
 //------------------------------------------------------------------------------
 // GLOBALS
-//------------------------------------------------------------------------------ 
+//------------------------------------------------------------------------------
 bool             GLOBAL_debugLED                     = false;
 char*            GLOBAL_defaultApi                   = "b:gps2";
 bool             GLOBAL_accel_healthy                = false;
@@ -21,6 +35,8 @@
 time_t           GLOBAL_wakeTime                     = 0;
 char             GLOBAL_exceptionString[30];
 char             GLOBAL_debug_buffer[200];
+char             GLOBAL_failed_broadcasts[10][160];
+bool             GLOBAL_failed_broadcast_slots[10];
 
 //SETTINGS
 int              RET_setting_firmware;
@@ -42,6 +58,7 @@
 uint16_t         RET_setting_beacon_interval_seconds;
 uint16_t         RET_setting_beacon_scan;
 //STATE
+char             RET_pf_identifier[7];
 uint8_t          RET_coldBoot = 1;
 bool             RET_asleep = false;
 bool             RET_busy = false;
@@ -52,6 +69,7 @@
 uint8_t          RET_buttonPressCount;
 time_t           RET_buttonPressTime;
 time_t           RET_buttonReleaseTime;
+time_t           RET_buttonReleaseTime_prev;
 time_t           RET_buttonHoldTime;
 time_t           RET_SetupRunAt;
 time_t           RET_SettingsGotAt;
@@ -61,6 +79,12 @@
 bool             RET_receivedNewSettings;
 uint32_t         RET_GPSFailCount;
 uint32_t         RET_NetworkFailCount;
+bool             RET_debug = true;
+time_t           RET_debug_offat;
+float            RET_voltage;
+float            RET_temperature;
+float            RET_temperature_max = -999.0; //Within broadcast frame. Set inital value to low
+float            RET_temperature_min = 999.0; //Within broadcase frame. Set inital value to high
 //MOTION STATE
 bool             RET_motionTriggeredinFrame;
 bool             RET_motionTriggeredInLocTXInterval;
@@ -93,13 +117,13 @@
 //------------------------------------------------------------------------------
 //PERIPHERALS
 //------------------------------------------------------------------------------ 
-//BLE myble;
 WatchdogTimer watchdog; //Do not set to less than 4500ms or can cause issues with softdevice
-void watchdogKick() {watchdog.kick();}
-SI7060 si7060(PN_I2C_SDA, PN_I2C_SCL);
+void watchdogKick() { watchdog.kick();}
+//SI7060 si7060(PN_I2C_SDA, PN_I2C_SCL);
 LIS3DH lis3dh(PN_SPI_MOSI, PN_SPI_MISO, PN_SPI_CS0, PN_SPI_CLK);
 Modem modem(PN_GSM_PWR_KEY, PN_VREG_EN, PN_GSM_WAKE_DISABLE);
 LowPowerTicker RTCticker;
+LowPowerTimer LPtimer;
 
 //------------------------------------------------------------------------------
 //THREAD SEMAPHORES
@@ -109,6 +133,16 @@
 //------------------------------------------------------------------------------
 // LOW LEVEL FUNCS
 //------------------------------------------------------------------------------
+void set_8bit_flag(uint8_t& flags, uint8_t flag) {
+    flags |= flag;
+}
+bool get_8bit_flag(uint8_t& flags, uint8_t flag) {
+    bool result = (flags & flag);
+    return result;
+}
+void clr_8bit_flag(uint8_t& flags, uint8_t flag) {
+    flags &= ~flag;
+}
 void nrf_configureForSleep(){
     //Disable SPI pins to reduce power
     //nrf_gpio_cfg_input(PN_SPI_MOSI, NRF_GPIO_PIN_NOPULL);  //Don't need this one
@@ -118,6 +152,7 @@
     nrf_gpio_cfg_input(PN_GSM_PWR_KEY, NRF_GPIO_PIN_NOPULL);
     nrf_gpio_cfg_input(PN_GSM_WAKE_DISABLE, NRF_GPIO_PIN_NOPULL);
     
+    /*
     //ERRATA 89, shut down i2c channels properly
     //TWI0
     //NRF_TWI0->ENABLE=0;//TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
@@ -130,13 +165,14 @@
     *(volatile uint32_t *)0x40004FFC = 0;
     *(volatile uint32_t *)0x40004FFC;
     *(volatile uint32_t *)0x40004FFC = 1;
+    */
 }
 void setState(uint8_t state) {
     RET_state_prev = RET_state;
     RET_state = state;
 }
-void dumpSettings() {    
-    if(DEBUG_ON){
+void dumpSettings() {  
+    if(RET_debug){
         debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_RTCunixtime:%u", RET_RTCunixtime);debug_exe();
         debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_firmware:%d", RET_setting_firmware);debug_exe();
         debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_minimumupdate_hrs:%d", RET_setting_minimumupdate_hrs);debug_exe();
@@ -157,9 +193,11 @@
         debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_connection_timeout:%d", RET_setting_connection_timeout);debug_exe();
         debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_beacon_interval_seconds:%d", RET_setting_beacon_interval_seconds);debug_exe();
         debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_beacon_scan:%d", RET_setting_beacon_scan);debug_exe();
+        debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_pf_identifier:%s", RET_pf_identifier);debug_exe();
     }
 }
 void recordFirmwareAsValid() {
+    debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RECORD FW %d AS VALID...", FW_VERSION);debug_exe();
     read_app_data_from_flash(&app_data);
     bool write_app_data_to_flash_execute = false;
     if(get_flag(&app_data, app_execution_flag) == true) {
@@ -174,9 +212,17 @@
     }
     if (write_app_data_to_flash_execute) {
         write_app_data_to_flash(&app_data);
-    }   
+        //read back to check
+        ThisThread::sleep_for(200); //need this delay
+        read_app_data_from_flash(&app_data);
+        if (app_data.current_firmware_version == FW_VERSION) {
+            debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "OK");debug_exe();
+        } else {
+            debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "FAIL - IS BLE SHUTDOWN?");debug_exe();
+        }
+    }
 }
-float getBatteryV() {
+void updateBatteryV() {
     NRF52_SAADC batteryIn;
     batteryIn.addChannel(9); // vdd for battery
     batteryIn.calibrate();
@@ -189,13 +235,13 @@
         voltage_accumulator += (batteryIn.getData()[0])*(1.0/1024.0)*3.60;
         readings ++;
     }
-    float voltage = (voltage_accumulator / (float)readings);
-    return voltage;
+    RET_voltage = (voltage_accumulator / (float)readings);
 }
 float nrfTemperature() {
+    float temperature = 0.0;
+    
     //INTERNAL NRF52 TEMP SENSOR
     uint32_t safetycounter = 0;
-    float temperature = 0.0;
     NRF_TEMP->TASKS_START=1;
     while (NRF_TEMP->EVENTS_DATARDY==0 && safetycounter < 10000) {
         safetycounter ++;
@@ -203,79 +249,109 @@
     NRF_TEMP->EVENTS_DATARDY=0;
     temperature = nrf_temp_read()/4.0;
     NRF_TEMP->TASKS_STOP=1;
+    
+    //SOFTDEVICE METHOD - To use this method you need to include #include "nrf_soc.h"
+    //THIS GAVE SOME INTERMITENT ODD RESULTS AND DOESNT SEEM AS RELIABLE
+    /*
+    int32_t t;
+    sd_temp_get(&t);
+    temperature = t/4.0;
+    */
+    
     return temperature;
 }
 float getTemperature() {
     float temperature;
     if (USE_NRF_TEMP_SENSOR) {
-        //INTERNAL NRF52 TEMP SENSOR
         temperature = nrfTemperature();
     } else {
-        temperature = si7060.getTemperature(); //currently disabled because its causing a high current 450ua sleep, most likely due to sensor not sleeping correctly, or i2c sleep issue
+        //temperature = si7060.getTemperature(); //currently disabled because its causing a high current 450ua sleep, most likely due to sensor not sleeping correctly, or i2c sleep issue
     }
     return temperature;  
 }
+void updateTemperatures() {
+    //RET_temperature = getTemperature(); //not smoothed
+    if (RET_temperature == 0.0f) {RET_temperature = getTemperature();}
+    RET_temperature = (RET_temperature + (getTemperature() - RET_temperature) * 0.25f); //smoothed
+    
+    if (RET_temperature < RET_temperature_min) {
+        RET_temperature_min = RET_temperature;
+    }
+    if (RET_temperature > RET_temperature_max) {
+        RET_temperature_max = RET_temperature;
+    }
+    if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "Temp:%.1f  Min:%.1f  Max:%.1f",RET_temperature,RET_temperature_min,RET_temperature_max);debug_exe();}
+}
 void addToExceptionString(char* value) {
     if(strstr(GLOBAL_exceptionString, value) == false){
         snprintf(GLOBAL_exceptionString+strlen(GLOBAL_exceptionString),sizeof(GLOBAL_exceptionString),"%s.",value);
     }
 }
+void resetTemperatures() {
+    RET_temperature_max = -999.0; //Within broadcast frame. Set inital value to low
+    RET_temperature_min = 999.0; //Within broadcase frame. Set inital value to high   
+}
 //------------------------------------------------------------------------------
 // USER BUTTON HANDLING
 //------------------------------------------------------------------------------ 
 void buttonPress() {
-    RET_buttonPressTime = RET_RTCunixtime;
+    RET_buttonPressTime = LPtimer.read_ms();
 }
 void buttonRelease() {
-    RET_buttonReleaseTime = RET_RTCunixtime;
-    RET_buttonHoldTime = (RET_buttonReleaseTime - RET_buttonPressTime);
-    RET_buttonPressCount ++;
+    //debounce catch
+    RET_buttonReleaseTime = LPtimer.read_ms();
+    if ((RET_buttonReleaseTime - RET_buttonReleaseTime_prev) > 75) { 
+        RET_buttonPressCount ++;
+        RET_buttonHoldTime = (RET_buttonReleaseTime - RET_buttonPressTime);
+        //temporarily enable debugging and dump settings
+        RET_debug = true;
+        RET_debug_offat = (RET_RTCunixtime + 600); //debug on for 10 mins
+    }
+    RET_buttonReleaseTime_prev = RET_buttonReleaseTime;
 }
 //------------------------------------------------------------------------------
 // RTC TICKER
-//------------------------------------------------------------------------------ 
-uint8_t RTCtick_ledflash_count = 0;
+//------------------------------------------------------------------------------
 void RTCtick() {
-    //YOU MUST NOT CALL ANY OTHER FUNCTIONS OR DEBUG FROM INSIDE HERE!!! OR IT LOCKS UP THE DEVICE, just change vars
+    //YOU MUST NOT CALL ANY OTHER FUNCTIONS OR DEBUG FROM INSIDE HERE!!! OR IT LOCKS UP THE DEVICE, just change vars & comparisons etc
     RET_RTCunixtime += 1;
-
-    //button logic, only when device asleep
-    //hold check
-    if (RET_buttonHoldTime >= 4 && RET_buttonHoldTime <= 10) {
+    
+    //button logic
+    if (RET_buttonHoldTime >= 4000 && RET_buttonHoldTime <= 10000) {
         RET_buttonHoldTime = 0;
         RET_buttonPressCount = 0;
-        RET_state_prev = RET_state;
-        RET_state = STATE_BUTTONHOLD;
+        if (RET_state != STATE_DORMANT) {
+            RET_state_prev = RET_state;
+            RET_state = STATE_TURNOFF;
+        } else {
+            RET_state = STATE_TURNON;
+        }
         mainthread.release();
-    } else if (RET_buttonHoldTime >= 14 && RET_buttonHoldTime <= 30) {
+    } else if (RET_buttonHoldTime >= 14000 && RET_buttonHoldTime <= 30000) {
         RET_buttonHoldTime = 0;
         RET_buttonPressCount = 0;
-        RET_state_prev = RET_state;
         RET_state = STATE_SCORCHEDEARTH;
         mainthread.release();
     } else {
-        if((RET_RTCunixtime - RET_buttonReleaseTime) > 1 && RET_buttonPressCount > 0) {
+        if((LPtimer.read_ms() - RET_buttonReleaseTime) > 1500 && RET_buttonPressCount > 0) {
             if(RET_busy == true) { 
                 //RTCtick_ledflash_count = 4;// 2 flashes
             } else {
                 RET_SetupRunAt = 0; //allow setup to run again
                 switch (RET_buttonPressCount) {   //double catches to help with debounce
                     case 1 :
-                    case 2 :
                         if(RET_state_prev != RET_state) {RET_state_prev = RET_state;}
                         RET_state = STATE_BUTTONPRESS1;
                         RET_buttonPressCount = 0;
                         mainthread.release();
                         break;
                     case 3 :
-                    case 4 :
                         if(RET_state_prev != RET_state) {RET_state_prev = RET_state;}
                         RET_state = STATE_BUTTONPRESS3;
                         RET_buttonPressCount = 0;
                         mainthread.release();
                         break;
                     case 5 :
-                    case 6 :
                         if(RET_state_prev != RET_state) {RET_state_prev = RET_state;}
                         RET_state = STATE_BUTTONPRESS5;
                         RET_buttonPressCount = 0;
@@ -286,9 +362,11 @@
                         break;
                 }
             }
+            RET_buttonPressCount = 0;
         }
     }
 }
+
 void resetGlobals() {
     GLOBAL_accel_healthy = false;
     GLOBAL_motionStopFlagTriggered = false;
@@ -312,13 +390,13 @@
     if(RET_haveSettings == true) {
         //check location tx delta is set
         if (RET_eventTime_location_tx == 0) {
-            if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "ERR:eventTime_location_tx is 0");debug_exe();}
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "ERR:eventTime_location_tx is 0");debug_exe();}
             RET_haveSettings = false;
         }
         //check location failsafe tx delta is less that 2 weeks
         long location_failsafe_tx_delta = (RET_eventTime_location_failsafe_tx - RET_RTCunixtime);
         if (location_failsafe_tx_delta > TENDAYSINSECONDS) {
-            if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "ERR:location_failsafe_tx_delta too small");debug_exe();}
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "ERR:location_failsafe_tx_delta too small");debug_exe();}
             RET_haveSettings = false;
         }
     }
@@ -359,7 +437,6 @@
     RET_setting_impact_g = 0;
     RET_setting_impact_alert = 0;
     RET_setting_connection_timeout = DEFAULT_CONNECTION_TIMEOUT;
-    RET_setting_beacon_interval_seconds = DEFAULT_BEACON_INTERVAL_SECONDS;
     RET_setting_beacon_scan = 0;
     RET_buttonPressCount = 0;
     RET_buttonPressTime = 0;
@@ -407,24 +484,8 @@
         addToExceptionString("A");   
     }
     
-    //Temperature
-    test_count ++;
-    float temperature;
-    if (USE_NRF_TEMP_SENSOR) {
-        //INTERNAL NRF52 TEMP SENSOR
-        temperature = nrfTemperature();
-    } else {
-        //temperature = si7060.getTemperature();
-    }
-    if (temperature > -40 && temperature < 60) {
-        test_pass ++;
-    } else {
-        addToExceptionString("T");
-    }
-    
     //Result
     if (test_count == test_pass) {
-        //addToExceptionString("HOK");  //dont need this, only add fails
         return true;
     } else {
         addToExceptionString("HF"); 
@@ -436,64 +497,58 @@
 // MOTION FUNCS
 //------------------------------------------------------------------------------ 
 bool checkMotion() {
-    if (lis3dh_int2) {
-        if (GLOBAL_debugLED) LED1blink(2,50);
-        RET_motionTriggeredinFrame = true;
-        GLOBAL_needToConfigureLis3dh = true; //interrupt has fire so need to clear it
-        if (!RET_motionPendingOnState) {
-            RET_motionPendingOnState = true;
-            RET_motionPendingOffState = false;
-            // Log start motion time
-            RET_motionStartTime = RET_RTCunixtime;
+    if (RET_haveSettings) { //NEED THIS AS THINGS GO FUNKY WITHOUT RTC TIME SET CORRECTLY
+        if (lis3dh_int2) {
+            RET_motionTriggeredinFrame = true;
+            GLOBAL_needToConfigureLis3dh = true; //interrupt has fire so need to clear it
+            if (!RET_motionPendingOnState) {
+                RET_motionPendingOnState = true;
+                RET_motionPendingOffState = false;
+                // Log start motion time
+                RET_motionStartTime = RET_RTCunixtime;
+            }
+        } else {
+            RET_motionTriggeredinFrame = false;
+            RET_motionPendingOnState = false;
+            if (!RET_motionPendingOffState) {
+                RET_motionPendingOffState = true;
+                //log stop motion time
+                RET_motionStopTime = RET_RTCunixtime;
+            }
         }
-    } else {
-        if (GLOBAL_debugLED) LED1blink(1,50);
-        RET_motionTriggeredinFrame = false;
-        RET_motionPendingOnState = false;
-        if (!RET_motionPendingOffState) {
-            RET_motionPendingOffState = true;
-            //log stop motion time
-            RET_motionStopTime = RET_RTCunixtime;
-        }
-    }
-    //calculate motion state
-    if (RET_motionPendingOnState) {
-        //check if above threshold
-        time_t inMotionForSeconds = ((RET_RTCunixtime - RET_motionStartTime) + (DEFAULT_SLEEP_FRAME / 1000)); //Plus DEFAULT_SLEEP_FRAME as it should include frame time
-        if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "MOT:%u s",inMotionForSeconds);debug_exe();}
-        if (inMotionForSeconds >= (RET_setting_motion_start_seconds + 15) && RET_motionState == false) {
-            RET_motionState = true;
-            RET_motionTriggeredInLocTXInterval = true;
-            //if (GLOBAL_debugLED) LED1blink(1,50);
-            if (RET_setting_activity_mode == 2) {
-                if (RET_setting_location_tx_failsafe_hrs > 0) {
+        //calculate motion state
+        if (RET_motionFrameStart == 0) {RET_motionFrameStart = RET_RTCunixtime;}
+        if (RET_motionPendingOnState) {
+            //check if above threshold
+            time_t inMotionForSeconds = ((RET_RTCunixtime - RET_motionStartTime) + (DEFAULT_SLEEP_FRAME / 1000)); //Plus DEFAULT_SLEEP_FRAME as it should include frame time
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "MOT:%u s",inMotionForSeconds);debug_exe();}
+            if (inMotionForSeconds >= (RET_setting_motion_start_seconds + 15) && RET_motionState == false) {
+                RET_motionState = true;
+                RET_motionTriggeredInLocTXInterval = true;
+                if (RET_setting_activity_mode == 2 && RET_setting_activity_tx_interval_hrs > 0) {
                     time_t epochOffsetMins = ((RET_RTCunixtime - RET_motionFrameStart) / 60);
                     sprintf(RET_activityData+strlen(RET_activityData),"1.%u!",epochOffsetMins);
                 }
             }
         }
-    }
-    if (RET_motionPendingOffState) {
-        time_t noMotionForSeconds = ((RET_RTCunixtime - RET_motionStopTime) + (DEFAULT_SLEEP_FRAME / 1000)); //Plus DEFAULT_SLEEP_FRAME as it should include frame time
-        if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "MOTLESS:%u s",noMotionForSeconds);debug_exe();}
-        if (noMotionForSeconds >= (RET_setting_motion_stop_seconds + 15) && RET_motionState == true) {
-            //if (GLOBAL_debugLED) LED1blink(2,50);
-            RET_motionPendingOffState = false;
-            RET_motionState = false;
-            GLOBAL_motionStopFlagTriggered = true;
-            if (RET_setting_activity_mode > 0 && RET_setting_location_tx_failsafe_hrs > 0) {
-                RET_motionTotalActivityHoursSincePost += ((float(RET_motionStopTime)-float(RET_motionStartTime)) / 3600.0f);
-                RET_motionTotalActivityHours += RET_motionTotalActivityHoursSincePost;
-                if (RET_setting_activity_mode == 2) {
-                    time_t epochOffsetMins = ((RET_RTCunixtime - RET_motionFrameStart) / 60);
-                    sprintf(RET_activityData+strlen(RET_activityData),"0.%u!",epochOffsetMins);
+        if (RET_motionPendingOffState) {
+            time_t noMotionForSeconds = ((RET_RTCunixtime - RET_motionStopTime) + (DEFAULT_SLEEP_FRAME / 1000)); //Plus DEFAULT_SLEEP_FRAME as it should include frame time
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "MOTLESS:%u s",noMotionForSeconds);debug_exe();}
+            if (noMotionForSeconds >= (RET_setting_motion_stop_seconds + 15) && RET_motionState == true) {
+                RET_motionPendingOffState = false;
+                RET_motionState = false;
+                GLOBAL_motionStopFlagTriggered = true;
+                if (RET_setting_activity_mode > 0 && RET_setting_activity_tx_interval_hrs > 0) {
+                    RET_motionTotalActivityHoursSincePost += ((float(RET_motionStopTime)-float(RET_motionStartTime)) / 3600.0f);
+                    RET_motionTotalActivityHours += RET_motionTotalActivityHoursSincePost;
+                    if (RET_setting_activity_mode == 2) {
+                        time_t epochOffsetMins = ((RET_RTCunixtime - RET_motionFrameStart) / 60);
+                        sprintf(RET_activityData+strlen(RET_activityData),"0.%u!",epochOffsetMins);
+                    }
                 }
             }
         }
     }
-    
-    if (GLOBAL_debugLED && RET_motionState == true) LED1on(1000);
-    
     return RET_motionState;
 }
 
@@ -504,15 +559,18 @@
     int matchCount = 0;
     int critical_fail_count = 0;
     int TEMP_a = -1; time_t TEMP_b = 0; int TEMP_c = -1; int TEMP_d = -1; int TEMP_e = -1; int TEMP_f = -1; int TEMP_g = -1; int TEMP_h = -1; int TEMP_i = -1; int TEMP_j = -1; 
-    int TEMP_k = -1; int TEMP_l = -1; int TEMP_m = -1; int TEMP_n = -1; int TEMP_o = -1; int TEMP_p = -1; int TEMP_q = -1; int TEMP_r = -1; int TEMP_s = -1; int TEMP_t = -1;
+    int TEMP_k = -1; int TEMP_l = -1; int TEMP_m = -1; int TEMP_n = -1; int TEMP_o = -1; int TEMP_p = -1; int TEMP_q = -1; int TEMP_r = -1; int TEMP_s = -1; int TEMP_t = -1; char TEMP_u[7];
     
-    //if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RESP: %s",settingsBuffer);debug_exe();}
+    if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RESP: %s",settingsBuffer);debug_exe();}
     
-    if ( (matchCount = sscanf(settingsBuffer,"a:%d,b:%u,c:%d,d:%d,e:%d,f:%d,g:%d,h:%d,i:%d,j:%d,k:%d,l:%d,m:%d,n:%d,o:%d,p:%d,q:%d,r:%d,s:%d,t:%d",
-    &TEMP_a,&TEMP_b,&TEMP_c,&TEMP_d,&TEMP_e,&TEMP_f,&TEMP_g,&TEMP_h,&TEMP_i,&TEMP_j,&TEMP_k,&TEMP_l,&TEMP_m,&TEMP_n,&TEMP_o,&TEMP_p,&TEMP_q,&TEMP_r,&TEMP_s,&TEMP_t) ) > 0 ) {
+    //exampple
+    //+CUSD: 0,”1#a:12,b:1558020598,c:-1,d:-1,e:1,f:2,g:5,h:168,i:90,j:168,k:0,l:8,m:60,n:60,o:0,p:0,q:120,r:0,s:0,t:1,u:F859C1#”,15    
+    
+    if ( (matchCount = sscanf(settingsBuffer,"a:%d,b:%u,c:%d,d:%d,e:%d,f:%d,g:%d,h:%d,i:%d,j:%d,k:%d,l:%d,m:%d,n:%d,o:%d,p:%d,q:%d,r:%d,s:%d,t:%d,u:%s",
+    &TEMP_a,&TEMP_b,&TEMP_c,&TEMP_d,&TEMP_e,&TEMP_f,&TEMP_g,&TEMP_h,&TEMP_i,&TEMP_j,&TEMP_k,&TEMP_l,&TEMP_m,&TEMP_n,&TEMP_o,&TEMP_p,&TEMP_q,&TEMP_r,&TEMP_s,&TEMP_t,&TEMP_u) ) > 0 ) {
         
-        //if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "SERVERPARAMS: a:%d,b:%u,c:%d,d:%d,e:%d,f:%d,g:%d,h:%d,i:%d,j:%d,k:%d,l:%d,m:%d,n:%d,o:%d,p:%d,q:%d,r:%d,s:%d,t:%d\n",
-        //TEMP_a,TEMP_b,TEMP_c,TEMP_d,TEMP_e,TEMP_f,TEMP_g,TEMP_h,TEMP_i,TEMP_j,TEMP_k,TEMP_l,TEMP_m,TEMP_n,TEMP_o,TEMP_p,TEMP_q,TEMP_r,TEMP_s,TEMP_t);debug_exe();}
+        if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "PARAMS: a:%d,b:%u,c:%d,d:%d,e:%d,f:%d,g:%d,h:%d,i:%d,j:%d,k:%d,l:%d,m:%d,n:%d,o:%d,p:%d,q:%d,r:%d,s:%d,t:%d,u:%s\n",
+        TEMP_a,TEMP_b,TEMP_c,TEMP_d,TEMP_e,TEMP_f,TEMP_g,TEMP_h,TEMP_i,TEMP_j,TEMP_k,TEMP_l,TEMP_m,TEMP_n,TEMP_o,TEMP_p,TEMP_q,TEMP_r,TEMP_s,TEMP_t,TEMP_u);debug_exe();}
         
         if(TEMP_a != -1) { RET_setting_minimumupdate_hrs = TEMP_a;                      }
         if(TEMP_b > 1552915630) {
@@ -520,15 +578,19 @@
                 //assume this is first proper unixtime and set
                 RET_RTCunixtime = TEMP_b;
             } else {
-                //this is not a first unixtime, so check within safe range
-                if ((TEMP_b - RET_RTCunixtime) < 604800) { //allow 1 week difference
+                //this is not a first unixtime, so check within safe range, convert to long long first to avoid -1 rollover issue
+                long long unixtime_in = TEMP_b;
+                long long unixtime_current = RET_RTCunixtime;
+                if ((unixtime_in - unixtime_current) < 604800) { //allow 1 week difference
                     RET_RTCunixtime = TEMP_b;
                 } else {
                     critical_fail_count++;
+                    if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "unixtime too far ahead. C:%u  N:%u",RET_RTCunixtime,TEMP_b);debug_exe();}
                 }
             }
         } else { 
             critical_fail_count++;
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "unixtime too low");debug_exe();}
         }
         if(TEMP_c != -1) { RET_setting_firmware = TEMP_c;                               } else { RET_setting_firmware = -1;}
         if(TEMP_d != -1) { setState(TEMP_d);                                            } else { setState(STATE_NORMAL);}
@@ -554,10 +616,11 @@
         if(TEMP_r != -1) { RET_setting_beacon_interval_seconds = TEMP_r;                }
         if(TEMP_s != -1) { RET_setting_beacon_scan = TEMP_s;                            }
         if(TEMP_t != -1) { RET_setting_activity_mode = TEMP_t;                          }
+        if(TEMP_u[0] != 0x00 && TEMP_u[1] != 0x00 && TEMP_u[2] != 0x00) { strcpy(RET_pf_identifier,TEMP_u);                      }
 
         if (critical_fail_count == 0) { 
             RET_receivedNewSettings = true;
-            //if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "SETTINGS OK");debug_exe();}
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "NEW SETTINGS");debug_exe();}
             dumpSettings();
             RET_haveSettings = true;
             GLOBAL_needToConfigureLis3dh = true;
@@ -573,19 +636,16 @@
                 app_data.current_firmware_version = FW_VERSION;
                 app_data.target_firmware_version = RET_setting_firmware;
                 write_app_data_to_flash(&app_data);
-                if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "OTA\n");debug_exe();}
+                if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "OTA\n");debug_exe();}
                 ThisThread::sleep_for(200);
                 system_reset();
             }
             return true;
         } else {
-            //if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "CRITICAL FAILS:%d",critical_fail_count);debug_exe();}
             addToExceptionString("SCF");
-            //dont set RET_haveSettings = false; here, if we already have settings continue to use them
             return false;
         }
     } else {
-        //dont set RET_haveSettings = false; here, if we already have settings continue to use them
         addToExceptionString("SPE");
         return false;
     }
@@ -597,24 +657,23 @@
 void setEventTime_Location() {
     if(RET_setting_location_tx_interval_mins > 0) { 
         RET_eventTime_location_tx = (RET_RTCunixtime + (RET_setting_location_tx_interval_mins * 60));
-        if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "EVTSET - LOC TX @ %u, MODE %d",RET_eventTime_location_tx, RET_setting_location_mode);debug_exe();}
+        if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "EVTSET - LOC TX @ %u, MODE %d",RET_eventTime_location_tx, RET_setting_location_mode);debug_exe();}
     }
     if(RET_setting_location_tx_failsafe_hrs > 0) { 
         RET_eventTime_location_failsafe_tx = (RET_RTCunixtime + (RET_setting_location_tx_failsafe_hrs * 3600));
-        if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "EVTSET - LOC FS TX @ %u",RET_eventTime_location_failsafe_tx);debug_exe();}
+        if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "EVTSET - LOC FS TX @ %u",RET_eventTime_location_failsafe_tx);debug_exe();}
     }
 }
 void setEventTime_Activity() {
     if(RET_setting_activity_tx_interval_hrs > 0) { 
-        RET_motionFrameStart = RET_RTCunixtime; //SET START FRAME INITAL
         RET_eventTime_activity_tx = (RET_RTCunixtime + (RET_setting_activity_tx_interval_hrs * 3600));
-        if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "EVTSET - ACT TX @ %u",RET_eventTime_activity_tx);debug_exe();}
+        if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "EVTSET - ACT TX @ %u",RET_eventTime_activity_tx);debug_exe();}
     }
 }
 void setEventTime_Environmental() {
     if(RET_eventTime_environmental_tx > 0) { 
         RET_eventTime_environmental_tx = (RET_RTCunixtime + (RET_setting_environmental_tx_interval_mins * 60));
-        if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "EVTSET - ENV TX @ %u",RET_eventTime_environmental_tx);debug_exe();}
+        if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "EVTSET - ENV TX @ %u",RET_eventTime_environmental_tx);debug_exe();}
     }
 }
 void setEventTimes() {
@@ -628,14 +687,14 @@
 // ERROR LOG
 //------------------------------------------------------------------------------ 
 void sendErrorLog(char* error) {
-    float voltage = getBatteryV();
+    updateBatteryV();
     int timetaken = (RET_RTCunixtime - GLOBAL_wakeTime);
     char bytestosend[100];
     memset(bytestosend,0x00,sizeof(bytestosend));
-    snprintf(bytestosend,sizeof(bytestosend),"(%s,a:log,f:%d,v:%.2f,e:%d,z:%s.%s,c:1,s:0)\0",GLOBAL_defaultApi,FW_VERSION,voltage,timetaken,error,GLOBAL_exceptionString);
+    snprintf(bytestosend,sizeof(bytestosend),"(%s,a:log,f:%d,v:%.2f,e:%d,z:%s.%s,c:1,s:0)\0",GLOBAL_defaultApi,FW_VERSION,RET_voltage,timetaken,error,GLOBAL_exceptionString);
     if (modem.on(RET_force2G)) {
         if (modem.registerOnNetwork(DEFAULT_CONNECTION_ATTEMPTS,RET_setting_connection_timeout,RET_NetworkFailCount)) {
-            modem.USSDmessage(bytestosend, false, 2, GLOBAL_defaultApi);
+            modem.USSDmessage(bytestosend, false, GLOBAL_defaultApi);
         }
     }
     ThisThread::sleep_for(250);
@@ -644,9 +703,55 @@
 //------------------------------------------------------------------------------
 // EVENTS
 //------------------------------------------------------------------------------ 
+void failed_broadcast_log(char* eventstring) {
+    //First available free slot
+    bool saved = false;
+    for(int i = 0; i < sizeof(GLOBAL_failed_broadcast_slots); i++) {
+        if (GLOBAL_failed_broadcast_slots[i] == false) {
+            memset(GLOBAL_failed_broadcasts[i],0x00,sizeof(GLOBAL_failed_broadcasts[i])); //clear row
+            snprintf(GLOBAL_failed_broadcasts[i],sizeof(GLOBAL_failed_broadcasts[i]),"%s",eventstring); //save new row
+            GLOBAL_failed_broadcast_slots[i] = true;
+            saved = true;
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"Failed Broadcast saved: %s",eventstring);debug_exe();}
+            break;
+        }
+    }
+    if (!saved) {
+        if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"Failed Broadcast save fail");debug_exe();}
+    }
+    return;
+}
+void failed_broadcasts_tx() {
+    //check we have something to send...
+    int numbertosend = 0;
+    for(int i = 0; i < sizeof(GLOBAL_failed_broadcast_slots); i++) {
+        if (GLOBAL_failed_broadcast_slots[i] == true) {
+            numbertosend ++;
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"Retry:%s",GLOBAL_failed_broadcasts[i]);debug_exe();}
+        }
+    }
+    if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"Failed Broadcasts to send:%d",numbertosend);debug_exe();}
+    for(int i = 0; i < sizeof(GLOBAL_failed_broadcast_slots); i++) {
+        if (GLOBAL_failed_broadcast_slots[i] == true) {
+            if (RET_NetworkFailCount <= DEFAULT_MAX_FAILED_CONNECTIONS) {
+                if (modem.on(RET_force2G)) {
+                    if (modem.registerOnNetwork(2,RET_setting_connection_timeout,RET_NetworkFailCount)) {
+                        char result[100];
+                        bool getResponse = false;
+                        snprintf(result,sizeof(result),"%s",modem.USSDmessage(GLOBAL_failed_broadcasts[i], getResponse, GLOBAL_defaultApi));
+                        if (strcmp(result, "sendok") == 0) {
+                            //clear row
+                            memset(GLOBAL_failed_broadcasts[i],0x00,sizeof(GLOBAL_failed_broadcasts[i]));
+                            GLOBAL_failed_broadcast_slots[i] = false;
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
 bool event_setup(bool manualrun) {
-    bool pass = true;
-    float voltage = getBatteryV();
+    bool pass = false;
     LED1on(0);
     if (RET_NetworkFailCount > DEFAULT_MAX_FAILED_CONNECTIONS) addToExceptionString("NF");
     if (RET_GPSFailCount > DEFAULT_MAX_FAILED_GPS) addToExceptionString("GF");
@@ -654,7 +759,6 @@
     RET_NetworkFailCount = 0;
     RET_GPSFailCount = 0;
     RET_setting_connection_timeout = 180; //reset to longer value to setup run to help with connection
-    float temperature = getTemperature();
     bool selftestresult = selfTest();
     int connectionStartTime = RET_RTCunixtime;
     if (modem.on(RET_force2G)) {
@@ -663,63 +767,55 @@
             int timetaken_connection = (RET_RTCunixtime - connectionStartTime);
             if (manualrun) addToExceptionString("MAN");
             char bytestosend[160];
-            snprintf(bytestosend,sizeof(bytestosend),"(%s,a:setup,f:%d,v:%.2f,t:%.1f,e:%d,y:%d,z:SETUP-%s,k:%s,m:%s,c:1,s:1)\0",GLOBAL_defaultApi,FW_VERSION,voltage,temperature,timetaken_total,timetaken_connection,GLOBAL_exceptionString,SKU,HW_MAJORREVISION);
+            snprintf(bytestosend,sizeof(bytestosend),"(%s,a:setup,f:%d,v:%.2f,t:%.1f,e:%d,y:%d,z:SETUP-%s,k:%s,m:%s,c:1,s:1)\0",GLOBAL_defaultApi,FW_VERSION,RET_voltage,RET_temperature,timetaken_total,timetaken_connection,GLOBAL_exceptionString,SKU,HW_MAJORREVISION);
             char result[200];
-            snprintf(result,sizeof(result),"%s",modem.USSDmessage(bytestosend, true, 2, GLOBAL_defaultApi));
+            snprintf(result,sizeof(result),"%s",modem.USSDmessage(bytestosend, true, GLOBAL_defaultApi));
             RET_setupInProgress = false; //this turns off the flashing led
-            if (strcmp(result, "err") != 0) {
-                if (saveSettings(result) == false) {
+            if (strcmp(result, "sendokrecfail") == 0) {
+                //send ok but receive fail
+                if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"USSD Send Ok but Rec fail");debug_exe();}
+                sendErrorLog("ERR-SU-NR");
+            } else if (strcmp(result, "sendfail") == 0) {
+                //do nothing
+                if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"USSD Send Fail");debug_exe();}
+            } else {
+                if (saveSettings(result) == true) {
+                    pass = true;
+                } else {
                     //something went critically wrong getting settings 
-                    pass = false;
                     sendErrorLog("ERR-SU-IR");
-                }                   
-            } else {
-                //Response error
-                sendErrorLog("ERR-SU-NR");
+                }
             }
-        } else {
-            //FAILUREMODE modem failed to register on network
-            //LED1errorCode(3,1); //ERROR 3
-            pass = false;
         }
     } else {
         //FAILUREMODE Modem failed to turn on  
-        LED1errorCode(2,1); //ERROR 2
-        pass = false;
+        if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"Modem Fail");debug_exe();}
     }
     
     //IF WE PASSED THEN LETS DO OTHER POSTS
     if (pass == true) {
         GLOBAL_wakeTime = RET_RTCunixtime; //lets reset this here so that the following loc and act function have sensible values for total time
-    
         //GET LOC DATA
         uint8_t previous_location_accuracy = RET_setting_location_accuracy;
         RET_setting_location_accuracy = 1; //set location mode to CL only
-        event_location_tx();
+        event_location_tx(false);
         RET_setting_location_accuracy = previous_location_accuracy; //set location mode back to previous
-    
         //SEND ANY ACTIVITY DATA
         event_activity_tx();
-        
         LED1blink(4,500); //PASS AND END
     }
     
     //TIDY UP = LOG RUN TIME - THIS MUST GO AT END AFTER WE HAVE GOT SERVER TIMESTAMP
-    modem.off(true);
     RET_SetupRunAt = RET_RTCunixtime;
-    setEventTimes();
-    
     RET_GPSFailCount = 0;
     RET_NetworkFailCount = 0;
     //RESULT
     return pass;
 }
-
 void event_turnonofflog_tx(bool turnon) {
     RET_NetworkFailCount = 0; //reset network blocker
     RET_GPSFailCount = 0;
-    float voltage = getBatteryV();
-    float temperature = getTemperature();
+    updateBatteryV();
     int connectionStartTime = RET_RTCunixtime;
     if (modem.on(RET_force2G)) {
         char locString[70];
@@ -731,21 +827,21 @@
             int timetaken_connection = (RET_RTCunixtime - connectionStartTime);
             char bytestosend[160];
             if (turnon) {
-                snprintf(bytestosend,sizeof(bytestosend),"(%s,a:log,f:%d,t:%.1f,v:%.2f,z:TURNON,e:%d,y:%d,x:%d,c:1,s:1%s)\0",GLOBAL_defaultApi,FW_VERSION,temperature,voltage,timetaken_total,timetaken_connection,timetaken_gps,locString);
+                snprintf(bytestosend,sizeof(bytestosend),"(%s,a:log,f:%d,t:%.1f,v:%.2f,z:TURNON,e:%d,y:%d,x:%d,c:1,s:1%s)\0",GLOBAL_defaultApi,FW_VERSION,RET_temperature,RET_voltage,timetaken_total,timetaken_connection,timetaken_gps,locString);
             } else {
-                snprintf(bytestosend,sizeof(bytestosend),"(%s,a:log,f:%d,t:%.1f,v:%.2f,z:TURNOFF,e:%d,y:%d,x:%d,c:1,s:1%s)\0",GLOBAL_defaultApi,FW_VERSION,temperature,voltage,timetaken_total,timetaken_connection,timetaken_gps,locString);
+                snprintf(bytestosend,sizeof(bytestosend),"(%s,a:log,f:%d,t:%.1f,v:%.2f,z:TURNOFF,e:%d,y:%d,x:%d,c:1,s:1%s)\0",GLOBAL_defaultApi,FW_VERSION,RET_temperature,RET_voltage,timetaken_total,timetaken_connection,timetaken_gps,locString);
             }
             char result[180];
-            snprintf(result,sizeof(result),"%s",modem.USSDmessage(bytestosend, false, 2, GLOBAL_defaultApi));
+            snprintf(result,sizeof(result),"%s",modem.USSDmessage(bytestosend, false, GLOBAL_defaultApi));
         }
     }
-    modem.off(true);
 }
-
-void event_location_tx() {
-    float voltage = getBatteryV();
-    float temperature = getTemperature();
+void event_location_tx(bool failsafe) {
+    //check if we have any outstanding to send
+    failed_broadcasts_tx();
     bool selfTestResult = selfTest();
+    char bytesToSend[160];
+    //see if we are in range of ble detector, if so, no need to get gps and broadcast
     //Set any network or GPS fail flags
     if (RET_NetworkFailCount > DEFAULT_MAX_FAILED_CONNECTIONS) addToExceptionString("NF");
     if (RET_GPSFailCount > DEFAULT_MAX_FAILED_GPS) addToExceptionString("GF");
@@ -757,6 +853,7 @@
             int gpsStartTime = RET_RTCunixtime;
             memcpy(locString, modem.getLocation(RET_setting_location_accuracy, RET_setting_location_timeout, RET_GPSFailCount, RET_NetworkFailCount), sizeof(locString));
             int timetaken_gps = (RET_RTCunixtime - gpsStartTime);
+            
             //SEND DATA
             int connectionStartTime = RET_RTCunixtime;
             if (modem.registerOnNetwork(DEFAULT_CONNECTION_ATTEMPTS,RET_setting_connection_timeout,RET_NetworkFailCount)) {
@@ -766,32 +863,85 @@
                 bool getSettings = true;
                 //work out if we need to get settings back
                 if (  ((RET_RTCunixtime - RET_SettingsGotAt)/3600) < RET_setting_minimumupdate_hrs  ) { getSettings = false; timetaken_total -= 10;} //remove the extra 10 seconds from times
-                char bytesToSend[160];
-                snprintf(bytesToSend,sizeof(bytesToSend),"(%s,a:loc,f:%d,t:%.1f,v:%.2f,z:LOC-%s,e:%d,y:%d,x:%d,c:1,s:%d%s)\0",GLOBAL_defaultApi,FW_VERSION,temperature,voltage,GLOBAL_exceptionString,timetaken_total,timetaken_connection,timetaken_gps,getSettings,locString);
+                snprintf(bytesToSend,sizeof(bytesToSend),"(%s,a:loc,f:%d,t:%.1f,v:%.2f,z:LOC-%s,e:%d,y:%d,x:%d,j:%d,c:1,s:%d%s)\0",GLOBAL_defaultApi,FW_VERSION,RET_temperature,RET_voltage,GLOBAL_exceptionString,timetaken_total,timetaken_connection,timetaken_gps,RET_motionTriggeredInLocTXInterval,getSettings,locString);
                 char result[180];
-                snprintf(result,sizeof(result),"%s",modem.USSDmessage(bytesToSend, getSettings, 2, GLOBAL_defaultApi));
-                if (result != "err") {
+                snprintf(result,sizeof(result),"%s",modem.USSDmessage(bytesToSend, getSettings, GLOBAL_defaultApi));
+                if (getSettings == true && strcmp(result, "sendokrecfail") == 0) {
+                    //send ok but receive fail
+                    if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"USSD Send Ok but Rec fail");debug_exe();}
+                    sendErrorLog("ERR-LOC-NR");
+                } else if (strcmp(result, "sendok") == 0) {
+                    //do nothing
+                } else if (strcmp(result, "sendfail") == 0) {
+                    if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"USSD Send Fail");debug_exe();}
+                    //need to log for retry
+                } else {
                     if (getSettings) {
                         if (saveSettings(result) == false){sendErrorLog("ERR-LOC-IR");}
                     }
-                } else {
-                    sendErrorLog("ERR-LOC-NR");
                 }
             }
         }
     }
-    modem.off(true);
     //RESETS
     RET_motionTriggeredInLocTXInterval = false;
     setEventTime_Location();
 }
-
-void event_activity_log(char* eventstring) {
-    //STUB
-    return;
+void event_activity_tx() {
+    //check if we have any outstanding to send
+    failed_broadcasts_tx();
+    //check we have something to send...
+    bool sendok = false;
+    if (RET_motionTotalActivityHoursSincePost > 0.0f && RET_setting_activity_mode > 0) {
+        //Build data to send
+        char bytesToSend[160];
+        if (RET_setting_activity_mode == 1) {
+            snprintf(bytesToSend,sizeof(bytesToSend),"(%s,a:act,t:%u,r:%.2f,h:%.2f,c:1)\0",GLOBAL_defaultApi,RET_motionFrameStart,RET_motionTotalActivityHoursSincePost,RET_motionTotalActivityHours);
+        } else if (RET_setting_activity_mode == 2) {
+            snprintf(bytesToSend,sizeof(bytesToSend),"(%s,a:act,e:%s,t:%u,r:%.2f,c:1)\0",GLOBAL_defaultApi,RET_activityData,RET_motionFrameStart,RET_motionTotalActivityHoursSincePost);
+        }
+        if (RET_NetworkFailCount <= DEFAULT_MAX_FAILED_CONNECTIONS) {
+            if (modem.on(RET_force2G)) {
+                //SEND DATA
+                if (modem.registerOnNetwork(2,RET_setting_connection_timeout,RET_NetworkFailCount)) {
+                    char result[100];
+                    bool getResponse = false;
+                    snprintf(result,sizeof(result),"%s",modem.USSDmessage(bytesToSend, getResponse, GLOBAL_defaultApi));
+                    if (strcmp(result, "sendok") == 0) {
+                        sendok = true;
+                        //if(!RET_debug) {sendok = true;} //FOR TESTING
+                    }
+                }
+            }
+        }
+        //If send failed then log it for retry - only need to do this for mode 2, for mode the time just increments
+        if (sendok == true) {
+            if (RET_setting_activity_mode == 1) {
+                RET_motionTotalActivityHoursSincePost = 0.0f;
+                if (RET_haveSettings) { RET_motionFrameStart = RET_RTCunixtime; }
+            } else if (RET_setting_activity_mode == 2) {
+                RET_motionTotalActivityHoursSincePost = 0.0f;
+                if (RET_haveSettings) { RET_motionFrameStart = RET_RTCunixtime; }
+            }
+        } else if (sendok == false) {
+            if (RET_setting_activity_mode == 1) {
+                //do nothing
+            } else if (RET_setting_activity_mode == 2) {
+                failed_broadcast_log(bytesToSend);
+                RET_motionTotalActivityHoursSincePost = 0.0f;
+                if (RET_haveSettings) { RET_motionFrameStart = RET_RTCunixtime; }
+            }
+        }
+    }
+    //RESETS
+    memset(RET_activityData,0x00,sizeof(RET_activityData));
+    setEventTime_Activity();
 }
+/*
 void event_activity_tx() {
-    //SEND ACTIVITY DATA
+    bool sendok = false;
+    //check if we have any outstanding to send
+    failed_broadcasts_tx();
     
     //check we have something to send...
     if (RET_motionTotalActivityHoursSincePost > 0.0f && RET_setting_activity_mode > 0) {
@@ -802,35 +952,33 @@
         } else if (RET_setting_activity_mode == 2) {
             snprintf(bytesToSend,sizeof(bytesToSend),"(%s,a:act,e:%s,t:%u,r:%.2f,c:1)\0",GLOBAL_defaultApi,RET_activityData,RET_motionFrameStart,RET_motionTotalActivityHoursSincePost);
         }
-        
         if (RET_NetworkFailCount <= DEFAULT_MAX_FAILED_CONNECTIONS) {
-            float temperature = getTemperature();
-            float voltage = getBatteryV();
             if (modem.on(RET_force2G)) {
                 //SEND DATA
                 if (modem.registerOnNetwork(2,RET_setting_connection_timeout,RET_NetworkFailCount)) {
-                    char result[180];
+                    char result[100];
                     bool getResponse = false;
-                    snprintf(result,sizeof(result),"%s",modem.USSDmessage(bytesToSend, getResponse, 3, GLOBAL_defaultApi));
-                    if (result != "err") {
-                        //RESET ACTIVITY FRAME
-                        memset(RET_activityData,0,sizeof(RET_activityData));
-                        if (RET_haveSettings) { RET_motionFrameStart = RET_RTCunixtime; }
-                    } else {
-                        //TODO: LETS LOG THE DATA INSTEAD   
-                        event_activity_log(bytesToSend);
+                    snprintf(result,sizeof(result),"%s",modem.USSDmessage(bytesToSend, getResponse, GLOBAL_defaultApi));
+                    if (strcmp(result, "sendok") == 0) {
+                        //sendok = true;
+                        if(!RET_debug) {sendok = true;}
                     }
                 }
             }
             modem.off(true);
-        } else {
-            //TODO: LETS LOG THE DATA INSTEAD   
-            event_activity_log(bytesToSend);
+        }
+        //If send failed then log it for retry
+        if (sendok == false) {
+            failed_broadcast_log(bytesToSend);
         }
     }
     //RESETS
+    RET_motionTotalActivityHoursSincePost = 0.0f;
+    memset(RET_activityData,0x00,sizeof(RET_activityData));
+    if (RET_haveSettings) { RET_motionFrameStart = RET_RTCunixtime; } //this is now safe to do as we are logging the fails
     setEventTime_Activity();
 }
+*/
 
 //------------------------------------------------------------------------------
 // STATE ENGINE
@@ -843,17 +991,18 @@
             //check that we havent run setup too recently
             time_t setupRunAt_delta = (RET_RTCunixtime - RET_SetupRunAt);
             if (RET_SetupRunAt == 0 || setupRunAt_delta >= ONEDAYINSECONDS) {
+                updateBatteryV();
                 if (event_setup(false)) {
                     // All good
                     setState(STATE_NORMAL);
                 } else {
                     RET_eventTime_wakeFromDormant = (RET_RTCunixtime + ONEDAYINSECONDS);
                     setState(STATE_DORMANT);
-                    if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"SETUP FAILED:DORMANT until %u\n",RET_eventTime_wakeFromDormant);debug_exe();}
+                    if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"SETUP FAILED:DORMANT until %u\n",RET_eventTime_wakeFromDormant);debug_exe();}
                 }
             } else {
                 time_t setupCanRunAt = (RET_RTCunixtime + (ONEDAYINSECONDS - setupRunAt_delta));
-                if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"SETUP CAN RUN AGAIN @%u \n",setupCanRunAt);debug_exe();}
+                if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"SETUP CAN RUN AGAIN @%u \n",setupCanRunAt);debug_exe();}
             }
             RET_busy = false;
             break;
@@ -872,7 +1021,7 @@
                         if (RET_motionTriggeredInLocTXInterval == true) {
                             run_location_tx = true;
                         } else {
-                             if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "Skip TX no mot\n");debug_exe();}
+                             if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "Skip TX no mot\n");debug_exe();}
                         }
                     }
                     break;
@@ -883,9 +1032,11 @@
             if(RET_RTCunixtime >= RET_eventTime_location_failsafe_tx && RET_eventTime_location_failsafe_tx > 0) { 
                 RET_NetworkFailCount = 0; //reset to ensure connection
                 RET_GPSFailCount = 0; // reset to ensure gps try
-                run_location_tx = true;
+                updateBatteryV();
+                event_location_tx(true);
+            } else {
+                if (run_location_tx) { updateBatteryV(); event_location_tx(false); }
             }
-            if (run_location_tx) { event_location_tx(); }
             
             
             //ACTIVITY EVENT
@@ -915,15 +1066,16 @@
                     setState(STATE_SETUP); 
                 }
             }
-            if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"STATE:DORMANT until %u\n",RET_eventTime_wakeFromDormant);debug_exe();}
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"STATE:DORMANT until %u  Prev S:%d\n",RET_eventTime_wakeFromDormant,RET_state_prev);debug_exe();}
             RET_busy = false;
             break;
         }
         case STATE_BUTTONPRESS1 :
         {
             RET_busy = true;
-            if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"BUTTON PRESS 1\n");debug_exe();}
-            if (getBatteryV() < 2.5f) {
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"BUTTON PRESS 1\n");debug_exe();}
+            updateBatteryV();
+            if (RET_voltage < 2.5f) {
                 LED1blink(3,500);
             } else if (selfTest() == false){
                 LED1blink(4,500);
@@ -939,6 +1091,7 @@
             } else {
                 setState(RET_state_prev);
             }
+            dumpSettings();
             RET_busy = false;
             break;
         }
@@ -946,9 +1099,10 @@
         {
             RET_busy = true;
             if(RET_state_prev == STATE_DORMANT || RET_state_prev == STATE_NORMAL) {
-                if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"BUTTON PRESS 3\n");debug_exe();}
+                if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"BUTTON PRESS 3\n");debug_exe();}
                 LED1blink(3,500);
                 LED1on(0);
+                updateBatteryV();
                 event_setup(true);
                 LED1off();
             }
@@ -960,43 +1114,48 @@
         {
             RET_busy = true;
             if(RET_state_prev == STATE_DORMANT || RET_state_prev == STATE_NORMAL) {
-                if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"BUTTON PRESS 5\n");debug_exe();}
+                if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"BUTTON PRESS 5\n");debug_exe();}
                 LED1blink(5,500);
                 LED1on(0);
-                event_location_tx();
+                updateBatteryV();
+                event_location_tx(false);
                 LED1off();
             }
             setState(STATE_NORMAL); //turns device back on
             RET_busy = false;
             break;  
         }
-        case STATE_BUTTONHOLD :
+        case STATE_TURNOFF :
         {
             RET_busy = true;
-            if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"BUTTON HOLD \n");debug_exe();}
-            if (RET_state_prev == STATE_NORMAL) {
-                RET_eventTime_wakeFromDormant = (RET_RTCunixtime + THREEDAYSINSECONDS);
-                setState(STATE_DORMANT);
-                if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"TURNING OFF\n");debug_exe();}
-                if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"STATE:DORMANT until %u\n",RET_eventTime_wakeFromDormant);debug_exe();}
-                LED1on(5000);
-                event_turnonofflog_tx(false);
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"BUTTON HOLD \n");debug_exe();}
+            RET_eventTime_wakeFromDormant = (RET_RTCunixtime + THREEDAYSINSECONDS);
+            setState(STATE_DORMANT);
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"TURNING OFF\n");debug_exe();}
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"STATE:DORMANT until %u\n",RET_eventTime_wakeFromDormant);debug_exe();}
+            LED1on(5000);
+            //event_turnonofflog_tx(false);
+            RET_busy = false;
+            break;
+        }
+        case STATE_TURNON :
+        {
+            RET_busy = true;
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"BUTTON HOLD \n");debug_exe();}
+            if (RET_haveSettings) {
+                setState(STATE_NORMAL);
             } else {
-                if (RET_haveSettings) {
-                    setState(STATE_NORMAL);
-                } else {
-                    setState(STATE_SETUP);
-                }
-                if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"TURNING ON\n");debug_exe();}
-                LED1blink(20,100);
+                setState(STATE_SETUP);
             }
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"TURNING ON\n");debug_exe();}
+            LED1blink(20,100);
             RET_busy = false;
             break;
         }
         case STATE_SCORCHEDEARTH :
         {
             RET_busy = true;
-            if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"SCORCHED EARTH - RESETTING");debug_exe();}
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"SCORCHED EARTH - RESETTING");debug_exe();}
             setState(STATE_SETUP); //this wont be used but just incase to kick it out of this state
             read_app_data_from_flash(&app_data);
             app_data.current_firmware_version = 0;
@@ -1018,10 +1177,12 @@
 //------------------------------------------------------------------------------ 
 int main() {
     //INIT
+    LED1off();
+    ThisThread::sleep_for(2000); //Initial pause, this is needed for softdevice to init, dont remove!! If we dont have this we get crashes
     watchdog.configure(300.0); //5 mins
-    LED1off();
     modem.off(false);
     RTCticker.attach(&RTCtick, 1.0);
+    LPtimer.start();
     button.fall(&buttonPress);
     button.rise(&buttonRelease);
     read_app_data_from_flash(&app_data);
@@ -1033,35 +1194,34 @@
         RET_coldBoot = 1;
         switch(NRF_POWER->RESETREAS) {
             case 0x00000001  :
-                if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"RR:HW\n");debug_exe();}
+                //if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"RR:HW\n");debug_exe();}
             break;
             case 0x00000002  :
-                if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"RR:WD\n");debug_exe();}
+                //if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"RR:WD\n");debug_exe();}
             break;
             case 0x00000004  :
-                if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"RR:SW\n");debug_exe();}
+                //if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"RR:SW\n");debug_exe();}
             break;
             case 0x00000008  :
-                if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"RR:LU\n");debug_exe();}
+                //if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"RR:LU\n");debug_exe();}
             break;            
         }
         NRF_POWER->RESETREAS = 0xffffffff;
     } else {
         //if its not one of these reasons then its a power-on or a brown-out
-        if(get_flag(&app_data, app_execution_flag) == false) {
+        //if(get_flag(&app_data, app_execution_flag) == false) {
             //THIS is a unexpected reset / brownout???
-            //THIS NEEDS TESTING
-        }
+        //}
     }
     
     //CHECK FOR FIRST BOOT
     if (RET_coldBoot == 1) { 
         setDefaults(); 
         //check battery
-        if (getBatteryV() < 2.5f) {
+        updateBatteryV();
+        if (RET_voltage < 2.5f) {
             //battery low
             LED1errorCode(10,2);
-            addToExceptionString("BA");
         }
         addToExceptionString("FR");
     }
@@ -1071,6 +1231,7 @@
         //WATCHDOG
         watchdogKick();
         RET_asleep = false;
+        updateTemperatures();
         
         //INIT
         resetGlobals();
@@ -1087,27 +1248,35 @@
         }
         
         //MAIN LOGIC
-        if(DEBUG_ON){
+        if(RET_debug){
             if (RET_state != 99) {
                 debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "F:%d, S:%d, SET:%d, MF:%d, MS:%d, MTX:%d, %u, L:%u, LFS:%u, A:%u", FW_VERSION, RET_state, RET_haveSettings, RET_motionTriggeredinFrame, RET_motionState, RET_motionTriggeredInLocTXInterval, RET_RTCunixtime,RET_eventTime_location_tx,RET_eventTime_location_failsafe_tx,RET_eventTime_activity_tx);debug_exe();
-                debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "ACT M:%d, HsP:%.2f, Ht:%.2f D:%s\n",RET_setting_activity_mode,RET_motionTotalActivityHoursSincePost,RET_motionTotalActivityHours,RET_activityData);debug_exe();
+                debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "ACT M:%d, HsP:%.2f, Ht:%.2f, D:%s",RET_setting_activity_mode,RET_motionTotalActivityHoursSincePost,RET_motionTotalActivityHours,RET_activityData);debug_exe();
             } else {
                 debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "F:%d, S:%d, WAKE@:%u\n", FW_VERSION, RET_state, RET_eventTime_wakeFromDormant);debug_exe();
             }
+            if (RET_coldBoot == false && RET_RTCunixtime > RET_debug_offat) {
+                debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"DEBUGGING OFF\n");debug_exe();
+                RET_debug = false;
+            }
         }
 
         //STATE ENGINE
         mainStateEngine();
-                
+        
         //LOG FIRST RUN - BOOTLOADER COMMS
         if (RET_coldBoot) {
             recordFirmwareAsValid();
             RET_coldBoot = 0;
         }
-                
+        
         //PRE-SLEEP ACTIONS
         LED1off();
-        modem.off(false);
+        if (GLOBAL_modemOn) {
+            modem.off(true); //SOFT SHUT DOWN - THIS IS THE ONLY MODEM OFF, DONT REMOVE
+        } else {
+            modem.off(false); //HARD SHUT DOWN - THIS IS THE ONLY MODEM OFF, DONT REMOVE
+        }
         RET_motionTriggeredinFrame = false;
         if (GLOBAL_needToConfigureLis3dh) { lis3dh_configureForSleep(RET_setting_motion_g,RET_setting_impact_g); }
         nrf_configureForSleep();
--- a/main.h	Thu May 16 12:31:44 2019 +0000
+++ b/main.h	Thu May 23 11:39:28 2019 +0000
@@ -16,14 +16,13 @@
 //------------------------------------------------------------------------------
 //DEFINES
 //------------------------------------------------------------------------------ 
-#define FW_VERSION          18
+#define FW_VERSION          20
 //#define SKU                 "GPSPLUSDEV"
 #define SKU                 "GPSPLUS"
 #define HW_MAJORREVISION    "001"
 
 //MODES
 #define USE_NRF_TEMP_SENSOR                 1
-#define DEBUG_ON                            1
 
 //DEFAULT SETTINGS
 #define DEFAULT_SLEEP_FRAME                 60000
@@ -39,9 +38,8 @@
 #define DEFAULT_IMPACT_G                    127
 #define DEFAULT_CONNECTION_ATTEMPTS         1
 #define DEFAULT_CONNECTION_TIMEOUT          140
-#define DEFAULT_BEACON_INTERVAL_SECONDS     20
-#define DEFAULT_MAX_FAILED_CONNECTIONS      2 //max number of failed connections before device stops broadcasting until movement detected
-#define DEFAULT_MAX_FAILED_GPS              2 //max number of failed gps searches before device stops trying gps until movement detected
+#define DEFAULT_MAX_FAILED_CONNECTIONS      3 //max number of failed connections before device stops broadcasting until movement detected
+#define DEFAULT_MAX_FAILED_GPS              3 //max number of failed gps searches before device stops trying gps until movement detected
 
 //CONSTS
 #define ONEDAYINSECONDS                     86400
@@ -49,6 +47,12 @@
 #define SEVENDAYSINSECONDS                  604800
 #define TENDAYSINSECONDS                    864000
 
+//MODES
+#define LOCATION_MODE_INTERVAL              1
+#define LOCATION_MODE_INTERVAL_MOTION       2
+#define LOCATION_MODE_INTELLIGENT           3
+#define LOCATION_MODE_REALTIME              4
+
 //DEFINES
 #define ACTIVITY_BUFFERSIZE                 100
 
@@ -56,19 +60,18 @@
 //mbed Libraries
 //------------------------------------------------------------------------------
 #include "mbed.h"
-#include "nrf_soc.h"
+//#include "nrf_soc.h"
 #include "nrf_temp.h"
 #include "board.h"
 //#include "ble/BLE.h"
-//#include "nvstore.h"
-#include "FlashIAPBlockDevice.h"
+//#include "FlashIAPBlockDevice.h"
 
 //------------------------------------------------------------------------------
 //peripheral Libraries
 //------------------------------------------------------------------------------
 #include "WatchdogTimer.h"
 #include "LIS3DH.h"
-#include "SI7060.h"
+//#include "SI7060.h"
 #include "acd_nrf52_saadc.h"
 
 //------------------------------------------------------------------------------
@@ -102,7 +105,6 @@
 extern time_t GLOBAL_RTCunixtime;
 extern time_t GLOBAL_wakeTime;
 extern char GLOBAL_debug_buffer[200];
-extern uint8_t RTCtick_ledflash_count;
 //FUNCS
 extern void watchdogKick();
 
--- a/modem.cpp	Thu May 16 12:31:44 2019 +0000
+++ b/modem.cpp	Thu May 23 11:39:28 2019 +0000
@@ -4,8 +4,9 @@
 
 Modem::Modem(PinName pwrkey, PinName vreg_en, PinName w_disable): _pwrkey(pwrkey), _vreg_en(vreg_en), _w_disable(w_disable)
 {
-    _pwrkey.input();
-    _w_disable.input();
+    //initially setup control lines as no pull to reduce power consumption, they will be correctly configured by .on() and .off()
+    nrf_gpio_cfg_input(PN_GSM_PWR_KEY, NRF_GPIO_PIN_NOPULL);
+    nrf_gpio_cfg_input(PN_GSM_WAKE_DISABLE, NRF_GPIO_PIN_NOPULL);
 }
 
 void Modem::ATsendCMD(char* cmd) 
@@ -141,10 +142,21 @@
 
 void Modem::off(bool soft) 
 {
-    if (GLOBAL_modemOn) {
+    if (GLOBAL_modemOn == true) {
         if (soft) {
-            ATsendCMD("AT+QPOWD=1");
-            ATwaitForWord("POWERED DOWN",ATTIMEOUT_MED);
+            bool atok = false;
+            int  atoktries = 0;
+            while(atok == false && atoktries < 3) {
+                ATsendCMD("AT");
+                if (ATwaitForWord("OK\r\n",ATTIMEOUT_SHORT)) {
+                    atok = true;
+                }
+                atoktries ++;
+            }
+            if (atok == true) {
+                ATsendCMD("AT+QPOWD=0");
+                ATwaitForWord("POWERED DOWN",ATTIMEOUT_SHORT);
+            }
         }
         GLOBAL_modemOn = false;
     }
@@ -153,6 +165,10 @@
     _w_disable.input(); //enable airplane mode
     _pwrkey.input();
     _vreg_en = 0;       //kill power to module
+    
+    //disable control pins, needed to get low power off state
+    nrf_gpio_cfg_input(PN_GSM_PWR_KEY, NRF_GPIO_PIN_NOPULL);
+    nrf_gpio_cfg_input(PN_GSM_WAKE_DISABLE, NRF_GPIO_PIN_NOPULL);
 }
 
 uint64_t Modem::getIMEI() 
@@ -220,11 +236,15 @@
             while(GLOBAL_registeredOnNetwork == false && runtime < timeout) {
                 runtime = (t.read() - startseconds);
                 ThisThread::sleep_for(1000);
+                //TURN OFF ECHO //we need this again incase of modem brown out, as it means the modems starts echoing again
+                    ATsendCMD("ATE0");
+                    ATwaitForWord("OK",ATTIMEOUT_SHORT);
                 ATsendCMD("AT+CREG?");
                 if (ATwaitForWord("+CREG: 0,5",ATTIMEOUT_VERYSHORT)) {
                     NRFuart_flush();
                     GLOBAL_registeredOnNetwork = true;
                 };
+                
             }
             attempt ++;
             //if there are more attempt potential, then reset the modem
@@ -239,7 +259,7 @@
     NRFuart_flush();
     if (GLOBAL_registeredOnNetwork == true) {
         BYREF_NetworkFailCount = 0;
-        ThisThread::sleep_for(2000); //wait 2 seconds for things to settle
+        ThisThread::sleep_for(1000); //wait 1 seconds for things to settle
         return true;
     } else {
         BYREF_NetworkFailCount ++;
@@ -252,11 +272,16 @@
     bool sent = false;
     bool criticalfail = false;
     int attempt = 0;
+    bool gotResponse = false;
     
     //TRY X NUMBER OF TIMES
     while (!sent && attempt < maxAttempts) {
         criticalfail = false;
         
+        //TURN OFF ECHO //we need this again incase of modem brown out, as it means the modems starts echoing again
+            ATsendCMD("ATE0");
+            ATwaitForWord("OK",ATTIMEOUT_SHORT);
+        
         if (!criticalfail) {
             ATsendCMD("AT+QHTTPCFG=\"contextid\",1");    
             if (!ATwaitForWord("OK\r",ATTIMEOUT_SHORT)) criticalfail = true;
@@ -269,7 +294,7 @@
         
         if (!criticalfail) {
             ATsendCMD("AT+QIACT=1");    
-            if (!ATwaitForWord("OK\r",ATTIMEOUT_MED)) criticalfail = true;
+            if (!ATwaitForWord("OK\r",ATTIMEOUT_LONG)) criticalfail = true;
         }
         
         /*if (!criticalfail) {
@@ -309,6 +334,10 @@
             ATsendCMD("AT+QHTTPREAD=80");
             ATwaitForWord("CONNECT\r\n",ATTIMEOUT_MED);
             ATgetResponse('\r',ATTIMEOUT_SHORT);
+            
+            if (ATwaitForWord("+QHTTPREAD: 0",ATTIMEOUT_MED)) {
+                gotResponse = true;
+            }
         }
         
         NRFuart_flush();
@@ -318,28 +347,53 @@
         if (getResponse == false) {
             return "sendonly";
         } else {
-            return ATinBuffer;
+            if (gotResponse == true) {
+                return ATinBuffer;
+            } else {
+                return "noresp";
+            }
         }
     } else {
         return "err";
     }
 }
  
-bool Modem::USSDsend(char* message, int maxAttempts) 
+bool Modem::USSDsend(char* message) 
 {
     bool sent = false;
     int attempt = 0;
+    
+    //CHECK FOR AT OK
+    bool atok = false;
+    int  atoktries = 0;
+    while(atok == false && atoktries < 3) {
+        ATsendCMD("AT");
+        if (ATwaitForWord("OK\r\n",ATTIMEOUT_SHORT)) {
+            atok = true;
+        }
+        atoktries ++;
+    }
+    if (!atok) return false;
+    
+    char bytestosend[160];
+    snprintf(bytestosend, sizeof(bytestosend), "AT+CUSD=1,\"#469*%s#\"", message);
+        
     //TRY X NUMBER OF TIMES
-    while (!sent && attempt < maxAttempts) {
-        char bytestosend[160];
-        snprintf(bytestosend, sizeof(bytestosend), "AT+CUSD=1,\"#469*%s#\"", message);
+    //maxAttempts
+    while (!sent && attempt < 100) { //10 seconds, 100*200ms
+        //TURN OFF ECHO //we need this again incase of modem brown out, as it means the modems starts echoing again
+        ATsendCMD("ATE0");
+        ATwaitForWord("OK",ATTIMEOUT_SHORT);
         ATsendCMD(bytestosend);
-        if (ATwaitForWord("+CUSD: 0",ATTIMEOUT_MED)) {
-            sent = true;
-        };
+        if (!ATwaitForWord("+CME ERROR",200)) { 
+            if (ATwaitForWord("+CUSD: 0",ATTIMEOUT_SHORT)) {
+                sent = true;
+            };
+        }
         NRFuart_flush();
         attempt ++;
     }
+    
     if (sent) {
         return true;
     } else {
@@ -381,7 +435,7 @@
 }
 
 
-char* Modem::USSDmessage(char* message, bool needResponse, int maxAttempts, char* api) 
+char* Modem::USSDmessage(char* message, bool needResponse, char* api) 
 {  
     uint8_t messageIndex = 1;
     bool result;
@@ -389,9 +443,9 @@
     if (messageLength > USSD_MAXLENGTH) {
         char message_failsafe[100];
         snprintf(message_failsafe,sizeof(message_failsafe),"(%s,a:error,z:TOOBIG,s:1,c:%d)\0",api,messageIndex);
-        result = USSDsend(message_failsafe, maxAttempts);
+        result = USSDsend(message_failsafe);
     } else {
-        result = USSDsend(message, maxAttempts);
+        result = USSDsend(message);
     }
     if (result) {
         if (needResponse) {
@@ -399,13 +453,13 @@
             if (strcmp(response, "err") != 0) {
                 return response;
             } else {
-                return "err-sendonly";
+                return "sendokrecfail";
             }
         } else {
-            return "ok";   
+            return "sendok";
         } 
     } else {
-        return "err";   
+        return "sendfail";   
     }
 }
 
@@ -421,6 +475,10 @@
     uint32_t startseconds;
     uint32_t runtime;
     
+    //TURN OFF ECHO //we need this again incase of modem brown out, as it means the modems starts echoing again
+    ATsendCMD("ATE0");
+    ATwaitForWord("OK",ATTIMEOUT_SHORT);
+    
     if (accuracy >= 2 && BYREF_GPSFailCount <= DEFAULT_MAX_FAILED_GPS) {
         //Enable External LNA power - IS DISABLED BY DEFAULT
         //ATsendCMD("AT+QGPSCFG=\"lnacontrol\",1");
@@ -438,6 +496,9 @@
         while(!haveGPSFix && runtime < timeout_seconds) {
             ThisThread::sleep_for(3000); //this goes first
             runtime = (t.read() - startseconds);
+            //TURN OFF ECHO //we need this again incase of modem brown out, as it means the modems starts echoing again
+                ATsendCMD("ATE0");
+                ATwaitForWord("OK",ATTIMEOUT_SHORT);
             ATsendCMD("AT+QGPSLOC=2");
             if (ATwaitForWord("+QGPSLOC: ",ATTIMEOUT_SHORT)) {
                 GPS_fixstage = 1;
@@ -489,6 +550,9 @@
             runtime = 0;
             while(haveCellFix == false && runtime < 20) {
                 runtime = (t.read() - startseconds);
+                //TURN OFF ECHO //we need this again incase of modem brown out, as it means the modems starts echoing again
+                    ATsendCMD("ATE0");
+                    ATwaitForWord("OK",ATTIMEOUT_SHORT);
                 ATsendCMD("AT+QENG=\"servingcell\"");
                 if (ATwaitForWord("+QENG: \"servingcell\",\"NOCONN\",",ATTIMEOUT_VERYSHORT)) {
                     if (ATgetResponse('\r',ATTIMEOUT_SHORT)) {
@@ -499,6 +563,7 @@
                         }
                     }
                 }
+                ATwaitForWord("OK",ATTIMEOUT_SHORT);
             }
                     
             //example from mulbs
--- a/modem.h	Thu May 16 12:31:44 2019 +0000
+++ b/modem.h	Thu May 23 11:39:28 2019 +0000
@@ -26,9 +26,9 @@
             //funcs
             bool registerOnNetwork(int maxAttempts, uint32_t timeout, uint32_t &BYREF_NetworkFailCount);
             char* HTTPpost(char* url, char* message, bool getResponse, int maxAttempts);
-            bool USSDsend(char* message, int maxAttempts);
+            bool USSDsend(char* message);
             char* USSDreceive(int messageIndex);
-            char* USSDmessage(char* message, bool needResponse, int maxAttempts, char* api);
+            char* USSDmessage(char* message, bool needResponse, char* api);
             char* getLocation(uint8_t accuracy, uint16_t timeout_seconds, uint32_t &BYREF_GPSFailCount, uint32_t &BYREF_NetworkFailCount); //accuracy is 1,2
             uint64_t getIMEI(void);
             uint64_t getCCID(void);
--- a/states.h	Thu May 16 12:31:44 2019 +0000
+++ b/states.h	Thu May 23 11:39:28 2019 +0000
@@ -4,5 +4,6 @@
 #define STATE_BUTTONPRESS1       81
 #define STATE_BUTTONPRESS3       82
 #define STATE_BUTTONPRESS5       83
-#define STATE_BUTTONHOLD         89
+#define STATE_TURNOFF            88
+#define STATE_TURNON             89
 #define STATE_SCORCHEDEARTH      90
\ No newline at end of file