init

Dependencies:   aconno_I2C Lis2dh12 WatchdogTimer

Revision:
52:bd7678eade77
Parent:
51:9078e6928412
Child:
53:c6942af186d7
--- 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);