init

Dependencies:   aconno_I2C Lis2dh12 WatchdogTimer

Files at this revision

API Documentation at this revision

Comitter:
pathfindr
Date:
Wed May 29 22:59:12 2019 +0000
Parent:
51:9078e6928412
Child:
53:c6942af186d7
Commit message:
ble funcs

Changed in this revision

SI7060.cpp Show annotated file Show diff for this revision Revisions of this file
_CHANGES.md 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
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
mbed_app.json 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
--- a/SI7060.cpp	Thu May 23 11:39:28 2019 +0000
+++ b/SI7060.cpp	Wed May 29 22:59:12 2019 +0000
@@ -23,23 +23,21 @@
 };
 
 void SI7060::sleep() {
-    /*
-    writeValue(CMD_SI7060_meas,0b00000001);
-    */
+    writeValue(CMD_SI7060_meas,0x01);
 };
 
 void SI7060::prepare() {
-    /*
-    writeValue(CMD_SI7060_slTimeena,0b00000000);
-    writeValue(CMD_SI7060_meas,0b00000100);
+    uint8_t _ret;
+    _ret = readValue(CMD_SI7060_ID);
+    _ret = readValue(CMD_SI7060_meas);
+    writeValue(CMD_SI7060_meas,0x04);
+    _ret = readValue(CMD_SI7060_meas);
     writeValue(CMD_SI7060_sw_op,0x4E);
     writeValue(CMD_SI7060_sw_hyst,0x1C);
-    */
 };
 
 float SI7060::getTemperature(void) 
 {
-    /*
     prepare();
     
     float _temp;
@@ -54,8 +52,6 @@
     
     sleep();
     return _temp;
-    */
-    return 0.0;
 }
 
 SI7060::~SI7060(){};
\ No newline at end of file
--- a/_CHANGES.md	Thu May 23 11:39:28 2019 +0000
+++ b/_CHANGES.md	Wed May 29 22:59:12 2019 +0000
@@ -2,3 +2,4 @@
 
 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
+Added data loggin for failed activity broadcasts
--- a/board.h	Thu May 23 11:39:28 2019 +0000
+++ b/board.h	Wed May 29 22:59:12 2019 +0000
@@ -37,5 +37,5 @@
 //#define BD_PAGE_ADDRESS 0x5d000 //380928
 
 #define USERDATA_START          0x7E000 // - 8k for user data
-//#define APPDATA_START           0x40000 // - 4k for app data - DEVELOPMENT
-#define APPDATA_START           0x3D000 // - 4k for app data - PRODUCTION
\ 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/main.cpp	Thu May 23 11:39:28 2019 +0000
+++ b/main.cpp	Wed May 29 22:59:12 2019 +0000
@@ -6,109 +6,143 @@
 • 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(bool failsafe);
+#if BLE_ENABLED
+    void bleShutdown();
+#endif
 
 //------------------------------------------------------------------------------
 // GLOBALS
 //------------------------------------------------------------------------------
-bool             GLOBAL_debugLED                     = false;
-char*            GLOBAL_defaultApi                   = "b:gps2";
-bool             GLOBAL_accel_healthy                = false;
-bool             GLOBAL_motionStopFlagTriggered      = false;
-bool             GLOBAL_needToConfigureLis3dh        = false;
-bool             GLOBAL_registeredOnNetwork          = false;
-bool             GLOBAL_modemOn                      = false;
-bool             GLOBAL_LEDSequenceinProgress        = false;
-time_t           GLOBAL_wakeTime                     = 0;
+char*            GLOBAL_defaultApi                                  = "b:gps2";
+bool             GLOBAL_accel_healthy                               = false;
+bool             GLOBAL_motionStopFlagTriggered                     = false;
+bool             GLOBAL_needToConfigureLis3dh                       = false;
+bool             GLOBAL_registeredOnNetwork                         = false;
+bool             GLOBAL_modemOn                                     = false;
+bool             GLOBAL_LEDSequenceinProgress                       = false;
+time_t           GLOBAL_wakeTime                                    = 0;
 char             GLOBAL_exceptionString[30];
-char             GLOBAL_debug_buffer[200];
+char             GLOBAL_debug_buffer[DEBUG_BUFFERSIZE];
 char             GLOBAL_failed_broadcasts[10][160];
 bool             GLOBAL_failed_broadcast_slots[10];
+char             GLOBAL_GPSlocString_prev[70];
+bool             GLOBAL_have_GPSlocString_prev                      = false;
 
 //SETTINGS
-int              RET_setting_firmware;
-uint32_t         RET_setting_minimumupdate_hrs;
-uint8_t          RET_setting_location_mode;
-uint8_t          RET_setting_location_accuracy;
-uint32_t         RET_setting_location_tx_interval_mins;
-uint32_t         RET_setting_location_tx_failsafe_hrs;
-uint16_t         RET_setting_location_timeout;
-uint32_t         RET_setting_activity_tx_interval_hrs;
-uint8_t          RET_setting_activity_mode;
-uint32_t         RET_setting_environmental_tx_interval_mins;
-uint16_t         RET_setting_motion_g;
-time_t           RET_setting_motion_start_seconds;
-time_t           RET_setting_motion_stop_seconds;
-uint16_t         RET_setting_impact_g;
-uint8_t          RET_setting_impact_alert;
-uint16_t         RET_setting_connection_timeout;
-uint16_t         RET_setting_beacon_interval_seconds;
-uint16_t         RET_setting_beacon_scan;
+int              RET_setting_firmware                               = 0;
+uint32_t         RET_setting_minimumupdate_hrs                      = 0;
+uint8_t          RET_setting_location_mode                          = DEFAULT_LOCATION_MODE;
+uint8_t          RET_setting_location_accuracy                      = DEFAULT_LOCATION_ACCURACY;
+uint32_t         RET_setting_location_tx_interval_mins              = DEFAULT_LOCATION_TX_INTERVAL_MINS;
+uint32_t         RET_setting_location_tx_failsafe_hrs               = DEFAULT_LOCATION_TX_FAILSAFE_HRS;
+uint16_t         RET_setting_location_timeout                       = DEFAULT_LOCATION_TIMEOUT;
+uint32_t         RET_setting_activity_tx_interval_hrs               = 0;
+uint8_t          RET_setting_activity_mode                          = 1;
+uint32_t         RET_setting_environmental_tx_interval_mins         = 0;
+uint16_t         RET_setting_motion_g                               = DEFAULT_MOTION_G;
+time_t           RET_setting_motion_start_seconds                   = DEFAULT_MOTION_START_SECONDS;
+time_t           RET_setting_motion_stop_seconds                    = DEFAULT_MOTION_STOP_SECONDS;
+uint16_t         RET_setting_impact_g                               = 0;
+uint8_t          RET_setting_impact_alert                           = 0;
+uint16_t         RET_setting_connection_timeout                     = DEFAULT_CONNECTION_TIMEOUT;
+uint16_t         RET_setting_beacon_interval_seconds                = 0;
+uint8_t          RET_setting_beacon_scan                            = 0;
 //STATE
 char             RET_pf_identifier[7];
