init

Dependencies:   aconno_I2C Lis2dh12 WatchdogTimer

Revision:
51:9078e6928412
Parent:
50:a94e70c00fff
Child:
52:bd7678eade77
diff -r a94e70c00fff -r 9078e6928412 main.cpp
--- 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();