init
Dependencies: aconno_I2C Lis2dh12 WatchdogTimer
main.cpp
- Committer:
- pathfindr
- Date:
- 2019-05-29
- Revision:
- 53:c6942af186d7
- Parent:
- 52:bd7678eade77
- Child:
- 54:2840f2d50734
File content as of revision 53:c6942af186d7:
#include "main.h"
// MUST USE MBED 5.10.4 2fd0c5cfbd
/*
PRE DEPLOYMENT CHECKS!!
• Ensure APP DATA address is correct
*/
/*
TO DO
STOP FRASH WRITE FROM CRASHING IF THERE IS A PROBLEM
*/
//------------------------------------------------------------------------------
//FUNCTION PROTOTYPES - NEED TO ADD ALL OF THE MISSING ONES
//------------------------------------------------------------------------------
//should really add these - will just add as and when needed for now
void event_activity_tx();
void event_location_tx(bool failsafe);
#if BLE_ENABLED
void bleShutdown();
#endif
//------------------------------------------------------------------------------
// GLOBALS
//------------------------------------------------------------------------------
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[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 = 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 = 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_humidity = 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 = 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 = 0;
//EVENTS LOGGING
time_t RET_eventTime_location_log = 0;
time_t RET_eventTime_environmental_log = 0;
//EVENTS TX
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;
int RET_closestBT04Tag_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
//------------------------------------------------------------------------------
InterruptIn button(PN_IN_BUTTON);
//------------------------------------------------------------------------------
//PERIPHERALS
//------------------------------------------------------------------------------
#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;
//------------------------------------------------------------------------------
//SEMAPHORES
//------------------------------------------------------------------------------
Semaphore mainthread;
//------------------------------------------------------------------------------
// LOW LEVEL FUNCS
//------------------------------------------------------------------------------
void watchdogKick() {
watchdog.kick();
}
void set_8bit_flag(uint8_t& flags, uint8_t flag) {
flags |= flag;
}
bool get_8bit_flag(uint8_t& flags, uint8_t flag) {
bool result = (flags & flag);
return result;
}
void clr_8bit_flag(uint8_t& flags, uint8_t flag) {
flags &= ~flag;
}
void nrf_configureForSleep(){
//Disable SPI pins to reduce power
//nrf_gpio_cfg_input(PN_SPI_MOSI, NRF_GPIO_PIN_NOPULL); //Don't need this one
nrf_gpio_cfg_input(PN_SPI_MISO, NRF_GPIO_PIN_NOPULL);
//disable modem control lines
nrf_gpio_cfg_input(PN_GSM_PWR_KEY, NRF_GPIO_PIN_NOPULL);
nrf_gpio_cfg_input(PN_GSM_WAKE_DISABLE, NRF_GPIO_PIN_NOPULL);
//TWI0
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;
*(volatile uint32_t *)0x40004FFC = 0;
*(volatile uint32_t *)0x40004FFC;
*(volatile uint32_t *)0x40004FFC = 1;
}
void setState(uint8_t state) {
RET_state_prev = RET_state;
RET_state = state;
}
void dumpSettings() {
if(RET_debug){
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_RTCunixtime:%u", RET_RTCunixtime);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_firmware:%d", RET_setting_firmware);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_minimumupdate_hrs:%d", RET_setting_minimumupdate_hrs);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_state:%d", RET_state);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_location_mode:%d", RET_setting_location_mode);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_location_accuracy:%d", RET_setting_location_accuracy);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_location_tx_interval_mins:%d", RET_setting_location_tx_interval_mins);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_location_tx_failsafe_hrs:%d", RET_setting_location_tx_failsafe_hrs);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_location_timeout:%d", RET_setting_location_timeout);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_activity_tx_interval_hrs:%d", RET_setting_activity_tx_interval_hrs);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_activity_mode:%d", RET_setting_activity_mode);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_environmental_tx_interval_mins:%d", RET_setting_environmental_tx_interval_mins);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_motion_g:%d", RET_setting_motion_g);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_motion_start_seconds:%d", RET_setting_motion_start_seconds);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_motion_stop_seconds:%d", RET_setting_motion_stop_seconds);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_impact_g:%d", RET_setting_impact_g);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_impact_alert:%d", RET_setting_impact_alert);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_connection_timeout:%d", RET_setting_connection_timeout);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_beacon_interval_seconds:%d", RET_setting_beacon_interval_seconds);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_setting_beacon_scan:%d", RET_setting_beacon_scan);debug_exe();
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RET_pf_identifier:%s", RET_pf_identifier);debug_exe();
}
}
void recordFirmwareAsValid() {
#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;
if(get_flag(&app_data, app_execution_flag) == true) {
clr_flag(&app_data, app_execution_flag);
clr_flag(&app_data, first_run_flag);
write_app_data_to_flash_execute = true;
}
if(app_data.current_firmware_version != FW_VERSION) {
app_data.current_firmware_version = FW_VERSION;
app_data.target_firmware_version = FW_VERSION;
write_app_data_to_flash_execute = true;
}
if (write_app_data_to_flash_execute) {
write_app_data_to_flash(&app_data);
//read back to check
ThisThread::sleep_for(200); //need this delay
read_app_data_from_flash(&app_data);
if (app_data.current_firmware_version == FW_VERSION) {
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "OK");debug_exe();
} else {
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "FAIL - IS BLE SHUTDOWN?");debug_exe();
}
}
}
void updateBatteryV() {
NRF52_SAADC batteryIn;
batteryIn.addChannel(9); // vdd for battery
batteryIn.calibrate();
//get initial reading, first reading is always low
batteryIn.updateData(); batteryIn.getData()[0];
float voltage_accumulator = 0.0;
uint8_t readings = 0;
for (uint8_t i = 1; i <= 50; i++) { // need to get it 2 times to get accurate data, first one is always low for some reason
batteryIn.updateData();
voltage_accumulator += (batteryIn.getData()[0])*(1.0/1024.0)*3.60;
readings ++;
}
RET_voltage = (voltage_accumulator / (float)readings);
}
//------------------------------------------------------------------------------
// TEMPERATURE
//------------------------------------------------------------------------------
float getTemperature() {
return si7060.getTemperature();
}
void updateTemperatures() {
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_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "Temp:%.1f Min:%.1f Max:%.1f",RET_temperature,RET_temperature_min,RET_temperature_max);debug_exe();}
}
void addToExceptionString(char* value) {
if(strstr(GLOBAL_exceptionString, value) == false){
snprintf(GLOBAL_exceptionString+strlen(GLOBAL_exceptionString),sizeof(GLOBAL_exceptionString),".%s",value);
}
}
void resetTemperatures() {
RET_temperature_max = -999.0; //Within broadcast frame. Set inital value to low
RET_temperature_min = 999.0; //Within broadcase frame. Set inital value to high
}
//------------------------------------------------------------------------------
// USER BUTTON HANDLING
//------------------------------------------------------------------------------
void buttonPress() {
RET_buttonPressTime = LPtimer.read_ms();
}
void buttonRelease() {
//debounce catch
RET_buttonReleaseTime = LPtimer.read_ms();
if ((RET_buttonReleaseTime - RET_buttonReleaseTime_prev) > 75) {
RET_buttonPressCount ++;
RET_buttonHoldTime = (RET_buttonReleaseTime - RET_buttonPressTime);
//temporarily enable debugging and dump settings
RET_debug = true;
RET_debug_offat = (RET_RTCunixtime + 3600); //debug on for 1hr
}
RET_buttonReleaseTime_prev = RET_buttonReleaseTime;
}
//------------------------------------------------------------------------------
// RTC TICKER
//------------------------------------------------------------------------------
void RTCtick() {
//YOU MUST NOT CALL ANY OTHER FUNCTIONS OR DEBUG FROM INSIDE HERE!!! OR IT LOCKS UP THE DEVICE, just change vars & comparisons etc
RET_RTCunixtime += 1;
//button logic
if (RET_buttonHoldTime >= 4000 && RET_buttonHoldTime <= 10000) {
RET_buttonHoldTime = 0;
RET_buttonPressCount = 0;
if (RET_state != STATE_DORMANT) {
RET_state_prev = RET_state;
RET_state = STATE_TURNOFF;
} else {
RET_state = STATE_TURNON;
}
mainthread.release();
} else if (RET_buttonHoldTime >= 14000 && RET_buttonHoldTime <= 30000) {
RET_buttonHoldTime = 0;
RET_buttonPressCount = 0;
RET_state = STATE_SCORCHEDEARTH;
mainthread.release();
} else {
if((LPtimer.read_ms() - RET_buttonReleaseTime) > 1500 && RET_buttonPressCount > 0) {
if(RET_busy == true) {
//RTCtick_ledflash_count = 4;// 2 flashes
} else {
RET_SetupRunAt = 0; //allow setup to run again
switch (RET_buttonPressCount) { //double catches to help with debounce
case 1 :
if(RET_state_prev != RET_state) {RET_state_prev = RET_state;}
RET_state = STATE_BUTTONPRESS1;
RET_buttonPressCount = 0;
mainthread.release();
break;
case 3 :
if(RET_state_prev != RET_state) {RET_state_prev = RET_state;}
RET_state = STATE_BUTTONPRESS3;
RET_buttonPressCount = 0;
mainthread.release();
break;
case 5 :
if(RET_state_prev != RET_state) {RET_state_prev = RET_state;}
RET_state = STATE_BUTTONPRESS5;
RET_buttonPressCount = 0;
mainthread.release();
break;
default :
//do nothing
break;
}
}
RET_buttonPressCount = 0;
}
}
if(RET_debug && GLOBAL_LEDSequenceinProgress == false){
if (RET_motionState) {
led1 = 0;
} else {
led1 = 1;
}
}
}
//------------------------------------------------------------------------------
// GLOBALS
//------------------------------------------------------------------------------
void resetSessionVars() {
GLOBAL_accel_healthy = false;
RET_motionTriggeredinFrame = false;
RET_modemBrownOutCountInSession = 0;
RET_humidity = 99.0f;
memset(GLOBAL_exceptionString,0x00,sizeof(GLOBAL_exceptionString));
}
void healthCheck() {
//check for watchdog fire
if (RET_watchdogfired == true) {
addToExceptionString("WD");
RET_watchdogfired = false;
}
//check clock
if(RET_haveSettings == true) {
if (RET_RTCunixtime < 1547678732) {
//go dormant for 72hrs and then resetup
RET_haveSettings = false;
setState(STATE_DORMANT);
}
}
//check that we have a reasonable time to loc
if(RET_haveSettings == true) {
//check location tx delta is set
if (RET_eventTime_location_tx == 0) {
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "ERR:eventTime_location_tx is 0");debug_exe();}
RET_haveSettings = false;
}
//check location failsafe tx delta is less that 2 weeks
long location_failsafe_tx_delta = (RET_eventTime_location_failsafe_tx - RET_RTCunixtime);
if (location_failsafe_tx_delta > TENDAYSINSECONDS) {
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "ERR:location_failsafe_tx_delta too small");debug_exe();}
RET_haveSettings = false;
}
}
if (RET_haveSettings == false) {
setState(STATE_SETUP);
}
}
bool selfTest() {
int test_count = 0;
int test_pass = 0;
//Accelerometer
test_count ++;
uint8_t lis3dh_id;
lis3dh.LIS3DH_GetWHO_AM_I(&lis3dh_id);
if (lis3dh_id == 51) {
GLOBAL_accel_healthy = true;
test_pass ++;
} else {
GLOBAL_accel_healthy = false;
addToExceptionString("AF");
}
//Result
if (test_count == test_pass) {
return true;
} else {
//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 *)¶ms->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",RET_closestLocationTag_id, RET_closestLocationTag_rssi);debug_exe();}
}
}
break;
}
case BLE_SERVICEID_BT04 :
{
//get serial
//char serial[9];
//snprintf(serial, sizeof(serial), "%02x%02x%02x%02x", params->advertisingData[11], params->advertisingData[12], params->advertisingData[13], params->advertisingData[14]);
//if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"Serial: %s", serial);debug_exe();}
//get battery
//int battery = params->advertisingData[15];
//if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"Battery: %i", battery);debug_exe();}
//get temperature positive
/*
bool temppositive = !(params->advertisingData[17] & 0b01000000);
float temperature =
(
((params->advertisingData[17] & 0b00111111) << 8) |
((params->advertisingData[18] & 0b11111111))
) / 100.0;
if (!temppositive) temperature = -temperature;
//if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"Temp: %f", temperature);debug_exe();}
*/
//get humidity
int tag_rssi = params->rssi * -1; //to convert to positive number
if (tag_rssi < RET_closestBT04Tag_rssi) {
RET_humidity =
(
((params->advertisingData[19] & 0b01111111) << 8) |
((params->advertisingData[20] & 0b11111111))
) / 100.0;
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "Humidity Tag Present: %f",RET_humidity);debug_exe();}
}
//rssi
//if(DEBUG_ON){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"Rssi: %i", params->rssi);debug_exe();}
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
//------------------------------------------------------------------------------
bool checkMotion() {
if (RET_haveSettings) { //NEED THIS AS THINGS GO FUNKY WITHOUT RTC TIME SET CORRECTLY
if (lis3dh_int2) {
RET_motionTriggeredinFrame = true;
GLOBAL_needToConfigureLis3dh = true; //interrupt has fire so need to clear it
if(RET_debug) {
LED1on(100);
}
if (!RET_motionPendingOnState) {
RET_motionPendingOnState = true;
RET_motionPendingOffState = false;
// Log start motion time
RET_motionStartTime = RET_RTCunixtime;
}
} else {
RET_motionTriggeredinFrame = false;
RET_motionPendingOnState = false;
if (!RET_motionPendingOffState) {
RET_motionPendingOffState = true;
//log stop motion time
RET_motionStopTime = RET_RTCunixtime;
}
}
//calculate motion state
if (RET_motionFrameStart == 0) {RET_motionFrameStart = RET_RTCunixtime;}
if (RET_motionPendingOnState) {
//check if above threshold
time_t inMotionForSeconds = ((RET_RTCunixtime - RET_motionStartTime) + (DEFAULT_SLEEP_FRAME / 1000)); //Plus DEFAULT_SLEEP_FRAME as it should include frame time
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "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_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), "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);
}
}
}
}
}
}
return RET_motionState;
}
//------------------------------------------------------------------------------
// UPDATE OPERATING SETTINGS
//------------------------------------------------------------------------------
bool saveSettings(char* settingsBuffer) {
int matchCount = 0;
int critical_fail_count = 0;
int TEMP_a = -1; time_t TEMP_b = 0; int TEMP_c = -1; int TEMP_d = -1; int TEMP_e = -1; int TEMP_f = -1; int TEMP_g = -1; int TEMP_h = -1; int TEMP_i = -1; int TEMP_j = -1;
int TEMP_k = -1; int TEMP_l = -1; int TEMP_m = -1; int TEMP_n = -1; int TEMP_o = -1; int TEMP_p = -1; int TEMP_q = -1; int TEMP_r = -1; int TEMP_s = -1; int TEMP_t = -1; char TEMP_u[7];
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "RESP: %s",settingsBuffer);debug_exe();}
//exampple
//+CUSD: 0,”1#a:12,b:1558020598,c:-1,d:-1,e:1,f:2,g:5,h:168,i:90,j:168,k:0,l:8,m:60,n:60,o:0,p:0,q:120,r:0,s:0,t:1,u:F859C1#”,15
if ( (matchCount = sscanf(settingsBuffer,"a:%d,b:%u,c:%d,d:%d,e:%d,f:%d,g:%d,h:%d,i:%d,j:%d,k:%d,l:%d,m:%d,n:%d,o:%d,p:%d,q:%d,r:%d,s:%d,t:%d,u:%s",
&TEMP_a,&TEMP_b,&TEMP_c,&TEMP_d,&TEMP_e,&TEMP_f,&TEMP_g,&TEMP_h,&TEMP_i,&TEMP_j,&TEMP_k,&TEMP_l,&TEMP_m,&TEMP_n,&TEMP_o,&TEMP_p,&TEMP_q,&TEMP_r,&TEMP_s,&TEMP_t,&TEMP_u) ) > 0 ) {
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "PARAMS: a:%d,b:%u,c:%d,d:%d,e:%d,f:%d,g:%d,h:%d,i:%d,j:%d,k:%d,l:%d,m:%d,n:%d,o:%d,p:%d,q:%d,r:%d,s:%d,t:%d,u:%s\n",
TEMP_a,TEMP_b,TEMP_c,TEMP_d,TEMP_e,TEMP_f,TEMP_g,TEMP_h,TEMP_i,TEMP_j,TEMP_k,TEMP_l,TEMP_m,TEMP_n,TEMP_o,TEMP_p,TEMP_q,TEMP_r,TEMP_s,TEMP_t,TEMP_u);debug_exe();}
if(TEMP_a != -1) { RET_setting_minimumupdate_hrs = TEMP_a; }
if(TEMP_b > 1552915630) {
if (RET_RTCunixtime < 1552915630) {
//assume this is first proper unixtime and set
RET_RTCunixtime = TEMP_b;
} else {
//this is not a first unixtime, so check within safe range, convert to long long first to avoid -1 rollover issue
long long unixtime_in = TEMP_b;
long long unixtime_current = RET_RTCunixtime;
if ((unixtime_in - unixtime_current) < 604800) { //allow 1 week difference
RET_RTCunixtime = TEMP_b;
} else {
critical_fail_count++;
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "unixtime too far ahead. C:%u N:%u",RET_RTCunixtime,TEMP_b);debug_exe();}
}
}
} else {
critical_fail_count++;
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "unixtime too low");debug_exe();}
}
if(TEMP_c != -1) { RET_setting_firmware = TEMP_c; } else { RET_setting_firmware = -1;}
if(TEMP_d != -1) { setState(TEMP_d); } else { setState(STATE_NORMAL);}
if(TEMP_e != -1) { RET_setting_location_mode = TEMP_e; }
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; }
if(TEMP_h != -1) { RET_setting_location_tx_failsafe_hrs = TEMP_h; }
if(RET_setting_location_tx_failsafe_hrs > 504) {RET_setting_location_tx_failsafe_hrs = DEFAULT_LOCATION_TX_FAILSAFE_HRS;}
if(TEMP_i != -1) { RET_setting_location_timeout = TEMP_i; }
if(RET_setting_location_timeout < 60 || RET_setting_location_timeout > 300) {RET_setting_location_timeout = DEFAULT_LOCATION_TIMEOUT;}
if(TEMP_j != -1) { RET_setting_activity_tx_interval_hrs = TEMP_j; }
if(TEMP_k != -1) { RET_setting_environmental_tx_interval_mins = TEMP_k; }
if(TEMP_l != -1) { RET_setting_motion_g = TEMP_l; }
if(RET_setting_motion_g < 4 || RET_setting_motion_g > 127) {RET_setting_motion_g = DEFAULT_MOTION_G;}
if(TEMP_m != -1) { RET_setting_motion_start_seconds = TEMP_m; }
if(TEMP_n != -1) { RET_setting_motion_stop_seconds = TEMP_n; }
if(TEMP_o != -1) { RET_setting_impact_g = TEMP_o; }
if(TEMP_p != -1) { RET_setting_impact_alert = TEMP_p; }
if(TEMP_q != -1) { RET_setting_connection_timeout = TEMP_q; }
if(RET_setting_connection_timeout < 60 || RET_setting_connection_timeout > 240) { RET_setting_connection_timeout = DEFAULT_CONNECTION_TIMEOUT; }
if(TEMP_r != -1) { RET_setting_beacon_interval_seconds = TEMP_r; }
if(TEMP_s != -1) { RET_setting_beacon_scan = TEMP_s; }
if(TEMP_t != -1) { RET_setting_activity_mode = TEMP_t; }
if(TEMP_u[0] != 0x00 && TEMP_u[1] != 0x00 && TEMP_u[2] != 0x00) { strcpy(RET_pf_identifier,TEMP_u); }
if (critical_fail_count == 0) {
RET_receivedNewSettings = true;
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "NEW SETTINGS");debug_exe();}
dumpSettings();
RET_haveSettings = true;
GLOBAL_needToConfigureLis3dh = true;
RET_SettingsGotAt = RET_RTCunixtime;
//check for firmware update
if (RET_setting_firmware > 0 && RET_setting_firmware != FW_VERSION) {
//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);
app_data.current_firmware_version = FW_VERSION;
app_data.target_firmware_version = RET_setting_firmware;
write_app_data_to_flash(&app_data);
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "OTA\n");debug_exe();}
ThisThread::sleep_for(200);
system_reset();
}
return true;
} else {
addToExceptionString("SCF");
return false;
}
} else {
addToExceptionString("SPE");
return false;
}
}
//------------------------------------------------------------------------------
// SET EVENT TIMES
//------------------------------------------------------------------------------
void setEventTime_Location() {
if(RET_setting_location_tx_interval_mins > 0) {
RET_eventTime_location_tx = (RET_RTCunixtime + (RET_setting_location_tx_interval_mins * 60));
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "EVTSET - LOC TX @ %u, MODE %d",RET_eventTime_location_tx, RET_setting_location_mode);debug_exe();}
}
if(RET_setting_location_tx_failsafe_hrs > 0) {
RET_eventTime_location_failsafe_tx = (RET_RTCunixtime + (RET_setting_location_tx_failsafe_hrs * 3600));
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "EVTSET - LOC FS TX @ %u",RET_eventTime_location_failsafe_tx);debug_exe();}
}
}
void setEventTime_Activity() {
if(RET_setting_activity_tx_interval_hrs > 0) {
RET_eventTime_activity_tx = (RET_RTCunixtime + (RET_setting_activity_tx_interval_hrs * 3600));
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "EVTSET - ACT TX @ %u",RET_eventTime_activity_tx);debug_exe();}
}
}
void setEventTime_Environmental() {
if(RET_eventTime_environmental_tx > 0) {
RET_eventTime_environmental_tx = (RET_RTCunixtime + (RET_setting_environmental_tx_interval_mins * 60));
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "EVTSET - ENV TX @ %u",RET_eventTime_environmental_tx);debug_exe();}
}
}
void setEventTimes() {
//SET ALL EVENT TIMES
setEventTime_Location();
setEventTime_Activity();
setEventTime_Environmental();
}
//------------------------------------------------------------------------------
// ERROR LOG
//------------------------------------------------------------------------------
void sendErrorLog(char* error) {
updateBatteryV();
int timetaken = (RET_RTCunixtime - GLOBAL_wakeTime);
char bytestosend[100];
memset(bytestosend,0x00,sizeof(bytestosend));
snprintf(bytestosend,sizeof(bytestosend),"(%s,a:log,f:%d,v:%.2f,e:%d,z:%s.%s,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);
}
}
ThisThread::sleep_for(250);
}
//------------------------------------------------------------------------------
// EVENTS
//------------------------------------------------------------------------------
void failed_broadcast_log(char* eventstring) {
//First available free slot
bool saved = false;
for(int i = 0; i < sizeof(GLOBAL_failed_broadcast_slots); i++) {
if (GLOBAL_failed_broadcast_slots[i] == false) {
memset(GLOBAL_failed_broadcasts[i],0x00,sizeof(GLOBAL_failed_broadcasts[i])); //clear row
snprintf(GLOBAL_failed_broadcasts[i],sizeof(GLOBAL_failed_broadcasts[i]),"%s",eventstring); //save new row
GLOBAL_failed_broadcast_slots[i] = true;
saved = true;
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"Failed Broadcast saved: %s",eventstring);debug_exe();}
break;
}
}
if (!saved) {
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"Failed Broadcast save fail");debug_exe();}
}
return;
}
void failed_broadcasts_tx() {
#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++) {
if (GLOBAL_failed_broadcast_slots[i] == true) {
numbertosend ++;
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"Retry:%s",GLOBAL_failed_broadcasts[i]);debug_exe();}
}
}
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"Failed Broadcasts to send:%d",numbertosend);debug_exe();}
for(int i = 0; i < sizeof(GLOBAL_failed_broadcast_slots); i++) {
if (GLOBAL_failed_broadcast_slots[i] == true) {
if (RET_NetworkFailCount <= DEFAULT_MAX_FAILED_CONNECTIONS) {
if (modem.on(RET_force2G)) {
if (modem.registerOnNetwork(2,RET_setting_connection_timeout,RET_NetworkFailCount)) {
char result[100];
bool getResponse = false;
snprintf(result,sizeof(result),"%s",modem.USSDmessage(GLOBAL_failed_broadcasts[i], getResponse, GLOBAL_defaultApi));
if (strcmp(result, "sendok") == 0) {
//clear row
memset(GLOBAL_failed_broadcasts[i],0x00,sizeof(GLOBAL_failed_broadcasts[i]));
GLOBAL_failed_broadcast_slots[i] = false;
}
}
}
}
}
}
}
bool event_setup(bool manualrun) {
#if BLE_ENABLED
bleStopAdvertising();
#endif
bool pass = false;
LED1on(0);
if (RET_NetworkFailCount > DEFAULT_MAX_FAILED_CONNECTIONS) addToExceptionString("NF");
if (RET_GPSFailCount > DEFAULT_MAX_FAILED_GPS) addToExceptionString("GF");
RET_setupInProgress = true;
RET_NetworkFailCount = 0;
RET_GPSFailCount = 0;
RET_setting_connection_timeout = 180; //reset to longer value to setup run to help with connection
bool selftestresult = selfTest();
int connectionStartTime = RET_RTCunixtime;
if (modem.on(RET_force2G)) {
if (modem.registerOnNetwork(DEFAULT_CONNECTION_ATTEMPTS,RET_setting_connection_timeout,RET_NetworkFailCount)) {
int timetaken_total = (RET_RTCunixtime - GLOBAL_wakeTime) + 10; //add 10 for ussd response time.
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,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
if (strcmp(result, "sendokrecfail") == 0) {
//send ok but receive fail
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"USSD Send Ok but Rec fail");debug_exe();}
sendErrorLog("ERR-SU-NR");
} else if (strcmp(result, "sendfail") == 0) {
//do nothing
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"USSD Send Fail");debug_exe();}
} else {
if (saveSettings(result) == true) {
pass = true;
} else {
//something went critically wrong getting settings
sendErrorLog("ERR-SU-IR");
}
}
}
} else {
//FAILUREMODE Modem failed to turn on
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"Modem Fail");debug_exe();}
}
//IF WE PASSED THEN LETS DO OTHER POSTS
if (pass == true) {
GLOBAL_wakeTime = RET_RTCunixtime; //lets reset this here so that the following loc and act function have sensible values for total time
//GET LOC DATA
//uint8_t previous_location_accuracy = RET_setting_location_accuracy;
//RET_setting_location_accuracy = 1; //set location mode to CL only
event_location_tx(false);
//RET_setting_location_accuracy = previous_location_accuracy; //set location mode back to previous
//SEND ANY ACTIVITY DATA
event_activity_tx();
LED1blink(4,500); //PASS AND END
}
//TIDY UP = LOG RUN TIME - THIS MUST GO AT END AFTER WE HAVE GOT SERVER TIMESTAMP
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();
int connectionStartTime = RET_RTCunixtime;
if (modem.on(RET_force2G)) {
char locString[70];
int gpsStartTime = RET_RTCunixtime;
memcpy(locString, modem.getLocation(1, RET_setting_location_timeout, RET_GPSFailCount, RET_NetworkFailCount), sizeof(locString));
int timetaken_gps = (RET_RTCunixtime - gpsStartTime);
if (modem.registerOnNetwork(DEFAULT_CONNECTION_ATTEMPTS,RET_setting_connection_timeout,RET_NetworkFailCount)) {
int timetaken_total = (RET_RTCunixtime - GLOBAL_wakeTime);
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,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,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));
}
}
}
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];
//Check for Nearby Location Beacons
memset(RET_closestLocationTag_id, 0x00, sizeof(RET_closestLocationTag_id));
RET_closestLocationTag_rssi = 999;
RET_locationTag_present = false;
RET_detector_present = false;
#if BLE_ENABLED
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 (RET_locationTag_present && RET_debug) {debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer), "LocationTag: %s, rssi: %d",RET_closestLocationTag_id, RET_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;
if (RET_locationTag_present) {
snprintf(locString, sizeof(locString), ",l:%s.%d\0",RET_closestLocationTag_id,RET_closestLocationTag_rssi);
addToExceptionString("BL");
} else {
//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 {
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,w:%.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_humidity,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_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...
bool sendok = false;
if (RET_motionTotalActivityHoursSincePost > 0.0f && RET_setting_activity_mode > 0) {
//Build data to send
char bytesToSend[160];
if (RET_setting_activity_mode == 1) {
snprintf(bytesToSend,sizeof(bytesToSend),"(%s,a:act,t:%u,r:%.2f,h:%.2f)\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)\0",GLOBAL_defaultApi,RET_activityData,RET_motionFrameStart,RET_motionTotalActivityHoursSincePost);
}
if (RET_NetworkFailCount <= DEFAULT_MAX_FAILED_CONNECTIONS) {
if (modem.on(RET_force2G)) {
//SEND DATA
if (modem.registerOnNetwork(2,RET_setting_connection_timeout,RET_NetworkFailCount)) {
char result[100];
bool getResponse = false;
snprintf(result,sizeof(result),"%s",modem.USSDmessage(bytesToSend, getResponse, GLOBAL_defaultApi));
if (strcmp(result, "sendok") == 0) {
sendok = true;
//if(!RET_debug) {sendok = true;} //FOR TESTING
}
}
}
}
//If send failed then log it for retry - only need to do this for mode 2, for mode the time just increments
if (sendok == true) {
if (RET_setting_activity_mode == 1) {
RET_motionTotalActivityHoursSincePost = 0.0f;
if (RET_haveSettings) { RET_motionFrameStart = RET_RTCunixtime; }
} else if (RET_setting_activity_mode == 2) {
RET_motionTotalActivityHoursSincePost = 0.0f;
if (RET_haveSettings) { RET_motionFrameStart = RET_RTCunixtime; }
}
} else if (sendok == false) {
if (RET_setting_activity_mode == 1) {
//do nothing
} else if (RET_setting_activity_mode == 2) {
failed_broadcast_log(bytesToSend);
RET_motionTotalActivityHoursSincePost = 0.0f;
if (RET_haveSettings) { RET_motionFrameStart = RET_RTCunixtime; }
}
}
}
//RESETS
memset(RET_activityData,0x00,sizeof(RET_activityData));
setEventTime_Activity();
}
//------------------------------------------------------------------------------
// STATE ENGINE
//------------------------------------------------------------------------------
void mainStateEngine() {
switch(RET_state) {
case STATE_SETUP :
{ //need the curlies to avoid "transfer of control bypass init error warning"
RET_busy = true;
//check that we havent run setup too recently
time_t setupRunAt_delta = (RET_RTCunixtime - RET_SetupRunAt);
if (RET_SetupRunAt == 0 || setupRunAt_delta >= ONEDAYINSECONDS) {
updateBatteryV();
if (event_setup(false)) {
// All good
setState(STATE_NORMAL);
} else {
RET_eventTime_wakeFromDormant = (RET_RTCunixtime + ONEDAYINSECONDS);
setState(STATE_DORMANT);
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"SETUP FAILED:DORMANT until %u\n",RET_eventTime_wakeFromDormant);debug_exe();}
}
} else {
time_t setupCanRunAt = (RET_RTCunixtime + (ONEDAYINSECONDS - setupRunAt_delta));
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"SETUP CAN RUN AGAIN @%u \n",setupCanRunAt);debug_exe();}
}
RET_busy = false;
break;
}
case STATE_NORMAL :
{
RET_busy = true;
//LOCATION EVENT
bool run_location_tx = false;
switch (RET_setting_location_mode) {
case 1: //INTERVAL POST
if(RET_RTCunixtime >= RET_eventTime_location_tx && RET_eventTime_location_tx > 0) { run_location_tx = true; }
break;
case 2: //INTERVAL POST WITH MOTION CHECK
if(RET_RTCunixtime >= RET_eventTime_location_tx && RET_eventTime_location_tx > 0) {
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();}
}
}
break;
case 3: //POST ON STOP MOTION
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) {
if (RET_setting_activity_mode == 1 && RET_motionTotalActivityHoursSincePost > 0.0f) {
run_activity_tx = true;
}
if (RET_setting_activity_mode == 2 && strlen(RET_activityData) > 1) {
run_activity_tx = true;
}
}
//If in sendevent mode, check if buffer is close to full, if so send
if (RET_setting_activity_mode == 2 && strlen(RET_activityData) > (ACTIVITY_BUFFERSIZE-20)) { run_activity_tx = true; }
if (run_activity_tx) { event_activity_tx(); }
RET_busy = false;
break;
}
case STATE_DORMANT :
{
RET_busy = true;
if (RET_RTCunixtime >= RET_eventTime_wakeFromDormant) {
if (RET_haveSettings) {
setState(STATE_NORMAL);
} else {
setState(STATE_SETUP);
}
}
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"STATE:DORMANT until %u Prev S:%d\n",RET_eventTime_wakeFromDormant,RET_state_prev);debug_exe();}
RET_busy = false;
break;
}
case STATE_BUTTONPRESS1 :
{
RET_busy = true;
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"BUTTON PRESS 1\n");debug_exe();}
updateBatteryV();
if (RET_voltage < 2.5f) {
LED1blink(3,500);
} else if (selfTest() == false){
LED1blink(4,500);
} else {
if(RET_state_prev == STATE_DORMANT) {
LED1on(500);
} else if (RET_state_prev == STATE_NORMAL) {
LED1blink(2,500);
}
}
if (RET_state_prev != STATE_NORMAL || RET_state_prev != STATE_DORMANT) {
setState(STATE_NORMAL);
} else {
setState(RET_state_prev);
}
dumpSettings();
RET_busy = false;
break;
}
case STATE_BUTTONPRESS3 :
{
RET_busy = true;
if(RET_state_prev == STATE_DORMANT || RET_state_prev == STATE_NORMAL) {
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"BUTTON PRESS 3\n");debug_exe();}
LED1blink(3,500);
LED1on(0);
updateBatteryV();
event_setup(true);
LED1off();
}
setState(STATE_NORMAL); //turns device back on
RET_busy = false;
break;
}
case STATE_BUTTONPRESS5 :
{
RET_busy = true;
if(RET_state_prev == STATE_DORMANT || RET_state_prev == STATE_NORMAL) {
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"BUTTON PRESS 5\n");debug_exe();}
LED1blink(5,500);
LED1on(0);
updateBatteryV();
event_location_tx(false);
LED1off();
}
setState(STATE_NORMAL); //turns device back on
RET_busy = false;
break;
}
case STATE_TURNOFF :
{
RET_busy = true;
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"BUTTON HOLD \n");debug_exe();}
RET_eventTime_wakeFromDormant = (RET_RTCunixtime + THREEDAYSINSECONDS);
setState(STATE_DORMANT);
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"TURNING OFF\n");debug_exe();}
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"STATE:DORMANT until %u\n",RET_eventTime_wakeFromDormant);debug_exe();}
LED1on(5000);
//event_turnonofflog_tx(false);
RET_busy = false;
break;
}
case STATE_TURNON :
{
RET_busy = true;
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"BUTTON HOLD \n");debug_exe();}
if (RET_haveSettings) {
setState(STATE_NORMAL);
} else {
setState(STATE_SETUP);
}
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"TURNING ON\n");debug_exe();}
LED1blink(20,100);
RET_busy = false;
break;
}
case STATE_SCORCHEDEARTH :
{
RET_busy = true;
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"SCORCHED EARTH - RESETTING");debug_exe();}
setState(STATE_SETUP); //this wont be used but just incase to kick it out of this state
read_app_data_from_flash(&app_data);
app_data.current_firmware_version = 0;
app_data.target_firmware_version = 0;
write_app_data_to_flash(&app_data);
system_reset();
RET_busy = false;
break;
}
default :
{
setState(STATE_SETUP);
}
}
}
//------------------------------------------------------------------------------
// MAIN
//------------------------------------------------------------------------------
int main() {
//INIT
LED1off();
ThisThread::sleep_for(2000); //Initial pause, this is needed for softdevice to init, dont remove!! If we dont have this we get crashes
watchdog.configure(300.0); //5 mins //Do not set to less than 4500ms or can cause issues with softdevice
modem.off(false);
RTCticker.attach(&RTCtick, 1.0);
LPtimer.start();
button.fall(&buttonPress);
button.rise(&buttonRelease);
read_app_data_from_flash(&app_data);
dumpSettings();
//CHECK IF THIS IS RESET
//0x00000008 == lock up //0x00000004 == soft reset //0x00000002 == watchdog //0x00000001 == button/hardreset
if (NRF_POWER->RESETREAS != 0xffffffff) {
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();}
break;
case 0x00000002 :
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();}
break;
case 0x00000008 :
if(RET_debug){debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"RR:LU\n");debug_exe();}
break;
}
NRF_POWER->RESETREAS = 0xffffffff;
}
//CHECK FOR FIRST BOOT
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) { LED1errorCode(10,2);}
addToExceptionString("FR");
}
//MAIN LOOP
while(true) {
RET_asleep = false;
watchdogKick();
updateTemperatures();
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
RET_NetworkFailCount = 0;
RET_GPSFailCount = 0;
}
}
//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_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();
}
if (RET_coldBoot == false && RET_RTCunixtime > RET_debug_offat) {
debug_prep();snprintf(GLOBAL_debug_buffer, sizeof(GLOBAL_debug_buffer),"DEBUGGING OFF\n");debug_exe();
RET_debug = false;
}
}
//STATE ENGINE
mainStateEngine();
//LOG FIRST RUN - BOOTLOADER COMMS
if (RET_coldBoot) {
recordFirmwareAsValid();
RET_coldBoot = 0;
}
//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();
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);
}
}