-uint8_t          RET_coldBoot = 1;
-bool             RET_asleep = false;
-bool             RET_busy = false;
-time_t           RET_RTCunixtime;
-bool             RET_haveSettings;
-uint8_t          RET_state;
-uint8_t          RET_state_prev;
-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;
-bool             RET_setupInProgress;
-bool             RET_force2G;
-bool             RET_watchdogfired;
-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
+uint8_t          RET_coldBoot                                       = 1;
+bool             RET_asleep                                         = false;
+bool             RET_busy                                           = false;
+time_t           RET_RTCunixtime                                    = 0;
+bool             RET_haveSettings                                   = false;
+uint8_t          RET_state                                          = STATE_SETUP;
+uint8_t          RET_state_prev                                     = RET_state;
+uint8_t          RET_buttonPressCount                               = 0;
+time_t           RET_buttonPressTime                                = 0;
+time_t           RET_buttonReleaseTime                              = 0;
+time_t           RET_buttonReleaseTime_prev                         = 0;
+time_t           RET_buttonHoldTime                                 = 0;
+time_t           RET_SetupRunAt                                     = 0;
+time_t           RET_SettingsGotAt                                  = 0;
+bool             RET_setupInProgress                                = false;
+bool             RET_force2G                                        = DEFAULT_FORCE2G;
+bool             RET_watchdogfired                                  = false;
+bool             RET_receivedNewSettings                            = false;
+uint32_t         RET_GPSFailCount                                   = 0;
+uint32_t         RET_NetworkFailCount                               = 0;
+bool             RET_debug                                          = true;
+time_t           RET_debug_offat                                    = 0;
+float            RET_voltage                                        = 0.0;
+float            RET_temperature                                    = 0.0;
+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
+uint32_t         RET_modemBrownOutCountInSession                    = 0;
 //MOTION STATE
-bool             RET_motionTriggeredinFrame;
-bool             RET_motionTriggeredInLocTXInterval;
-time_t           RET_motionStartTime;
-time_t           RET_motionStopTime;
-bool             RET_motionPendingOnState;
-bool             RET_motionPendingOffState;
-bool             RET_motionState;
-float            RET_motionTotalActivityHours;
-float            RET_motionTotalActivityHoursSincePost;
-time_t           RET_motionFrameStart;
+bool             RET_motionTriggeredinFrame                         = false;
+bool             RET_motionStateOnInLocTXInterval                   = false;
+time_t           RET_motionStartTime                                = 0;
+time_t           RET_motionStopTime                                 = 0;
+bool             RET_motionPendingOnState                           = false;
+bool             RET_motionPendingOffState                          = false;
+bool             RET_motionState                                    = false;
+float            RET_motionTotalActivityHours                       = 0.0f;
+float            RET_motionTotalActivityHoursSincePost              = 0.0f;
+time_t           RET_motionFrameStart                               = 0;
 char             RET_activityData[ACTIVITY_BUFFERSIZE];
 //IMPACT
-bool             RET_impactTriggered;
+bool             RET_impactTriggered                                = 0;
 //EVENTS LOGGING
-time_t           RET_eventTime_location_log;
-time_t           RET_eventTime_environmental_log;
+time_t           RET_eventTime_location_log                         = 0;
+time_t           RET_eventTime_environmental_log                    = 0;
 //EVENTS TX
-time_t           RET_eventTime_location_tx;
-time_t           RET_eventTime_location_failsafe_tx;
-time_t           RET_eventTime_environmental_tx;
-time_t           RET_eventTime_activity_tx;
-time_t           RET_eventTime_wakeFromDormant;
-
+time_t           RET_eventTime_location_tx                          = 0;
+time_t           RET_eventTime_location_failsafe_tx                 = 0;
+time_t           RET_eventTime_environmental_tx                     = 0;
+time_t           RET_eventTime_activity_tx                          = 0;
+time_t           RET_eventTime_wakeFromDormant                      = 0;
+//BLE
+#if BLE_ENABLED
+    bool             RET_bleBroadcasting                                = false;
+    uint8_t          RET_bleAdv_flags                                   = 0;
+    char             RET_closestLocationTag_id[17];
+    int              RET_closestLocationTag_rssi                        = 999;
+    bool             RET_locationTag_present                            = false;
+    bool             RET_detector_present                               = false;
+    const uint8_t    bleAdv_motionTriggeredinFrame_flag                 = 0b01000000;
+    const uint8_t    bleAdv_motionState_flag                            = 0b00100000;
+    const uint8_t    bleAdv_impact_flag                                 = 0b00010000;
+    #pragma pack(1)
+    struct bleData_t {
+        uint16_t applicationSpecificId;
+        uint8_t firmware;
+        uint8_t flags;
+        uint16_t voltage;
+        uint8_t buttonpresses;
+        int16_t temperature;
+        uint8_t humidity;
+        uint8_t lux;
+        int8_t accel_x;
+        int8_t accel_y;
+        int8_t accel_z;
+        /*char id_1; //cant use this and local name as it pushes us over size limit
+        char id_2;
+        char id_3;
+        char id_4;
+        char id_5;
+        char id_6;*/
+    };
+    #pragma pack()
+#endif
 //------------------------------------------------------------------------------
 //GPIO
 //------------------------------------------------------------------------------ 
@@ -117,22 +151,27 @@
 //------------------------------------------------------------------------------
 //PERIPHERALS
 //------------------------------------------------------------------------------ 
-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);
+#if BLE_ENABLED 
+    BLE myble;
+#endif
+WatchdogTimer watchdog;
 LIS3DH lis3dh(PN_SPI_MOSI, PN_SPI_MISO, PN_SPI_CS0, PN_SPI_CLK);
+SI7060 si7060(PN_I2C_SDA, PN_I2C_SCL);
 Modem modem(PN_GSM_PWR_KEY, PN_VREG_EN, PN_GSM_WAKE_DISABLE);
 LowPowerTicker RTCticker;
 LowPowerTimer LPtimer;
 
 //------------------------------------------------------------------------------
-//THREAD SEMAPHORES
+//SEMAPHORES
 //------------------------------------------------------------------------------ 
 Semaphore mainthread;
 
 //------------------------------------------------------------------------------
 // LOW LEVEL FUNCS
 //------------------------------------------------------------------------------
+void watchdogKick() {
+    watchdog.kick();
+}
 void set_8bit_flag(uint8_t& flags, uint8_t flag) {
     flags |= flag;
 }
@@ -152,20 +191,16 @@
     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;
-    //NRF_TWI0->ENABLE=1;//TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
+    NRF_TWI0->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
     *(volatile uint32_t *)0x40003FFC = 0;
     *(volatile uint32_t *)0x40003FFC;
     *(volatile uint32_t *)0x40003FFC = 1;
     //TWI1
-    //NRF_TWI1->ENABLE=TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
+    NRF_TWI1->ENABLE=TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
     *(volatile uint32_t *)0x40004FFC = 0;
     *(volatile uint32_t *)0x40004FFC;
     *(volatile uint32_t *)0x40004FFC = 1;
-    */
 }
 void setState(uint8_t state) {
     RET_state_prev = RET_state;
@@ -197,6 +232,9 @@
     }
 }
 void recordFirmwareAsValid() {
+    #if BLE_ENABLED
+        bleShutdown();
+    #endif
     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;
@@ -237,54 +275,22 @@
     }
     RET_voltage = (voltage_accumulator / (float)readings);
 }
-float nrfTemperature() {
-    float temperature = 0.0;
-    
-    //INTERNAL NRF52 TEMP SENSOR
-    uint32_t safetycounter = 0;
-    NRF_TEMP->TASKS_START=1;
-    while (NRF_TEMP->EVENTS_DATARDY==0 && safetycounter < 10000) {
-        safetycounter ++;
-    };
-    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;
-}
+//------------------------------------------------------------------------------
+// TEMPERATURE
+//------------------------------------------------------------------------------ 
 float getTemperature() {
-    float temperature;
-    if (USE_NRF_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
-    }
-    return temperature;  
+    return si7060.getTemperature();
 }
 void updateTemperatures() {
-    //RET_temperature = getTemperature(); //not smoothed
-    if (RET_temperature == 0.0f) {RET_temperature = getTemperature();}
+    if (RET_temperature == 0.0) {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_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);
+        snprintf(GLOBAL_exceptionString+strlen(GLOBAL_exceptionString),sizeof(GLOBAL_exceptionString),".%s",value);
     }
 }
 void resetTemperatures() {
@@ -305,7 +311,7 @@
         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_debug_offat = (RET_RTCunixtime + 3600); //debug on for 1hr
     }
     RET_buttonReleaseTime_prev = RET_buttonReleaseTime;
 }
@@ -365,11 +371,22 @@
             RET_buttonPressCount = 0;
         }
     }
+    
+    if(RET_debug && GLOBAL_LEDSequenceinProgress == false){
+        if (RET_motionState) {
+            led1 = 0;   
+        } else {
+            led1 = 1;   
+        }
+    }
 }
-
-void resetGlobals() {
+//------------------------------------------------------------------------------
+// GLOBALS
+//------------------------------------------------------------------------------ 
+void resetSessionVars() {
     GLOBAL_accel_healthy = false;
-    GLOBAL_motionStopFlagTriggered = false;
+    RET_motionTriggeredinFrame = false;
+    RET_modemBrownOutCountInSession = 0;
     memset(GLOBAL_exceptionString,0x00,sizeof(GLOBAL_exceptionString));
 }
 void healthCheck() {
@@ -404,69 +421,6 @@
         setState(STATE_SETUP);
     }
 }
-void setDefaults() {
-    //STATE
-    RET_asleep = false;
-    RET_busy = false;
-    RET_haveSettings = false;
-    RET_state = STATE_SETUP;
-    RET_state_prev = RET_state;
-    RET_RTCunixtime = 0;
-    RET_SetupRunAt = 0;
-    RET_SettingsGotAt = 0;
-    RET_force2G = DEFAULT_FORCE2G;
-    RET_watchdogfired = false;
-    RET_setupInProgress = false;
-    RET_receivedNewSettings = false;
-    RET_GPSFailCount = 0;
-    RET_NetworkFailCount = 0;
-    //SETTINGS
-    RET_setting_firmware = 0;
-    RET_setting_minimumupdate_hrs = 0;
-    RET_setting_location_mode = DEFAULT_LOCATION_MODE;
-    RET_setting_location_accuracy = DEFAULT_LOCATION_ACCURACY;
-    RET_setting_location_tx_interval_mins = DEFAULT_LOCATION_TX_INTERVAL_MINS;
-    RET_setting_location_tx_failsafe_hrs = DEFAULT_LOCATION_TX_FAILSAFE_HRS;
-    RET_setting_location_timeout = DEFAULT_LOCATION_TIMEOUT;
-    RET_setting_activity_tx_interval_hrs = 0;
-    RET_setting_activity_mode = 1;
-    RET_setting_environmental_tx_interval_mins = 0;
-    RET_setting_motion_g = DEFAULT_MOTION_G;
-    RET_setting_motion_start_seconds = DEFAULT_MOTION_START_SECONDS;
-    RET_setting_motion_stop_seconds = DEFAULT_MOTION_STOP_SECONDS;
-    RET_setting_impact_g = 0;
-    RET_setting_impact_alert = 0;
-    RET_setting_connection_timeout = DEFAULT_CONNECTION_TIMEOUT;
-    RET_setting_beacon_scan = 0;
-    RET_buttonPressCount = 0;
-    RET_buttonPressTime = 0;
-    RET_buttonReleaseTime = 0;
-    RET_buttonHoldTime = 0;
-    //MOTION STATE
-    RET_motionTriggeredinFrame = false;
-    RET_motionTriggeredInLocTXInterval = false;
-    RET_motionStartTime = 0;
-    RET_motionStopTime = 0;
-    RET_motionPendingOnState = 0;
-    RET_motionPendingOffState = 0;
-    RET_motionState = 0;
-    RET_motionTotalActivityHours = 0.0;
-    RET_motionTotalActivityHoursSincePost = 0.0;
-    RET_motionFrameStart = 0;
-    memset(RET_activityData,0x00,sizeof(RET_activityData));
-    //IMPACT
-    RET_impactTriggered = 0;
-    //EVENT HANDLING
-    RET_eventTime_location_log = 0;
-    RET_eventTime_location_tx = 0;
-    RET_eventTime_location_failsafe_tx = 0;
-    RET_eventTime_environmental_log = 0;
-    RET_eventTime_environmental_tx = 0;
-    RET_eventTime_activity_tx = 0;
-    RET_eventTime_wakeFromDormant = 0;
-    //PERIPHERAL RESET
-    lis3dh_configureForSleep(DEFAULT_MOTION_G,DEFAULT_IMPACT_G);
-}
 
 bool selfTest() {
     int test_count = 0;
@@ -481,17 +435,224 @@
         test_pass ++;
     } else {
         GLOBAL_accel_healthy = false;
-        addToExceptionString("A");   
+        addToExceptionString("AF");   
     }
     
     //Result
     if (test_count == test_pass) {
         return true;
     } else {
-        addToExceptionString("HF"); 
+        //addToExceptionString("HF"); 
         return false;   
     }
 }
+//------------------------------------------------------------------------------
+// BLE FUNCS
+//------------------------------------------------------------------------------
+#if BLE_ENABLED
+void bleBuildData(bleData_t &bleData)
+{
+    bleData.applicationSpecificId = BLE_SERVICEID_GPSPLUS;
+    bleData.firmware = FW_VERSION;
+    //set flags
+    if (RET_motionTriggeredinFrame) {
+        set_8bit_flag(RET_bleAdv_flags, bleAdv_motionTriggeredinFrame_flag);
+    } else {
+        clr_8bit_flag(RET_bleAdv_flags, bleAdv_motionTriggeredinFrame_flag);
+    }
+    if (RET_motionState) {
+        set_8bit_flag(RET_bleAdv_flags, bleAdv_motionState_flag);
+    } else {
+        clr_8bit_flag(RET_bleAdv_flags, bleAdv_motionState_flag);
+    }
+    clr_8bit_flag(RET_bleAdv_flags, bleAdv_impact_flag);
+    bleData.flags = RET_bleAdv_flags;
+    bleData.voltage = uint16_t(RET_voltage * 100);
+    bleData.temperature = uint16_t(getTemperature() * 10);
+    bleData.humidity = 0xFF;
+    bleData.lux = 0xFF;
+    bleData.accel_x = 0xFF;
+    bleData.accel_y = 0xFF;
+    bleData.accel_z = 0xFF;
+    /*
+    bleData.id_1 = RET_pf_identifier[0]; //dont use this just stick it in the local name
+    bleData.id_2 = RET_pf_identifier[1];
+    bleData.id_3 = RET_pf_identifier[2];
+    bleData.id_4 = RET_pf_identifier[3];
+    bleData.id_5 = RET_pf_identifier[4];
+    bleData.id_6 = RET_pf_identifier[5];
+    */
+}
+void bleUpdateAndAdvertise(void)
+{
+    int AdvertisingInterval = (RET_setting_beacon_interval_seconds * 1000);
+    bleData_t bleData;
+    bleBuildData(bleData);
+    myble.gap().stopAdvertising();
+    myble.gap().setTxPower(DEFAULT_BEACON_POWER); // set tx power,valid values are -40, -20, -16, -12, -8, -4, 0, 4
+    myble.gap().accumulateAdvertisingPayloadTxPower(DEFAULT_BEACON_POWER); // (accepted values are -40, -30, -20, -16, -12, -8, -4, 0, and 4 dBm)
+    myble.gap().setAdvertisingInterval(AdvertisingInterval);
+    myble.gap().updateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, (uint8_t *)&bleData, sizeof(bleData_t));
+    //myble.gap().updateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t *)&bleData, sizeof(bleData_t));
+    myble.gap().startAdvertising();
+    RET_bleBroadcasting = true;
+    if(RET_debug) {debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "BLE Adv Start");debug_exe();}
+}
+void bleSetupAdvertising(BLE::InitializationCompleteCallbackContext *params)
+{
+    if (RET_pf_identifier[0] != 0x00 && RET_pf_identifier[1] != 0x00 && RET_pf_identifier[2] != 0x00) {
+        bleData_t bleData;
+        bleBuildData(bleData);
+        char localname[6];
+        memcpy(localname,RET_pf_identifier,6);
+        myble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE );
+        myble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)localname, sizeof(localname));
+        myble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, (uint8_t *)&bleData, sizeof(bleData_t));
+        //myble.gap().accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t *)&bleData, sizeof(bleData_t));
+        myble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
+        if(RET_debug) {debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "BLE Setup...");debug_exe();}  
+    }
+}
+void bleStopAdvertising(void)
+{
+    myble.gap().stopAdvertising();
+    RET_bleBroadcasting = false;
+    if(RET_debug) {debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "BLE Adv Stop");debug_exe();}
+}
+void bleAdvertisementCallback(const Gap::AdvertisementCallbackParams_t *params) {
+    struct AdvertisingData_t {
+        uint8_t                        length;
+        GapAdvertisingData::DataType_t dataType;
+        uint8_t                        data[0];
+    } PACKED;
+    struct bleData_t {
+        uint16_t applicationSpecificId;
+    } PACKED;
+    
+    //LOOKING FOR (SIAEC BETA)
+    //14f64b977c250854
+    //442ce31996801546
+    
+    char beta_location_tag_0[17] = {'4','1','1','7','6','9','0','5','6','4','6','8','3','f','6','8',0x00}; //bens
+    char beta_location_tag_1[17] = {'1','4','f','6','4','b','9','7','7','c','2','5','0','8','5','4',0x00}; //singapore
+    char beta_location_tag_2[17] = {'4','4','2','c','e','3','1','9','9','6','8','0','1','5','4','6',0x00}; //singapore
+    
+    //Portal demos
+    char beta_location_tag_3[17] = {'1','5','f','c','6','d','d','5','c','3','7','f','1','f','4','a',0x00};
+    char beta_location_tag_4[17] = {'b','a','a','e','c','d','6','8','b','d','7','e','e','a','6','5',0x00};
+    char beta_location_tag_5[17] = {'7','e','4','b','7','8','e','0','f','a','3','3','0','8','a','0',0x00};
+    char beta_location_tag_6[17] = {'e','1','1','3','c','d','e','a','a','e','f','f','1','4','d','9',0x00};
+    char beta_location_tag_7[17] = {'8','c','9','2','4','5','f','f','0','c','f','a','b','9','2','f',0x00};
+    char beta_location_tag_8[17] = {'0','7','e','9','9','1','d','3','b','e','b','6','4','0','4','8',0x00};
+    char beta_location_tag_9[17] = {'9','5','6','3','a','0','8','6','2','1','e','8','e','c','1','4',0x00};
+    
+    //Search for the manufacturer specific data with matching application-ID
+    AdvertisingData_t *pAdvData;
+    for (size_t index = 0; index < params->advertisingDataLen; index += (pAdvData->length + 1)) {
+        pAdvData = (AdvertisingData_t *)&params->advertisingData[index];
+        const bleData_t *pbleData = (const bleData_t *)pAdvData->data;
+        
+        //ESTIMOTE BEACON
+        //example data 020104 0303 9afe1716 9afe 22 02c887042a33f9f0 00efebc60146f8ffffffff    //spaces just to show identifier
+        
+        //BLE TYPE SWITCH
+        switch(pbleData->applicationSpecificId) {
+            case BLE_SERVICEID_PFBEACON1 :
+            {
+                char beacon_identifier[17];
+                snprintf(beacon_identifier, sizeof(beacon_identifier), "%02x%02x%02x%02x%02x%02x%02x%02x",
+                params->advertisingData[12],
+                params->advertisingData[13],
+                params->advertisingData[14],
+                params->advertisingData[15],
+                params->advertisingData[16],
+                params->advertisingData[17],
+                params->advertisingData[18],
+                params->advertisingData[19]);
+                //if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), " Mac: [%02x%02x%02x%02x%02x%02x], rssi: %d, AType: %u, S: %04x, Id: %s",params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],params->rssi, params->type, pbleData->applicationSpecificId, beacon_identifier);debug_exe();}
+                //check to see if its one of the two location beta beacons we are looking for...
+                if (strcmp(beacon_identifier, beta_location_tag_0) == 0 
+                    || strcmp(beacon_identifier, beta_location_tag_1) == 0 
+                    || strcmp(beacon_identifier, beta_location_tag_2) == 0
+                    || strcmp(beacon_identifier, beta_location_tag_3) == 0
+                    || strcmp(beacon_identifier, beta_location_tag_4) == 0
+                    || strcmp(beacon_identifier, beta_location_tag_5) == 0
+                    || strcmp(beacon_identifier, beta_location_tag_6) == 0
+                    || strcmp(beacon_identifier, beta_location_tag_7) == 0
+                    || strcmp(beacon_identifier, beta_location_tag_8) == 0
+                    || strcmp(beacon_identifier, beta_location_tag_9) == 0
+                    ) {
+                    //dump advertising data
+                    //for (unsigned index = 0; index < params->advertisingDataLen; index++) { if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "%02x",params->advertisingData[index]);debug_exe(false);}}
+                    //if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), " MATCH");debug_exe();}
+                    int tag_rssi = params->rssi * -1; //to convert to positive number
+                    if (tag_rssi < RET_closestLocationTag_rssi) {
+                         RET_closestLocationTag_rssi = tag_rssi;
+                         memcpy(RET_closestLocationTag_id, beacon_identifier, sizeof(RET_closestLocationTag_id));
+                         RET_locationTag_present = true;
+                         //if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "Location Tag Present: %s, rssi: %d",closestLocationTag_id, closestLocationTag_rssi);debug_exe();}
+                    }
+                }
+                break;
+            }
+            case BLE_SERVICEID_BT04 :
+            {  
+                //nothing yet
+                break;
+            }
+            case BLE_SERVICEID_PFDETECTOR1 :
+            {
+                char ble_advdata[100];
+                snprintf(ble_advdata, sizeof(ble_advdata), "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+                params->advertisingData[0],
+                params->advertisingData[1],
+                params->advertisingData[2],
+                params->advertisingData[3],
+                params->advertisingData[4],
+                params->advertisingData[5],
+                params->advertisingData[6],
+                params->advertisingData[7],
+                params->advertisingData[8],
+                params->advertisingData[9],
+                params->advertisingData[10],
+                params->advertisingData[11],
+                params->advertisingData[12],
+                params->advertisingData[13],
+                params->advertisingData[14],
+                params->advertisingData[15],
+                params->advertisingData[16],
+                params->advertisingData[17],
+                params->advertisingData[18],
+                params->advertisingData[19],
+                params->advertisingData[20]);
+                //if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), " Mac: [%02x%02x%02x%02x%02x%02x], rssi: %d, AType: %u, Id: %s",params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],params->rssi, pAdvData->dataType, ble_advdata);debug_exe();}
+                //if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "Detector @rssi: %d",params->rssi);debug_exe();}
+                if (params->rssi >= -75) {
+                    RET_detector_present = true;
+                }
+                break;
+            }
+        }
+    }
+}
+void bleConfigureScan(void)
+{
+    //configure scan
+    //myble.gap().setScanParams(60,30); //scan interval //scan window
+    myble.gap().setScanParams(100,100); //scan interval //scan window
+    myble.gap().startScan(bleAdvertisementCallback);
+}
+void bleStopScan(void)
+{
+    myble.gap().stopScan();
+}
+void bleShutdown(void)
+{
+    bleStopScan();
+    bleStopAdvertising();
+    myble.shutdown();
+}
+#endif
 
 //------------------------------------------------------------------------------
 // MOTION FUNCS
@@ -501,6 +662,9 @@
         if (lis3dh_int2) {
             RET_motionTriggeredinFrame = true;
             GLOBAL_needToConfigureLis3dh = true; //interrupt has fire so need to clear it
+            if(RET_debug) {
+                LED1on(100);
+            }
             if (!RET_motionPendingOnState) {
                 RET_motionPendingOnState = true;
                 RET_motionPendingOffState = false;
@@ -521,29 +685,35 @@
         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) {
+            if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "M:%u",inMotionForSeconds);debug_exe();}
+            if (inMotionForSeconds >= RET_setting_motion_start_seconds) {
+                //if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "MotionOn");debug_exe();}
                 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);
+                RET_motionStateOnInLocTXInterval = true;
+                if (RET_motionState == false) { //If this is first after motionState 0
+                    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(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(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "NM:%u",noMotionForSeconds);debug_exe();}
+            if (noMotionForSeconds >= RET_setting_motion_stop_seconds) {
+                if (RET_motionState == true) {
+                    RET_motionPendingOffState = false;
+                    RET_motionState = false;
+                    GLOBAL_motionStopFlagTriggered = true;
+                    //if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "MotionStop");debug_exe();}
+                    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);
+                        }
                     }
                 }
             }
@@ -595,7 +765,7 @@
         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);}
         if(TEMP_e != -1) { RET_setting_location_mode = TEMP_e;                          }
-            if(RET_setting_location_mode > 3) {RET_setting_location_mode = DEFAULT_LOCATION_MODE;}
+            if(RET_setting_location_mode > 4) {RET_setting_location_mode = DEFAULT_LOCATION_MODE;}
         if(TEMP_f != -1) { RET_setting_location_accuracy = TEMP_f;                      }
             if(RET_setting_location_accuracy > 3) {RET_setting_location_accuracy = DEFAULT_LOCATION_ACCURACY;}
         if(TEMP_g != -1) { RET_setting_location_tx_interval_mins = TEMP_g;              }
@@ -630,6 +800,9 @@
                 //Broadcast any activity data we have before fw update
                 event_activity_tx();
                 //prep for FW update
+                #if BLE_ENABLED
+                    bleShutdown();
+                #endif
                 read_app_data_from_flash(&app_data);
                 clr_flag(&app_data, app_execution_flag);
                 clr_flag(&app_data, first_run_flag);
@@ -691,7 +864,7 @@
     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,RET_voltage,timetaken,error,GLOBAL_exceptionString);
+    snprintf(bytestosend,sizeof(bytestosend),"(%s,a:log,f:%d,v:%.2f,e:%d,z:%s.%s,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, GLOBAL_defaultApi);
@@ -722,6 +895,9 @@
     return;
 }
 void failed_broadcasts_tx() {
+    #if BLE_ENABLED
+        bleStopAdvertising();
+    #endif
     //check we have something to send...
     int numbertosend = 0;
     for(int i = 0; i < sizeof(GLOBAL_failed_broadcast_slots); i++) {
@@ -751,6 +927,9 @@
     }
 }
 bool event_setup(bool manualrun) {
+    #if BLE_ENABLED
+        bleStopAdvertising();
+    #endif
     bool pass = false;
     LED1on(0);
     if (RET_NetworkFailCount > DEFAULT_MAX_FAILED_CONNECTIONS) addToExceptionString("NF");
@@ -767,7 +946,7 @@
             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,RET_voltage,RET_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,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, GLOBAL_defaultApi));
             RET_setupInProgress = false; //this turns off the flashing led
@@ -796,10 +975,10 @@
     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
+        //uint8_t previous_location_accuracy = RET_setting_location_accuracy;
+        //RET_setting_location_accuracy = 1; //set location mode to CL only
         event_location_tx(false);
-        RET_setting_location_accuracy = previous_location_accuracy; //set location mode back to previous
+        //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
@@ -809,10 +988,14 @@
     RET_SetupRunAt = RET_RTCunixtime;
     RET_GPSFailCount = 0;
     RET_NetworkFailCount = 0;
+    setEventTimes();
     //RESULT
     return pass;
 }
 void event_turnonofflog_tx(bool turnon) {
+    #if BLE_ENABLED
+        bleStopAdvertising();
+    #endif
     RET_NetworkFailCount = 0; //reset network blocker
     RET_GPSFailCount = 0;
     updateBatteryV();
@@ -827,9 +1010,9 @@
             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,RET_temperature,RET_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,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,RET_temperature,RET_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,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, GLOBAL_defaultApi));
@@ -837,57 +1020,111 @@
     }
 }
 void event_location_tx(bool failsafe) {
+    #if BLE_ENABLED
+        bleStopAdvertising();
+    #endif
     //check if we have any outstanding to send
     failed_broadcasts_tx();
     bool selfTestResult = selfTest();
+    bool skipTX = false;
     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");
-    //lets check to see if we've had repeated comms failings in this location, if so dont bother trying. reset by movment and timeout
-    if (RET_NetworkFailCount <= DEFAULT_MAX_FAILED_CONNECTIONS) {
-        if (RET_receivedNewSettings) {RET_receivedNewSettings = false; addToExceptionString("SR"); }
-        if (modem.on(RET_force2G)) {
-            char locString[70];
-            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)) {
-                int timetaken_total = (RET_RTCunixtime - GLOBAL_wakeTime) + 10; //add 10 for avg ussd response time.
-                int timetaken_connection = (RET_RTCunixtime - connectionStartTime);
-                //Check if we should wait for settings back
-                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
-                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, 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
+    
+    //Check for Nearby Location Beacons
+    #if BLE_ENABLED
+        memset(RET_closestLocationTag_id, 0x00, sizeof(RET_closestLocationTag_id));
+        RET_closestLocationTag_rssi = 999;
+        RET_locationTag_present = false;
+        RET_detector_present = false;
+        if (RET_setting_beacon_scan == 1 && RET_setting_location_mode != LOCATION_MODE_REALTIME) {
+            LowPowerTimer bleScan_t;
+            bleScan_t.start();
+            uint32_t bleScan_startmillis = bleScan_t.read_ms(); uint32_t bleScan_runtime = 0;
+            if (!myble.hasInitialized()) {
+                myble.init();
+                while (!myble.hasInitialized() && bleScan_runtime < 1000) { 
+                    bleScan_runtime = (bleScan_t.read_ms() - bleScan_startmillis);
+                }
+            }
+            if (myble.hasInitialized()) {
+                //Scan for 10 seconds
+                bleConfigureScan();
+                bleScan_startmillis = bleScan_t.read_ms();
+                while (bleScan_runtime < 10000 && RET_detector_present == false) {
+                    bleScan_runtime = (bleScan_t.read_ms() - bleScan_startmillis);
+                    myble.waitForEvent(); // low power wait for event
+                }
+                //if (LocationTag_preset) if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "LocationTag: %s, rssi: %d",closestLocationTag_id, closestLocationTag_rssi);debug_exe();}
+            }
+            bleScan_t.stop();
+            myble.gap().stopScan();
+        }
+        //see if we are in range of ble detector, if so, no need to get gps and broadcast
+        if (RET_detector_present == true && RET_setting_beacon_interval_seconds > 0) {
+            skipTX = true;
+        }
+    #endif
+    
+    
+    if (skipTX == false || failsafe == true) {
+        //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");
+        //lets check to see if we've had repeated comms failings in this location, if so dont bother trying. reset by movment and timeout
+        if (RET_NetworkFailCount <= DEFAULT_MAX_FAILED_CONNECTIONS) {
+            if (RET_receivedNewSettings) {RET_receivedNewSettings = false; addToExceptionString("SR"); }
+            if (modem.on(RET_force2G)) {
+                char locString[70];
+                int gpsStartTime = RET_RTCunixtime;
+                
+                //check if we have moved since last post, if not use same valid gps fix if exists
+                if (RET_motionStateOnInLocTXInterval == false && GLOBAL_have_GPSlocString_prev == true) {
+                    memcpy(locString, GLOBAL_GPSlocString_prev, sizeof(locString));
+                    addToExceptionString("P");
                 } else {
-                    if (getSettings) {
-                        if (saveSettings(result) == false){sendErrorLog("ERR-LOC-IR");}
+                    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)) {
+                    int timetaken_total = (RET_RTCunixtime - GLOBAL_wakeTime) + 10; //add 10 for avg ussd response time.
+                    int timetaken_connection = (RET_RTCunixtime - connectionStartTime);
+                    //Check if we should wait for settings back
+                    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
+                    snprintf(bytesToSend,sizeof(bytesToSend),"(%s,a:loc,f:%d,t:%.0f,n:%.0f,q:%.0f,v:%.1f,z:L%s,e:%d,y:%d,x:%d,j:%d,s:%d%s)\0",GLOBAL_defaultApi,FW_VERSION,RET_temperature,RET_temperature_min,RET_temperature_max,RET_voltage,GLOBAL_exceptionString,timetaken_total,timetaken_connection,timetaken_gps,RET_motionStateOnInLocTXInterval,getSettings,locString);
+                    //snprintf(bytesToSend,sizeof(bytesToSend),"(%s,a:loc,f:%d,t:%.0f,v:%.1f,z:L-%s,e:%d,y:%d,x:%d,j:%d,s:%d%s)\0",GLOBAL_defaultApi,FW_VERSION,RET_temperature,RET_voltage,GLOBAL_exceptionString,timetaken_total,timetaken_connection,timetaken_gps,RET_motionStateOnInLocTXInterval,getSettings,locString);
+                    char result[180];
+                    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");}
+                        }
                     }
                 }
             }
         }
     }
     //RESETS
-    RET_motionTriggeredInLocTXInterval = false;
+    RET_motionStateOnInLocTXInterval = false;
     setEventTime_Location();
 }
 void event_activity_tx() {
+    #if BLE_ENABLED
+        bleStopAdvertising();
+    #endif
     //check if we have any outstanding to send
     failed_broadcasts_tx();
     //check we have something to send...
@@ -896,9 +1133,9 @@
         //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);
+            snprintf(bytesToSend,sizeof(bytesToSend),"(%s,a:act,t:%u,r:%.2f,h:%.2f)\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);
+            snprintf(bytesToSend,sizeof(bytesToSend),"(%s,a:act,e:%s,t:%u,r:%.2f)\0",GLOBAL_defaultApi,RET_activityData,RET_motionFrameStart,RET_motionTotalActivityHoursSincePost);
         }
         if (RET_NetworkFailCount <= DEFAULT_MAX_FAILED_CONNECTIONS) {
             if (modem.on(RET_force2G)) {
@@ -937,48 +1174,6 @@
     memset(RET_activityData,0x00,sizeof(RET_activityData));
     setEventTime_Activity();
 }
-/*
-void event_activity_tx() {
-    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) {
-        //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;}
-                    }
-                }
-            }
-            modem.off(true);
-        }
-        //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
@@ -1018,27 +1213,27 @@
                     break;
                 case 2: //INTERVAL POST WITH MOTION CHECK
                     if(RET_RTCunixtime >= RET_eventTime_location_tx && RET_eventTime_location_tx > 0) { 
-                        if (RET_motionTriggeredInLocTXInterval == true) {
+                        if (RET_motionStateOnInLocTXInterval == true || RET_motionState == true) {
                             run_location_tx = true;
                         } else {
-                             if(RET_debug){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;
                 case 3: //POST ON STOP MOTION
-                    if (GLOBAL_motionStopFlagTriggered) { run_location_tx = true; GLOBAL_motionStopFlagTriggered = false; }
+                    if (GLOBAL_motionStopFlagTriggered) { GLOBAL_motionStopFlagTriggered = false; run_location_tx = true; }
                     break;
             }
             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
+                addToExceptionString("FS");
                 updateBatteryV();
                 event_location_tx(true);
             } else {
                 if (run_location_tx) { updateBatteryV(); event_location_tx(false); }
             }
             
-            
             //ACTIVITY EVENT
             bool run_activity_tx = false;
             if(RET_RTCunixtime >= RET_eventTime_activity_tx && RET_eventTime_activity_tx > 0) {
@@ -1179,7 +1374,7 @@
     //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
+    watchdog.configure(300.0); //5 mins //Do not set to less than 4500ms or can cause issues with softdevice
     modem.off(false);
     RTCticker.attach(&RTCtick, 1.0);
     LPtimer.start();
@@ -1194,54 +1389,42 @@
         RET_coldBoot = 1;
         switch(NRF_POWER->RESETREAS) {
             case 0x00000001  :
-                //if(RET_debug){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(RET_debug){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(RET_debug){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(RET_debug){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) {
-            //THIS is a unexpected reset / brownout???
-        //}
     }
     
     //CHECK FOR FIRST BOOT
-    if (RET_coldBoot == 1) { 
-        setDefaults(); 
-        //check battery
+    if (RET_coldBoot == 1) {  
+        memset(RET_activityData,0x00,sizeof(RET_activityData));
+        lis3dh_configureForSleep(DEFAULT_MOTION_G,DEFAULT_IMPACT_G);
         updateBatteryV();
-        if (RET_voltage < 2.5f) {
-            //battery low
-            LED1errorCode(10,2);
-        }
+        if (RET_voltage < 2.5f) { LED1errorCode(10,2);}
         addToExceptionString("FR");
     }
     
     //MAIN LOOP
-    while(true) {    
-        //WATCHDOG
-        watchdogKick();
+    while(true) {
         RET_asleep = false;
+        watchdogKick();
         updateTemperatures();
-        
-        //INIT
-        resetGlobals();
+        resetSessionVars();
         healthCheck(); //this must be after resetGlobals
         GLOBAL_wakeTime = RET_RTCunixtime;
         
         //check and log motion
         if (RET_state == STATE_NORMAL || RET_state == STATE_SETUP) { 
-            if (checkMotion() == true) {
-                //if motionstate is true, then reset network and gps fail counts, so that they are not skipped
+            if (checkMotion() == true) { //if motionstate is true, then reset network and gps fail counts, so that they are not skipped
                 RET_NetworkFailCount = 0;
                 RET_GPSFailCount = 0;
             }
@@ -1250,7 +1433,7 @@
         //MAIN LOGIC
         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), "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_motionStateOnInLocTXInterval, 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",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();
@@ -1270,19 +1453,35 @@
             RET_coldBoot = 0;
         }
         
+        //CONFIGURE BLE BEACON BROADCAST
+        #if BLE_ENABLED
+            //see if we are in range of ble detector, if so, no need to get gps and broadcast
+            if (RET_setting_beacon_interval_seconds > 0 && RET_pf_identifier[0] != 0x00 && RET_pf_identifier[1] != 0x00 && RET_pf_identifier[2] != 0x00) {
+                if (RET_bleBroadcasting == false) {
+                    if(RET_debug) {debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "BLE init...");debug_exe();}
+                    myble.init(bleSetupAdvertising);
+                    if (myble.hasInitialized()) {
+                        if(RET_debug) {debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "OK");debug_exe();}
+                        bleUpdateAndAdvertise();
+                    } else {
+                        if(RET_debug) {debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "FAIL");debug_exe();}
+                    }
+                } else {
+                    if(RET_debug) {debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "BLE update");debug_exe();}
+                    bleUpdateAndAdvertise();
+                }
+            } else {
+                if (RET_bleBroadcasting == true) bleStopAdvertising();
+            }
+        #endif
+        
         //PRE-SLEEP ACTIONS
         LED1off();
-        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;
+        modem.off(GLOBAL_modemOn); //HARD OR SOFT SHUT DOWN - DEPENDING ON modemOn state
         if (GLOBAL_needToConfigureLis3dh) { lis3dh_configureForSleep(RET_setting_motion_g,RET_setting_impact_g); }
         nrf_configureForSleep();
         NRFuart_uninit();
         watchdogKick();
-        
         //SLEEP
         RET_asleep = true;
         mainthread.wait(DEFAULT_SLEEP_FRAME);
--- a/main.h	Thu May 23 11:39:28 2019 +0000
+++ b/main.h	Wed May 29 22:59:12 2019 +0000
@@ -14,18 +14,19 @@
 #define MAIN_INTERFACE_H_
 
 //------------------------------------------------------------------------------
-//DEFINES
+//FW DETAILS
 //------------------------------------------------------------------------------ 
-#define FW_VERSION          20
+#define FW_VERSION          328
 //#define SKU                 "GPSPLUSDEV"
 #define SKU                 "GPSPLUS"
 #define HW_MAJORREVISION    "001"
 
-//MODES
-#define USE_NRF_TEMP_SENSOR                 1
+//OPTIONS
+#define USE_NRF_TEMP_SENSOR                 false
+#define BLE_ENABLED                         true
 
-//DEFAULT SETTINGS
-#define DEFAULT_SLEEP_FRAME                 60000
+//DEFAULT VELUES
+#define DEFAULT_SLEEP_FRAME                 30000
 #define DEFAULT_FORCE2G                     false
 #define DEFAULT_LOCATION_MODE               1
 #define DEFAULT_LOCATION_ACCURACY           1  // 0 = no location, 1 = cl only, 2 = gps then cl
@@ -40,6 +41,9 @@
 #define DEFAULT_CONNECTION_TIMEOUT          140
 #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
+#define DEFAULT_MAX_MODEMBROWNOUTS          2
+#define DEFAULT_BEACON_INTERVAL_SECONDS     10
+#define DEFAULT_BEACON_POWER                4 //(accepted values are -40, -30, -20, -16, -12, -8, -4, 0, and 4 dBm)
 
 //CONSTS
 #define ONEDAYINSECONDS                     86400
@@ -55,23 +59,23 @@
 
 //DEFINES
 #define ACTIVITY_BUFFERSIZE                 100
+#define DEBUG_BUFFERSIZE                    200
 
 //------------------------------------------------------------------------------
 //mbed Libraries
 //------------------------------------------------------------------------------
 #include "mbed.h"
 //#include "nrf_soc.h"
-#include "nrf_temp.h"
 #include "board.h"
-//#include "ble/BLE.h"
-//#include "FlashIAPBlockDevice.h"
-
+#if BLE_ENABLED 
+    #include "ble/BLE.h" 
+#endif
 //------------------------------------------------------------------------------
 //peripheral Libraries
 //------------------------------------------------------------------------------
 #include "WatchdogTimer.h"
 #include "LIS3DH.h"
-//#include "SI7060.h"
+#include "SI7060.h"
 #include "acd_nrf52_saadc.h"
 
 //------------------------------------------------------------------------------
@@ -84,6 +88,13 @@
 #include "sensors.h"
 #include "modem.h"
 
+//BLE SERVICE IDS
+#define BLE_SERVICEID_GPSPLUS               0xfb10
+#define BLE_SERVICEID_PFDETECTOR1           0x4e96
+#define BLE_SERVICEID_PFBEACON1             0xfe9a //ESTIMOTE
+#define BLE_SERVICEID_BT04                  0xcbff //TZBT04 Temp/humid
+#define BLE_SERVICEID_PFBEACON2             0xfb20
+
 //------------------------------------------------------------------------------
 //Global macros
 //------------------------------------------------------------------------------
@@ -104,7 +115,9 @@
 extern bool GLOBAL_LEDSequenceinProgress;
 extern time_t GLOBAL_RTCunixtime;
 extern time_t GLOBAL_wakeTime;
-extern char GLOBAL_debug_buffer[200];
+extern char GLOBAL_debug_buffer[DEBUG_BUFFERSIZE];
+extern char GLOBAL_GPSlocString_prev[70];
+extern bool GLOBAL_have_GPSlocString_prev;
 //FUNCS
 extern void watchdogKick();
 
--- a/mbed_app.json	Thu May 23 11:39:28 2019 +0000
+++ b/mbed_app.json	Wed May 29 22:59:12 2019 +0000
@@ -23,8 +23,6 @@
             "platform.sys-stats-enabled": false
         },
         "NRF52_DK": {
-            "target.mbed_app_start": "0x3E000",
-            "target.bootloader_img": null,
             "target.OUTPUT_EXT": "bin",
             "target.uart_hwfc": 0,
             "nordic.uart_0_fifo_size": 1024,
--- a/modem.cpp	Thu May 23 11:39:28 2019 +0000
+++ b/modem.cpp	Wed May 29 22:59:12 2019 +0000
@@ -52,6 +52,71 @@
     }
 }
 
+int Modem::ATwaitForWordOrWord(char* word1, char* word2, uint32_t timeout)
+{
+      int targetIndex1 = 0;
+      int targetIndex2 = 0;
+      bool havefullmatch1 = false;
+      bool havefullmatch2 = false;
+      char captured[32];
+      memset(captured,0,sizeof(captured));
+      Timer t;
+      t.start();
+      uint32_t startmillis = t.read_ms();
+      uint32_t runtime = 0;
+      while((!havefullmatch1 || !havefullmatch2) && runtime < timeout)
+      {
+          runtime = (t.read_ms() - startmillis);
+          if(NRFuart_readable())
+           {
+              char c = NRFuart_getc();
+              if (c != word1[targetIndex1])
+               { //no match, reset
+                  targetIndex1 = 0;
+              }
+              
+              if (c != word2[targetIndex2])
+               { //no match, reset
+                  targetIndex2 = 0;
+              }          
+              
+              if (c == word1[targetIndex1])
+               { //we have a match
+                  captured[targetIndex1] = c;
+                  targetIndex1 ++;
+                  //check for full match
+                  if (  strcmp(word1, captured) == 0  )
+                   {
+                      havefullmatch1 = true;
+                  }
+              }
+              
+               if (c == word2[targetIndex2])
+               { //we have a match
+                  captured[targetIndex2] = c;
+                  targetIndex2 ++;
+                  //check for full match
+                  if (  strcmp(word2, captured) == 0  )
+                   {
+                      havefullmatch2 = true;
+                  }
+              }
+          }
+      }
+      t.stop();
+      t.reset();
+    
+      if (havefullmatch1) {
+            return 1;
+      }
+      else if(havefullmatch2) {
+            return 2;
+      }
+      else {
+            return 0;
+      }
+}
+
 
 bool Modem::ATgetResponse(char terminator, uint32_t timeout) 
 {
@@ -74,8 +139,8 @@
             }
         }
     }
+    t.reset();
     t.stop();
-    t.reset();
     ATinBuffer[charindex] = '\n'; //make sure we end with whitespace lf
     return gotTerminator;
 }
@@ -254,6 +319,7 @@
                 on(false);
             }
         }
+        t.reset();
         t.stop();
     }
     NRFuart_flush();
@@ -380,7 +446,7 @@
         
     //TRY X NUMBER OF TIMES
     //maxAttempts
-    while (!sent && attempt < 100) { //10 seconds, 100*200ms
+    while (!sent && attempt < 100) { //20 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);
@@ -401,7 +467,7 @@
     }
 }
 
-char* Modem::USSDreceive(int messageIndex) 
+char* Modem::USSDreceive(void) 
 {
     bool received = false;
     uint32_t timeout = ATTIMEOUT_LONG;
@@ -417,16 +483,14 @@
         if (ATwaitForWord("+CUSD: 0",ATTIMEOUT_SHORT)) {
             if (ATgetResponse('\r',ATTIMEOUT_SHORT)) {  
                 if ( (matchCount = sscanf(ATinBuffer,",\"%d#%[^#]",USSDmessageIndex,ATinBuffer) ) > 0 ) {
-                    if (USSDmessageIndex == messageIndex) {
-                        //NEED TO GET THIS WORKING SO WE KNOW WE ARE DEALING WITH THE RIGHT MESSAGE
-                        //MOVE THE BELOW INTO THIS IF STAEMEBNTS WHEN DONE
-                    }
                     received = true;
                 }
             }
         }
     }
     NRFuart_flush();
+    t.reset();
+    t.stop();
     if (received) {
         return ATinBuffer;
     } else {
@@ -437,19 +501,18 @@
 
 char* Modem::USSDmessage(char* message, bool needResponse, char* api) 
 {  
-    uint8_t messageIndex = 1;
     bool result;
     int messageLength = strlen(message);
-    if (messageLength > USSD_MAXLENGTH) {
+    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);
+        snprintf(message_failsafe,sizeof(message_failsafe),"(%s,a:error,z:TOOBIG,s:1)\0",api);
         result = USSDsend(message_failsafe);
     } else {
         result = USSDsend(message);
     }
     if (result) {
         if (needResponse) {
-            char* response = USSDreceive(messageIndex);
+            char* response = USSDreceive();
             if (strcmp(response, "err") != 0) {
                 return response;
             } else {
@@ -468,6 +531,7 @@
     NRFuart_flush();
     bool haveGPSFix = false;
     bool haveCellFix = false;
+    float utc; float lat; float lng; float hdp; float alt; uint8_t fix; float cog; float spkm; float spkn; uint32_t date; uint8_t sat;
     static char locDataOut[100];
     memset(locDataOut,0x00,sizeof(locDataOut));
     Timer t;
@@ -480,61 +544,56 @@
     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");
-        //ATwaitForWord("OK",ATTIMEOUT_SHORT);
-        
         //TURN ON GPS
         ATsendCMD("AT+QGPS=1");
         ATwaitForWord("OK",ATTIMEOUT_SHORT);
         
         //TRY UNTIL TIMEOUT
         uint8_t GPS_fixstage = 0;
-        //uint8_t GPS_fixcount = 0;
+        uint8_t GPS_fixloopcount = 0;
         startseconds = t.read();
         runtime = 0;
-        while(!haveGPSFix && runtime < timeout_seconds) {
-            ThisThread::sleep_for(3000); //this goes first
+        
+        while(GPS_fixstage < 2 && runtime < timeout_seconds) {
+            ThisThread::sleep_for(4000); //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("ATE0");
+            ATwaitForWord("OK",ATTIMEOUT_SHORT);
             ATsendCMD("AT+QGPSLOC=2");
             if (ATwaitForWord("+QGPSLOC: ",ATTIMEOUT_SHORT)) {
+                haveGPSFix = true;
                 GPS_fixstage = 1;
-                haveGPSFix = true;
+                GPS_fixloopcount ++;
+                int matchCount = 0;
+                if (ATgetResponse('\r',ATTIMEOUT_VERYSHORT)) { 
+                    if ((matchCount = sscanf(ATinBuffer,"%f,%f,%f,%f,%f,%d,%f,%f,%f,%d,%d",&utc,&lat,&lng,&hdp,&alt,&fix,&cog,&spkm,&spkn,&date,&sat)) == 11 ) {
+                        //{“fix”:“GPS”,“sat”:“9",“lat”:“52.913254",“lng”:“-1.455289",“hdp”:“2.0",“spd”:“0.0"}                    
+                        haveGPSFix = true;
+                        if (accuracy > 2) {
+                            if (hdp <= 1.8) {
+                                GPS_fixstage = 2;
+                            }
+                        } else {
+                            if (GPS_fixloopcount >= 1) {
+                                GPS_fixstage = 2;
+                            }
+                        }
+                    }
+                }
             }
         }
         
-        //STAGE 1 FIX - NOW WAIT for 5 seconds to improve fix quality // need better solution
-        if (GPS_fixstage == 1) {
-            ThisThread::sleep_for(5000);
-            ATsendCMD("AT+QGPSLOC=2");
-            if (ATwaitForWord("+QGPSLOC: ",ATTIMEOUT_SHORT)) {
-                GPS_fixstage = 2;
-            }
+        if (haveGPSFix) {
+            sprintf(locDataOut,",g:(fix:GPS,sat:%d,lat:%.5f,lng:%.5f,hdp:%.0f,spd:%.0f)\0",sat,lat,lng,hdp,spkm);
+            memset(GLOBAL_GPSlocString_prev,0x00,sizeof(GLOBAL_GPSlocString_prev));
+            memcpy(GLOBAL_GPSlocString_prev,locDataOut,sizeof(GLOBAL_GPSlocString_prev)); //save for future recall
+            GLOBAL_have_GPSlocString_prev = true;
+            BYREF_GPSFailCount = 0;
+        } else {
+            BYREF_GPSFailCount ++; 
         }
         
-        //STAGE 2 FIX
-        if (GPS_fixstage == 2) {
-            int matchCount = 0;
-            float utc; float lat; float lng; float hdp; float alt; uint8_t fix; float cog; float spkm; float spkn; uint32_t date; uint8_t sat;
-            
-            //Example data
-            //+QGPSLOC: 233510.0,52.55415,1.24021,1.2,59.2,2,0.00,0.0,0.0,201218,05
-            //115757.0,52.62091,1.29536,0.8,58.2,2,0.00,0.0,0.0,211218,07
-            if (ATgetResponse('\r',ATTIMEOUT_VERYSHORT)) { 
-                if ((matchCount = sscanf(ATinBuffer,"%f,%f,%f,%f,%f,%d,%f,%f,%f,%d,%d",&utc,&lat,&lng,&hdp,&alt,&fix,&cog,&spkm,&spkn,&date,&sat)) == 11 ) {
-                    //{“fix”:“GPS”,“sat”:“9",“lat”:“52.913254",“lng”:“-1.455289",“hdp”:“89.0",“spd”:“0.0"}                    
-                    sprintf(locDataOut,",g:(fix:GPS,sat:%d,lat:%.6f,lng:%.6f,hdp:%.1f,spd:%.1f)\0",sat,lat,lng,hdp,spkm);
-                    haveGPSFix = true;
-                    BYREF_GPSFailCount = 0; //reset
-                }
-            }
-        } else {
-            BYREF_GPSFailCount ++;       
-        }
-                
         //TURN OFF GPS
         ATsendCMD("AT+QGPSEND");
         ATwaitForWord("OK",ATTIMEOUT_SHORT);
@@ -551,8 +610,8 @@
             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("ATE0");
+                ATwaitForWord("OK",ATTIMEOUT_SHORT);
                 ATsendCMD("AT+QENG=\"servingcell\"");
                 if (ATwaitForWord("+QENG: \"servingcell\",\"NOCONN\",",ATTIMEOUT_VERYSHORT)) {
                     if (ATgetResponse('\r',ATTIMEOUT_SHORT)) {
@@ -583,6 +642,7 @@
         }
     }
     
+    t.reset();
     t.stop();
     
     //RETURN
--- a/modem.h	Thu May 23 11:39:28 2019 +0000
+++ b/modem.h	Wed May 29 22:59:12 2019 +0000
@@ -7,7 +7,7 @@
 
     #define UC20_BAUDRATE       115200
     #define SIM7600_BAUDRATE    115200
-    #define USSD_MAXLENGTH      160
+    #define USSD_MAXLENGTH      140
     #define ATTIMEOUT_VERYSHORT 3000
     #define ATTIMEOUT_SHORT     5000
     #define ATTIMEOUT_MED       10000
@@ -27,7 +27,7 @@
             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);
-            char* USSDreceive(int messageIndex);
+            char* USSDreceive(void);
             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);
@@ -37,6 +37,7 @@
             //AT
             void ATsendCMD(char* cmd);
             bool ATwaitForWord(char* word, uint32_t timeout);
+            int ATwaitForWordOrWord(char* word1, char* word2, uint32_t timeout);
             bool ATgetResponse(char terminator, uint32_t timeout);
         private: