@@ -1,50 +1,50 @@ | |||
#pragma once | |||
#include "Debug.h" | |||
#include "Alerts.h" | |||
#include "Config.h" | |||
#include "Rtc.h" | |||
#define LOGGER_NAME "Alerts" | |||
namespace alerts { | |||
uint8_t getTriggered(PositionEntryMetadata &metadata) { | |||
config_t* config = &config::main::value; | |||
uint8_t active = 0; | |||
if (metadata.batteryLevel <= config->alertBatteryLevel1) bitSet(active, ALERT_BATTERY_LEVEL_1); | |||
if (metadata.batteryLevel <= config->alertBatteryLevel2) bitSet(active, ALERT_BATTERY_LEVEL_2); | |||
if (metadata.temperature == ALERT_SUSPICIOUS_RTC_TEMPERATURE) bitSet(active, ALERT_RTC_TEMPERATURE_FAILURE); | |||
if (!rtc::isAccurate()) bitSet(active, ALERT_RTC_CLOCK_FAILURE); | |||
return config->activeAlerts ^ active; | |||
} | |||
void add(uint8_t mask) { | |||
config_t* config = &config::main::value; | |||
uint8_t active = config->activeAlerts; | |||
active |= mask; | |||
if (config->activeAlerts == active) return; //save a write to eeprom if there is no change | |||
config->activeAlerts = active; | |||
config::main::save(); | |||
} | |||
void clear(PositionEntryMetadata &metadata) { | |||
config_t* config = &config::main::value; | |||
uint8_t clearMask = 0; | |||
uint8_t active = config->activeAlerts; | |||
if (metadata.batteryLevel >= config->alertBatteryLevelClear) clearMask |= _BV(ALERT_BATTERY_LEVEL_1) | _BV(ALERT_BATTERY_LEVEL_2); | |||
if (metadata.temperature != ALERT_SUSPICIOUS_RTC_TEMPERATURE) bitSet(clearMask, ALERT_RTC_TEMPERATURE_FAILURE); | |||
if (rtc::isAccurate()) bitSet(clearMask, ALERT_RTC_CLOCK_FAILURE); | |||
active &= ~clearMask; | |||
if (config->activeAlerts == active) return; //save a write to eeprom if there is no change | |||
config->activeAlerts = active; | |||
config::main::save(); | |||
} | |||
} | |||
#pragma once | |||
#include "Alerts.h" | |||
#include "Config.h" | |||
#include "Rtc.h" | |||
#include "Logging.h" | |||
#define LOGGER_NAME "Alerts" | |||
namespace alerts { | |||
uint8_t getTriggered(PositionEntryMetadata &metadata) { | |||
config_t* config = &config::main::value; | |||
uint8_t active = 0; | |||
if (metadata.batteryLevel <= config->alertBatteryLevel1) bitSet(active, ALERT_BATTERY_LEVEL_1); | |||
if (metadata.batteryLevel <= config->alertBatteryLevel2) bitSet(active, ALERT_BATTERY_LEVEL_2); | |||
if (metadata.temperature == ALERT_SUSPICIOUS_RTC_TEMPERATURE) bitSet(active, ALERT_RTC_TEMPERATURE_FAILURE); | |||
if (!rtc::isAccurate()) bitSet(active, ALERT_RTC_CLOCK_FAILURE); | |||
return config->activeAlerts ^ active; | |||
} | |||
void add(uint8_t mask) { | |||
config_t* config = &config::main::value; | |||
uint8_t active = config->activeAlerts; | |||
active |= mask; | |||
if (config->activeAlerts == active) return; //save a write to eeprom if there is no change | |||
config->activeAlerts = active; | |||
config::main::save(); | |||
} | |||
void clear(PositionEntryMetadata &metadata) { | |||
config_t* config = &config::main::value; | |||
uint8_t clearMask = 0; | |||
uint8_t active = config->activeAlerts; | |||
if (metadata.batteryLevel >= config->alertBatteryLevelClear) clearMask |= _BV(ALERT_BATTERY_LEVEL_1) | _BV(ALERT_BATTERY_LEVEL_2); | |||
if (metadata.temperature != ALERT_SUSPICIOUS_RTC_TEMPERATURE) bitSet(clearMask, ALERT_RTC_TEMPERATURE_FAILURE); | |||
if (rtc::isAccurate()) bitSet(clearMask, ALERT_RTC_CLOCK_FAILURE); | |||
active &= ~clearMask; | |||
if (config->activeAlerts == active) return; //save a write to eeprom if there is no change | |||
config->activeAlerts = active; | |||
config::main::save(); | |||
} | |||
} |
@@ -1,86 +1,86 @@ | |||
#include "Config.h" | |||
#include "Debug.h" | |||
#include "Hardware.h" | |||
#define LOGGER_NAME "Config" | |||
namespace config { | |||
namespace main { | |||
config_t value; | |||
namespace details { | |||
void read() { | |||
VERBOSE("read"); | |||
hardware::i2c::powerOn(); | |||
hardware::i2c::eeprom.readBlock(CONFIG_ADDR, value); | |||
if (CONFIG_SEED != value.seed) reset(); //todo : reset network if seed for network is not right | |||
hardware::i2c::powerOff(); | |||
NOTICE_FORMAT("read", "%d, %s, %d, %d, %d, %d, %d, %B, %s", value.seed, value.version, value.firstEntry, value.lastEntry, value.alertBatteryLevel1, value.alertBatteryLevel2, value.alertBatteryLevelClear, value.activeAlerts, value.contactPhone); | |||
#if BACKUP_ENABLE_NETWORK | |||
NOTICE_FORMAT("read", "%d, %d, %s, %s", value.network.saveThreshold, value.network.lastSavedEntry, value.network.apn, value.network.url); | |||
//networkConfig_t c = { | |||
// POSITIONS_CONFIG_NET_DEFAULT_SAVE_THRESHOLD, | |||
// 0xFFFF, | |||
// POSITIONS_CONFIG_NET_DEFAULT_APN, | |||
// POSITIONS_CONFIG_NET_DEFAULT_URL, | |||
//}; | |||
//value.network = c; | |||
#endif | |||
/*strcpy_P(value.version, PSTR(VERSION)); | |||
value.alertBatteryLevel1 = CONFIG_DEFAULT_BATTERY_ALERT_LEVEL1; | |||
value.alertBatteryLevel2 = CONFIG_DEFAULT_BATTERY_ALERT_LEVEL2; | |||
value.alertBatteryLevelClear = CONFIG_DEFAULT_BATTERY_ALERT_CLEAR; | |||
value.activeAlerts = CONFIG_DEFAULT_ACTIVE_ALERTS; | |||
strcpy_P(config.contactPhone, PSTR(CONFIG_DEFAULT_CONTACT_PHONE));*/ | |||
} | |||
void write() { | |||
NOTICE_FORMAT("write", "%d, %s, %d, %d, %d, %d, %d, %B, %s", value.seed, value.version, value.firstEntry, value.lastEntry, value.alertBatteryLevel1, value.alertBatteryLevel2, value.alertBatteryLevelClear, value.activeAlerts, value.contactPhone); | |||
#if BACKUP_ENABLE_NETWORK | |||
NOTICE_FORMAT("write", "%d, %d, %s, %s", value.network.saveThreshold, value.network.lastSavedEntry, value.network.apn, value.network.url); | |||
#endif | |||
hardware::i2c::powerOn(); | |||
int written = hardware::i2c::eeprom.writeBlock(CONFIG_ADDR, value); | |||
hardware::i2c::powerOff(); | |||
} | |||
} | |||
void setup() { | |||
details::read(); | |||
//details::write(); | |||
} | |||
void save() { | |||
details::write(); | |||
} | |||
void reset() { | |||
VERBOSE("reset"); | |||
config_t config = {}; | |||
config.seed = CONFIG_SEED; | |||
strcpy_P(config.version, PSTR(VERSION)); | |||
config.firstEntry = config.lastEntry = 0xFFFF; | |||
config.alertBatteryLevel1 = CONFIG_DEFAULT_BATTERY_ALERT_LEVEL1; | |||
config.alertBatteryLevel2 = CONFIG_DEFAULT_BATTERY_ALERT_LEVEL2; | |||
config.alertBatteryLevelClear = CONFIG_DEFAULT_BATTERY_ALERT_CLEAR; | |||
config.activeAlerts = CONFIG_DEFAULT_ACTIVE_ALERTS; | |||
strcpy_P(config.contactPhone, PSTR(CONFIG_DEFAULT_CONTACT_PHONE)); | |||
#if BACKUP_ENABLE_NETWORK | |||
config.network.saveThreshold = POSITIONS_CONFIG_NET_DEFAULT_SAVE_THRESHOLD; | |||
config.network.lastSavedEntry = 0xFFFF; | |||
strcpy_P(config.network.apn, PSTR(POSITIONS_CONFIG_NET_DEFAULT_APN)); | |||
strcpy_P(config.network.url, PSTR(POSITIONS_CONFIG_NET_DEFAULT_URL)); | |||
#endif | |||
value = config; | |||
save(); | |||
} | |||
} | |||
#include "Config.h" | |||
#include "Hardware.h" | |||
#include "Logging.h" | |||
#define LOGGER_NAME "Config" | |||
namespace config { | |||
namespace main { | |||
config_t value; | |||
namespace details { | |||
void read() { | |||
VERBOSE("read"); | |||
hardware::i2c::powerOn(); | |||
hardware::i2c::eeprom.readBlock(CONFIG_ADDR, value); | |||
if (CONFIG_SEED != value.seed) reset(); //todo : reset network if seed for network is not right | |||
hardware::i2c::powerOff(); | |||
NOTICE_FORMAT("read", "%d, %s, %d, %d, %d, %d, %d, %B, %s", value.seed, value.version, value.firstEntry, value.lastEntry, value.alertBatteryLevel1, value.alertBatteryLevel2, value.alertBatteryLevelClear, value.activeAlerts, value.contactPhone); | |||
#if BACKUP_ENABLE_NETWORK | |||
NOTICE_FORMAT("read", "%d, %d, %s, %s", value.network.saveThreshold, value.network.lastSavedEntry, value.network.apn, value.network.url); | |||
//networkConfig_t c = { | |||
// POSITIONS_CONFIG_NET_DEFAULT_SAVE_THRESHOLD, | |||
// 0xFFFF, | |||
// POSITIONS_CONFIG_NET_DEFAULT_APN, | |||
// POSITIONS_CONFIG_NET_DEFAULT_URL, | |||
//}; | |||
//value.network = c; | |||
#endif | |||
/*strcpy_P(value.version, PSTR(VERSION)); | |||
value.alertBatteryLevel1 = CONFIG_DEFAULT_BATTERY_ALERT_LEVEL1; | |||
value.alertBatteryLevel2 = CONFIG_DEFAULT_BATTERY_ALERT_LEVEL2; | |||
value.alertBatteryLevelClear = CONFIG_DEFAULT_BATTERY_ALERT_CLEAR; | |||
value.activeAlerts = CONFIG_DEFAULT_ACTIVE_ALERTS; | |||
strcpy_P(config.contactPhone, PSTR(CONFIG_DEFAULT_CONTACT_PHONE));*/ | |||
} | |||
void write() { | |||
NOTICE_FORMAT("write", "%d, %s, %d, %d, %d, %d, %d, %B, %s", value.seed, value.version, value.firstEntry, value.lastEntry, value.alertBatteryLevel1, value.alertBatteryLevel2, value.alertBatteryLevelClear, value.activeAlerts, value.contactPhone); | |||
#if BACKUP_ENABLE_NETWORK | |||
NOTICE_FORMAT("write", "%d, %d, %s, %s", value.network.saveThreshold, value.network.lastSavedEntry, value.network.apn, value.network.url); | |||
#endif | |||
hardware::i2c::powerOn(); | |||
int written = hardware::i2c::eeprom.writeBlock(CONFIG_ADDR, value); | |||
hardware::i2c::powerOff(); | |||
} | |||
} | |||
void setup() { | |||
details::read(); | |||
//details::write(); | |||
} | |||
void save() { | |||
details::write(); | |||
} | |||
void reset() { | |||
VERBOSE("reset"); | |||
config_t config = {}; | |||
config.seed = CONFIG_SEED; | |||
strcpy_P(config.version, PSTR(VERSION)); | |||
config.firstEntry = config.lastEntry = 0xFFFF; | |||
config.alertBatteryLevel1 = CONFIG_DEFAULT_BATTERY_ALERT_LEVEL1; | |||
config.alertBatteryLevel2 = CONFIG_DEFAULT_BATTERY_ALERT_LEVEL2; | |||
config.alertBatteryLevelClear = CONFIG_DEFAULT_BATTERY_ALERT_CLEAR; | |||
config.activeAlerts = CONFIG_DEFAULT_ACTIVE_ALERTS; | |||
strcpy_P(config.contactPhone, PSTR(CONFIG_DEFAULT_CONTACT_PHONE)); | |||
#if BACKUP_ENABLE_NETWORK | |||
config.network.saveThreshold = POSITIONS_CONFIG_NET_DEFAULT_SAVE_THRESHOLD; | |||
config.network.lastSavedEntry = 0xFFFF; | |||
strcpy_P(config.network.apn, PSTR(POSITIONS_CONFIG_NET_DEFAULT_APN)); | |||
strcpy_P(config.network.url, PSTR(POSITIONS_CONFIG_NET_DEFAULT_URL)); | |||
#endif | |||
value = config; | |||
save(); | |||
} | |||
} | |||
} |
@@ -1,160 +1,161 @@ | |||
#include "Core.h" | |||
#include "Config.h" | |||
#include "Flash.h" | |||
#include "Alerts.h" | |||
#define LOGGER_NAME "Core" | |||
#define SMS_BUFFER_SIZE 140 | |||
#define NO_ALERTS_NOTIFIED 0 | |||
using namespace utils; | |||
namespace core { | |||
uint16_t sleepTime = SLEEP_DEFAULT_TIME_SECONDS; | |||
uint8_t stoppedInARow = SLEEP_DEFAULT_STOPPED_THRESHOLD - 1; | |||
TRACKER_MOVING_STATE movingState = TRACKER_MOVING_STATE::MOVING; | |||
namespace details { | |||
void appendToSmsBuffer(char * buffer, const char * fmt, ...) { | |||
va_list args; | |||
va_start(args, fmt); | |||
size_t bufferLeft = SMS_BUFFER_SIZE - strlen(buffer); | |||
char * p = buffer + strlen(buffer); | |||
vsnprintf_P(p, bufferLeft, fmt, args); | |||
va_end(args); | |||
} | |||
} | |||
void main() { | |||
bool acquired = false; | |||
PositionEntryMetadata metadata; | |||
if(movingState >= TRACKER_MOVING_STATE::STOPPED) positions::prepareBackup(); | |||
acquired = positions::acquire(metadata); | |||
if (acquired) { | |||
positions::appendLast(metadata); | |||
movingState = updateSleepTime(); | |||
gps::preserveCurrentCoordinates(); | |||
} | |||
alerts::clear(metadata); | |||
alerts::add(notifyFailures(metadata)); | |||
if(movingState >= TRACKER_MOVING_STATE::STOPPED) { | |||
positions::doBackup(movingState == TRACKER_MOVING_STATE::STOPPED); //do not force on STATIC | |||
} | |||
if (acquired) updateRtcTime(); | |||
mainunit::deepSleep(sleepTime); | |||
} | |||
uint8_t notifyFailures(PositionEntryMetadata &metadata) { | |||
SIM808RegistrationStatus networkStatus; | |||
char buffer[SMS_BUFFER_SIZE]; | |||
const __FlashStringHelper * backupFailureString = F(" Backup battery failure ?"); | |||
bool notified = false; | |||
uint8_t triggered = alerts::getTriggered(metadata); | |||
if (!triggered) return NO_ALERTS_NOTIFIED; | |||
NOTICE_FORMAT("notifyFailures", "triggered : %B", triggered); | |||
network::powerOn(); | |||
networkStatus = network::waitForRegistered(NETWORK_DEFAULT_TOTAL_TIMEOUT_MS); | |||
if (network::isAvailable(networkStatus.stat)) { | |||
strncpy_P(buffer, PSTR("Alerts !"), SMS_BUFFER_SIZE); | |||
if (bitRead(triggered, ALERT_BATTERY_LEVEL_1) || bitRead(triggered, ALERT_BATTERY_LEVEL_2)) { | |||
details::appendToSmsBuffer(buffer, PSTR("\n- Battery at %d%%."), metadata.batteryLevel); | |||
} | |||
if (bitRead(triggered, ALERT_RTC_TEMPERATURE_FAILURE)) { | |||
details::appendToSmsBuffer(buffer, PSTR("\n- Temperature is %dC.%S"), metadata.temperature, backupFailureString); | |||
} | |||
if (bitRead(triggered, ALERT_RTC_CLOCK_FAILURE)) { | |||
details::appendToSmsBuffer(buffer, PSTR("\n- RTC was stopped.%S"), backupFailureString); | |||
} | |||
#if ALERTS_ON_SERIAL_IF_AVAILABLE | |||
if(Serial) { | |||
NOTICE_FORMAT("notifyFailure", "%s", buffer); | |||
notified = true; | |||
} | |||
else { | |||
#endif | |||
notified = network::sendSms(buffer); | |||
#if ALERTS_ON_SERIAL_IF_AVAILABLE | |||
} | |||
#endif | |||
if (!notified) NOTICE_MSG("notifyFailure", "SMS not sent !"); | |||
} | |||
network::powerOff(); | |||
return notified ? triggered : NO_ALERTS_NOTIFIED; //If not notified, the alerts state should not be persisted (so we can retry to notify them) | |||
} | |||
void updateRtcTime() { | |||
tmElements_t time; | |||
gps::getTime(time); | |||
rtc::setTime(time); | |||
} | |||
TRACKER_MOVING_STATE updateSleepTime() { | |||
TRACKER_MOVING_STATE state = TRACKER_MOVING_STATE::MOVING; | |||
uint8_t velocity = gps::getVelocity(); | |||
sleepTime = mapSleepTime(velocity); | |||
if (velocity < SLEEP_TIMING_MIN_MOVING_VELOCITY) { | |||
float distance = gps::getDistanceFromPrevious(); //did we missed positions because we were sleeping ? | |||
if (distance > GPS_DEFAULT_MISSED_POSITION_GAP_KM) stoppedInARow = 0; | |||
else stoppedInARow = min(stoppedInARow + 1, SLEEP_DEFAULT_STOPPED_THRESHOLD + 1); //avoid overflow on REALLY long stops | |||
if (stoppedInARow < SLEEP_DEFAULT_STOPPED_THRESHOLD) { | |||
sleepTime = SLEEP_DEFAULT_PAUSING_TIME_SECONDS; | |||
state = TRACKER_MOVING_STATE::PAUSED; | |||
} | |||
else if (stoppedInARow == SLEEP_DEFAULT_STOPPED_THRESHOLD) state = TRACKER_MOVING_STATE::STOPPED; | |||
else state = TRACKER_MOVING_STATE::STATIC; | |||
} | |||
else stoppedInARow = 0; | |||
NOTICE_FORMAT("updateSleepTime", "%dkmh => %d seconds", velocity, sleepTime); | |||
return state; | |||
} | |||
uint16_t mapSleepTime(uint8_t velocity) { | |||
uint16_t result; | |||
uint16_t currentTime = 0xFFFF; | |||
if (rtc::isAccurate()) { | |||
tmElements_t time; | |||
rtc::getTime(time); | |||
currentTime = SLEEP_TIMING_TIME(time.Hour, time.Minute); | |||
} | |||
for (uint8_t i = flash::getArraySize(config::defaultSleepTimings); i--;) { | |||
sleepTimings_t timing; | |||
flash::read(&config::defaultSleepTimings[i], timing); | |||
if (velocity < timing.speed) continue; | |||
if (currentTime != 0xFFFF && (currentTime < timing.timeMin || currentTime > timing.timeMax)) continue; | |||
result = timing.seconds; | |||
break; | |||
} | |||
VERBOSE_FORMAT("mapSleepTime", "%d,%d", velocity, result); | |||
return result; | |||
} | |||
#include "Core.h" | |||
#include "Config.h" | |||
#include "Flash.h" | |||
#include "Alerts.h" | |||
#include "Logging.h" | |||
#define LOGGER_NAME "Core" | |||
#define SMS_BUFFER_SIZE 140 | |||
#define NO_ALERTS_NOTIFIED 0 | |||
using namespace utils; | |||
namespace core { | |||
uint16_t sleepTime = SLEEP_DEFAULT_TIME_SECONDS; | |||
uint8_t stoppedInARow = SLEEP_DEFAULT_STOPPED_THRESHOLD - 1; | |||
TRACKER_MOVING_STATE movingState = TRACKER_MOVING_STATE::MOVING; | |||
namespace details { | |||
void appendToSmsBuffer(char * buffer, const char * fmt, ...) { | |||
va_list args; | |||
va_start(args, fmt); | |||
size_t bufferLeft = SMS_BUFFER_SIZE - strlen(buffer); | |||
char * p = buffer + strlen(buffer); | |||
vsnprintf_P(p, bufferLeft, fmt, args); | |||
va_end(args); | |||
} | |||
} | |||
void main() { | |||
bool acquired = false; | |||
PositionEntryMetadata metadata; | |||
if(movingState >= TRACKER_MOVING_STATE::STOPPED) positions::prepareBackup(); | |||
acquired = positions::acquire(metadata); | |||
if (acquired) { | |||
positions::appendLast(metadata); | |||
movingState = updateSleepTime(); | |||
gps::preserveCurrentCoordinates(); | |||
} | |||
alerts::clear(metadata); | |||
alerts::add(notifyFailures(metadata)); | |||
if(movingState >= TRACKER_MOVING_STATE::STOPPED) { | |||
positions::doBackup(movingState == TRACKER_MOVING_STATE::STOPPED); //do not force on STATIC | |||
} | |||
if (acquired) updateRtcTime(); | |||
mainunit::deepSleep(sleepTime); | |||
} | |||
uint8_t notifyFailures(PositionEntryMetadata &metadata) { | |||
SIM808RegistrationStatus networkStatus; | |||
char buffer[SMS_BUFFER_SIZE]; | |||
const __FlashStringHelper * backupFailureString = F(" Backup battery failure ?"); | |||
bool notified = false; | |||
uint8_t triggered = alerts::getTriggered(metadata); | |||
if (!triggered) return NO_ALERTS_NOTIFIED; | |||
NOTICE_FORMAT("notifyFailures", "triggered : %B", triggered); | |||
network::powerOn(); | |||
networkStatus = network::waitForRegistered(NETWORK_DEFAULT_TOTAL_TIMEOUT_MS); | |||
if (network::isAvailable(networkStatus.stat)) { | |||
strncpy_P(buffer, PSTR("Alerts !"), SMS_BUFFER_SIZE); | |||
if (bitRead(triggered, ALERT_BATTERY_LEVEL_1) || bitRead(triggered, ALERT_BATTERY_LEVEL_2)) { | |||
details::appendToSmsBuffer(buffer, PSTR("\n- Battery at %d%%."), metadata.batteryLevel); | |||
} | |||
if (bitRead(triggered, ALERT_RTC_TEMPERATURE_FAILURE)) { | |||
details::appendToSmsBuffer(buffer, PSTR("\n- Temperature is %dC.%S"), metadata.temperature, backupFailureString); | |||
} | |||
if (bitRead(triggered, ALERT_RTC_CLOCK_FAILURE)) { | |||
details::appendToSmsBuffer(buffer, PSTR("\n- RTC was stopped.%S"), backupFailureString); | |||
} | |||
#if ALERTS_ON_SERIAL_IF_AVAILABLE | |||
if(Serial) { | |||
NOTICE_FORMAT("notifyFailure", "%s", buffer); | |||
notified = true; | |||
} | |||
else { | |||
#endif | |||
notified = network::sendSms(buffer); | |||
#if ALERTS_ON_SERIAL_IF_AVAILABLE | |||
} | |||
#endif | |||
if (!notified) NOTICE_MSG("notifyFailure", "SMS not sent !"); | |||
} | |||
network::powerOff(); | |||
return notified ? triggered : NO_ALERTS_NOTIFIED; //If not notified, the alerts state should not be persisted (so we can retry to notify them) | |||
} | |||
void updateRtcTime() { | |||
tmElements_t time; | |||
gps::getTime(time); | |||
rtc::setTime(time); | |||
} | |||
TRACKER_MOVING_STATE updateSleepTime() { | |||
TRACKER_MOVING_STATE state = TRACKER_MOVING_STATE::MOVING; | |||
uint8_t velocity = gps::getVelocity(); | |||
sleepTime = mapSleepTime(velocity); | |||
if (velocity < SLEEP_TIMING_MIN_MOVING_VELOCITY) { | |||
float distance = gps::getDistanceFromPrevious(); //did we missed positions because we were sleeping ? | |||
if (distance > GPS_DEFAULT_MISSED_POSITION_GAP_KM) stoppedInARow = 0; | |||
else stoppedInARow = min(stoppedInARow + 1, SLEEP_DEFAULT_STOPPED_THRESHOLD + 1); //avoid overflow on REALLY long stops | |||
if (stoppedInARow < SLEEP_DEFAULT_STOPPED_THRESHOLD) { | |||
sleepTime = SLEEP_DEFAULT_PAUSING_TIME_SECONDS; | |||
state = TRACKER_MOVING_STATE::PAUSED; | |||
} | |||
else if (stoppedInARow == SLEEP_DEFAULT_STOPPED_THRESHOLD) state = TRACKER_MOVING_STATE::STOPPED; | |||
else state = TRACKER_MOVING_STATE::STATIC; | |||
} | |||
else stoppedInARow = 0; | |||
NOTICE_FORMAT("updateSleepTime", "%dkmh => %d seconds", velocity, sleepTime); | |||
return state; | |||
} | |||
uint16_t mapSleepTime(uint8_t velocity) { | |||
uint16_t result; | |||
uint16_t currentTime = 0xFFFF; | |||
if (rtc::isAccurate()) { | |||
tmElements_t time; | |||
rtc::getTime(time); | |||
currentTime = SLEEP_TIMING_TIME(time.Hour, time.Minute); | |||
} | |||
for (uint8_t i = flash::getArraySize(config::defaultSleepTimings); i--;) { | |||
sleepTimings_t timing; | |||
flash::read(&config::defaultSleepTimings[i], timing); | |||
if (velocity < timing.speed) continue; | |||
if (currentTime != 0xFFFF && (currentTime < timing.timeMin || currentTime > timing.timeMax)) continue; | |||
result = timing.seconds; | |||
break; | |||
} | |||
VERBOSE_FORMAT("mapSleepTime", "%d,%d", velocity, result); | |||
return result; | |||
} | |||
} |
@@ -2,12 +2,10 @@ | |||
#include <Arduino.h> | |||
#include "Debug.h" | |||
#include "Gps.h" | |||
#include "MainUnit.h" | |||
#include "Network.h" | |||
#include "Rtc.h" | |||
#include "config/Pins.h" | |||
#include "Positions.h" | |||
enum class TRACKER_MOVING_STATE : uint8_t { | |||
@@ -1,300 +1,291 @@ | |||
#include "Debug.h" | |||
#include "Flash.h" | |||
#include "Positions.h" | |||
#include "Core.h" | |||
#include "Alerts.h" | |||
#define LOGGER_NAME "Debug" | |||
#define MENU_ENTRY(name, text) const char MENU_##name[] PROGMEM = text | |||
const char FAKE_GPS_ENTRY[] PROGMEM = "1,1,20170924184842.000,49.454862,1.144537,71.900,2.70,172.6,1,,1.3,2.2,1.8,,11,7,,,37,,"; | |||
MENU_ENTRY(HEADER, "========================\n-- Menu --"); | |||
MENU_ENTRY(SEPARATOR, "----"); | |||
MENU_ENTRY(RUN, "[R] Run"); | |||
MENU_ENTRY(RUN_ONCE, "[r] Run once"); | |||
MENU_ENTRY(RAM, "[f] Free RAM"); | |||
MENU_ENTRY(READ_BATTERY, "[b] Read battery"); | |||
MENU_ENTRY(GPS_ON, "[G] GPS On"); | |||
MENU_ENTRY(GPS_OFF, "[g] GPS Off"); | |||
MENU_ENTRY(GPS_GET, "[L] Get GPS position"); | |||
MENU_ENTRY(GPS_SET, "[l] Set last GPS position"); | |||
MENU_ENTRY(RTC_SET, "[T] Get RTC time"); | |||
MENU_ENTRY(RTC_GET, "[t] Set RTC time"); | |||
MENU_ENTRY(EEPROM_GET_CONFIG, "[C] Get EEPROM config"); | |||
MENU_ENTRY(EEPROM_RESET_CONFIG, "[c] Reset EEPROM config"); | |||
MENU_ENTRY(EEPROM_GET_CONTENT, "[E] Get EEPROM content"); | |||
MENU_ENTRY(EEPROM_GET_ENTRIES, "[P] Get EEPROM entries"); | |||
MENU_ENTRY(EEPROM_GET_LAST_ENTRY, "[p] Get EEPROM last entry"); | |||
MENU_ENTRY(EEPROM_ADD_ENTRY, "[a] Add last entry to EEPROM"); | |||
MENU_ENTRY(EEPROM_BACKUP_ENTRIES, "[B] Backup EEPROM entries"); | |||
MENU_ENTRY(NOTIFY_FAILURES, "[F] Notify failures"); | |||
MENU_ENTRY(CLEAR_ALERTS, "[A] Clear alerts"); | |||
MENU_ENTRY(SLEEP_DEEP, "[s] Deep sleep for 10s"); | |||
MENU_ENTRY(QUESTION, "?"); | |||
const uint8_t commandIdMapping[] PROGMEM = { | |||
'R', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::RUN), | |||
'r', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::ONCE), | |||
'f', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::RAM), | |||
'b', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::BATTERY), | |||
'G', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::GPS_ON), | |||
'g', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::GPS_OFF), | |||
'L', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::GPS_GET), | |||
'l', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::GPS_SET), | |||
'T', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::RTC_GET), | |||
't', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::RTC_SET), | |||
'C', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_CONFIG), | |||
'c', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_RESET_CONFIG), | |||
'E', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_CONTENT), | |||
'P', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_ENTRIES), | |||
'p', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_LAST_ENTRY), | |||
'a', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_ADD_ENTRY), | |||
'B', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_BACKUP_ENTRIES), | |||
'F', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::NOTIFY_FAILURES), | |||
'A', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::CLEAR_ALERTS), | |||
's', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP), | |||
}; | |||
const char * const MENU_ENTRIES[] PROGMEM = { | |||
MENU_HEADER, | |||
MENU_RUN, | |||
MENU_RUN_ONCE, | |||
MENU_SEPARATOR, | |||
MENU_RAM, | |||
MENU_READ_BATTERY, | |||
MENU_SEPARATOR, | |||
MENU_GPS_ON, | |||
MENU_GPS_OFF, | |||
MENU_GPS_GET, | |||
MENU_GPS_SET, | |||
MENU_SEPARATOR, | |||
MENU_RTC_SET, | |||
MENU_RTC_GET, | |||
MENU_SEPARATOR, | |||
MENU_EEPROM_GET_CONFIG, | |||
MENU_EEPROM_RESET_CONFIG, | |||
MENU_EEPROM_GET_CONTENT, | |||
MENU_EEPROM_GET_ENTRIES, | |||
MENU_EEPROM_GET_LAST_ENTRY, | |||
MENU_EEPROM_ADD_ENTRY, | |||
MENU_EEPROM_BACKUP_ENTRIES, | |||
MENU_SEPARATOR, | |||
MENU_NOTIFY_FAILURES, | |||
MENU_CLEAR_ALERTS, | |||
MENU_SEPARATOR, | |||
MENU_SLEEP_DEEP, | |||
MENU_QUESTION | |||
}; | |||
static const PositionEntryMetadata fakeMetadata PROGMEM = { | |||
100, | |||
3800, | |||
10, | |||
20, | |||
SIM808_GPS_STATUS::ACCURATE_FIX | |||
}; | |||
int freeRam2() { // dirty hack because putting it in namespace doesn't compile | |||
extern int __heap_start, *__brkval; | |||
int v; | |||
return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval); | |||
} | |||
using namespace utils; | |||
namespace debug { | |||
namespace details { | |||
inline void displayPosition(PositionEntry entry) { | |||
Log.notice(F("%d,%d,%d,%d,%d,%s"), | |||
entry.metadata.batteryLevel, | |||
entry.metadata.batteryVoltage, | |||
entry.metadata.temperature, | |||
static_cast<uint8_t>(entry.metadata.status), | |||
entry.metadata.timeToFix, | |||
entry.position); | |||
} | |||
} | |||
int freeRam() { | |||
return freeRam2(); | |||
} | |||
void displayFreeRam() { | |||
Log.notice(F("RAM: %d\n"), freeRam()); | |||
} | |||
GPSTRACKER_DEBUG_COMMAND parseCommand(char id) { | |||
size_t mappingArraySize = flash::getArraySize(commandIdMapping); | |||
char commandId; | |||
for (uint8_t i = 0; i < mappingArraySize; i += 2) { | |||
commandId = pgm_read_byte_near(commandIdMapping + i); | |||
if (commandId == id) return static_cast<GPSTRACKER_DEBUG_COMMAND>(pgm_read_byte_near(commandIdMapping + i + 1)); | |||
} | |||
return GPSTRACKER_DEBUG_COMMAND::NONE; | |||
} | |||
GPSTRACKER_DEBUG_COMMAND menu(uint16_t timeout) { | |||
GPSTRACKER_DEBUG_COMMAND command; | |||
size_t menuSize = flash::getArraySize(MENU_ENTRIES); | |||
uint8_t intermediate_timeout = 50; | |||
do { | |||
for (uint8_t i = 0; i < menuSize; i++) { | |||
Serial.println(reinterpret_cast<const __FlashStringHelper *>(pgm_read_word_near(&MENU_ENTRIES[i]))); | |||
} | |||
while (!Serial.available()) { | |||
if (timeout > 0) { | |||
delay(intermediate_timeout); | |||
timeout -= intermediate_timeout; | |||
if (timeout <= 0) { | |||
NOTICE_MSG("menu", "Timeout expired."); | |||
return GPSTRACKER_DEBUG_COMMAND::RUN; | |||
} | |||
} | |||
} | |||
command = parseCommand(Serial.read()); | |||
while (Serial.available()) Serial.read(); //flushing input | |||
} while (command == GPSTRACKER_DEBUG_COMMAND::NONE); | |||
return command; | |||
} | |||
void getAndDisplayGpsPosition() { | |||
SIM808_GPS_STATUS gpsStatus = gps::acquireCurrentPosition(GPS_DEFAULT_TOTAL_TIMEOUT_MS); | |||
NOTICE_FORMAT("getAndDisplayGpsPosition", "%d %s", gpsStatus, gps::lastPosition); | |||
} | |||
void setFakeGpsPosition() { | |||
strlcpy_P(gps::lastPosition, FAKE_GPS_ENTRY, GPS_POSITION_SIZE); | |||
NOTICE_FORMAT("setFakeGpsPosition", "Last position set to : %s", gps::lastPosition); | |||
NOTICE_FORMAT("setFakeGpsPosition", "Speed : %d", gps::getVelocity()); | |||
NOTICE_FORMAT("setFakeGpsPosition", "Sleep time : %d", core::mapSleepTime(gps::getVelocity())); | |||
} | |||
void getAndDisplayBattery() { | |||
hardware::sim808::powerOn(); | |||
SIM808ChargingStatus status = hardware::sim808::device.getChargingState(); | |||
hardware::sim808::powerOff(); | |||
NOTICE_FORMAT("getAndDisplayBattery", "%d %d%% %dmV", status.state, status.level, status.voltage); | |||
} | |||
void getAndDisplayRtcTime() { | |||
tmElements_t time; | |||
rtc::getTime(time); | |||
NOTICE_FORMAT("getAndDisplayRtcTime", "%d/%d/%d %d:%d:%d %t %d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second, rtc::isAccurate(), rtc::getTemperature()); | |||
} | |||
void setRtcTime() { | |||
tmElements_t time; | |||
gps::getTime(time); | |||
rtc::setTime(time); | |||
} | |||
void getAndDisplaySleepTimes() { | |||
size_t arraySize = flash::getArraySize(config::defaultSleepTimings); | |||
sleepTimings_t maxSpeedTiming; | |||
utils::flash::read(&config::defaultSleepTimings[arraySize - 1], maxSpeedTiming); | |||
for (int i = 0; i <= maxSpeedTiming.speed; i++) { | |||
core::mapSleepTime(i); | |||
} | |||
NOTICE_MSG("getAndDisplaySleepTimes", "Done"); | |||
} | |||
void getAndDisplayEepromConfig() { | |||
config::main::setup(); //forcing read again | |||
} | |||
void getAndDisplayEepromContent() { | |||
char buffer[128]; | |||
hardware::i2c::powerOn(); | |||
for (int i = 0; i < 8; i++) { | |||
hardware::i2c::eeprom.read(128 * i, buffer, 128); | |||
for (int i = 0; i < 128; i++) { | |||
Serial.print(buffer[i], HEX); | |||
} | |||
} | |||
Serial.println(); | |||
hardware::i2c::powerOff(); | |||
NOTICE_MSG("getAndDisplayEepromContent", "Done"); | |||
} | |||
void getAndDisplayEepromPositions() { | |||
uint16_t currentEntryIndex = config::main::value.firstEntry; | |||
PositionEntry currentEntry; | |||
hardware::i2c::powerOn(); | |||
do { | |||
if (!positions::get(currentEntryIndex, currentEntry)) break; | |||
details::displayPosition(currentEntry); | |||
} while (positions::moveNext(currentEntryIndex)); | |||
hardware::i2c::powerOff(); | |||
} | |||
void getAndDisplayEepromLastPosition() { | |||
uint16_t lastEntryIndex = config::main::value.lastEntry; | |||
PositionEntry lastEntry; | |||
if(positions::get(lastEntryIndex, lastEntry)) details::displayPosition(lastEntry); | |||
else Log.notice(F("No position recorded\n")); | |||
} | |||
void addLastPositionToEeprom() { | |||
hardware::sim808::powerOn(); | |||
SIM808ChargingStatus status = hardware::sim808::device.getChargingState(); | |||
hardware::sim808::powerOff(); | |||
PositionEntryMetadata metadata = { | |||
status.level, | |||
status.voltage, | |||
rtc::getTemperature(), | |||
0, | |||
SIM808_GPS_STATUS::OFF | |||
}; | |||
for(int i = 0; i < 10; i++) positions::appendLast(metadata); | |||
} | |||
void notifyFailures() { | |||
PositionEntryMetadata metadata = {}; | |||
flash::read(&fakeMetadata, metadata); | |||
metadata.batteryLevel = 1; | |||
metadata.temperature = ALERT_SUSPICIOUS_RTC_TEMPERATURE; | |||
uint8_t alerts = core::notifyFailures(metadata); | |||
NOTICE_FORMAT("notifyFailures", "result : %B", alerts); | |||
alerts::add(alerts); | |||
} | |||
void clearAlerts() { | |||
PositionEntryMetadata metadata = {}; | |||
flash::read(&fakeMetadata, metadata); | |||
alerts::clear(metadata); | |||
} | |||
#include "Debug.h" | |||
#include "MainUnit.h" | |||
#include "Flash.h" | |||
#include "Positions.h" | |||
#include "Core.h" | |||
#include "Alerts.h" | |||
#include "Logging.h" | |||
#define LOGGER_NAME "Debug" | |||
#define MENU_ENTRY(name, text) const char MENU_##name[] PROGMEM = text | |||
const char FAKE_GPS_ENTRY[] PROGMEM = "1,1,20170924184842.000,49.454862,1.144537,71.900,2.70,172.6,1,,1.3,2.2,1.8,,11,7,,,37,,"; | |||
MENU_ENTRY(HEADER, "========================\n-- Menu --"); | |||
MENU_ENTRY(SEPARATOR, "----"); | |||
MENU_ENTRY(RUN, "[R] Run"); | |||
MENU_ENTRY(RUN_ONCE, "[r] Run once"); | |||
MENU_ENTRY(RAM, "[f] Free RAM"); | |||
MENU_ENTRY(READ_BATTERY, "[b] Read battery"); | |||
MENU_ENTRY(GPS_ON, "[G] GPS On"); | |||
MENU_ENTRY(GPS_OFF, "[g] GPS Off"); | |||
MENU_ENTRY(GPS_GET, "[L] Get GPS position"); | |||
MENU_ENTRY(GPS_SET, "[l] Set last GPS position"); | |||
MENU_ENTRY(RTC_SET, "[T] Get RTC time"); | |||
MENU_ENTRY(RTC_GET, "[t] Set RTC time"); | |||
MENU_ENTRY(EEPROM_GET_CONFIG, "[C] Get EEPROM config"); | |||
MENU_ENTRY(EEPROM_RESET_CONFIG, "[c] Reset EEPROM config"); | |||
MENU_ENTRY(EEPROM_GET_CONTENT, "[E] Get EEPROM content"); | |||
MENU_ENTRY(EEPROM_GET_ENTRIES, "[P] Get EEPROM entries"); | |||
MENU_ENTRY(EEPROM_GET_LAST_ENTRY, "[p] Get EEPROM last entry"); | |||
MENU_ENTRY(EEPROM_ADD_ENTRY, "[a] Add last entry to EEPROM"); | |||
MENU_ENTRY(EEPROM_BACKUP_ENTRIES, "[B] Backup EEPROM entries"); | |||
MENU_ENTRY(NOTIFY_FAILURES, "[F] Notify failures"); | |||
MENU_ENTRY(CLEAR_ALERTS, "[A] Clear alerts"); | |||
MENU_ENTRY(SLEEP_DEEP, "[s] Deep sleep for 10s"); | |||
MENU_ENTRY(QUESTION, "?"); | |||
const uint8_t commandIdMapping[] PROGMEM = { | |||
'R', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::RUN), | |||
'r', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::ONCE), | |||
'f', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::RAM), | |||
'b', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::BATTERY), | |||
'G', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::GPS_ON), | |||
'g', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::GPS_OFF), | |||
'L', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::GPS_GET), | |||
'l', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::GPS_SET), | |||
'T', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::RTC_GET), | |||
't', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::RTC_SET), | |||
'C', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_CONFIG), | |||
'c', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_RESET_CONFIG), | |||
'E', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_CONTENT), | |||
'P', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_ENTRIES), | |||
'p', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_LAST_ENTRY), | |||
'a', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_ADD_ENTRY), | |||
'B', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_BACKUP_ENTRIES), | |||
'F', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::NOTIFY_FAILURES), | |||
'A', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::CLEAR_ALERTS), | |||
's', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP), | |||
}; | |||
const char * const MENU_ENTRIES[] PROGMEM = { | |||
MENU_HEADER, | |||
MENU_RUN, | |||
MENU_RUN_ONCE, | |||
MENU_SEPARATOR, | |||
MENU_RAM, | |||
MENU_READ_BATTERY, | |||
MENU_SEPARATOR, | |||
MENU_GPS_ON, | |||
MENU_GPS_OFF, | |||
MENU_GPS_GET, | |||
MENU_GPS_SET, | |||
MENU_SEPARATOR, | |||
MENU_RTC_SET, | |||
MENU_RTC_GET, | |||
MENU_SEPARATOR, | |||
MENU_EEPROM_GET_CONFIG, | |||
MENU_EEPROM_RESET_CONFIG, | |||
MENU_EEPROM_GET_CONTENT, | |||
MENU_EEPROM_GET_ENTRIES, | |||
MENU_EEPROM_GET_LAST_ENTRY, | |||
MENU_EEPROM_ADD_ENTRY, | |||
MENU_EEPROM_BACKUP_ENTRIES, | |||
MENU_SEPARATOR, | |||
MENU_NOTIFY_FAILURES, | |||
MENU_CLEAR_ALERTS, | |||
MENU_SEPARATOR, | |||
MENU_SLEEP_DEEP, | |||
MENU_QUESTION | |||
}; | |||
static const PositionEntryMetadata fakeMetadata PROGMEM = { | |||
100, | |||
3800, | |||
10, | |||
20, | |||
SIM808_GPS_STATUS::ACCURATE_FIX | |||
}; | |||
using namespace utils; | |||
namespace debug { | |||
namespace details { | |||
inline void displayPosition(PositionEntry entry) { | |||
Log.notice(F("%d,%d,%d,%d,%d,%s"), | |||
entry.metadata.batteryLevel, | |||
entry.metadata.batteryVoltage, | |||
entry.metadata.temperature, | |||
static_cast<uint8_t>(entry.metadata.status), | |||
entry.metadata.timeToFix, | |||
entry.position); | |||
} | |||
} | |||
void displayFreeRam() { | |||
Log.notice(F("RAM: %d\n"), mainunit::freeRam()); | |||
} | |||
GPSTRACKER_DEBUG_COMMAND parseCommand(char id) { | |||
size_t mappingArraySize = flash::getArraySize(commandIdMapping); | |||
char commandId; | |||
for (uint8_t i = 0; i < mappingArraySize; i += 2) { | |||
commandId = pgm_read_byte_near(commandIdMapping + i); | |||
if (commandId == id) return static_cast<GPSTRACKER_DEBUG_COMMAND>(pgm_read_byte_near(commandIdMapping + i + 1)); | |||
} | |||
return GPSTRACKER_DEBUG_COMMAND::NONE; | |||
} | |||
GPSTRACKER_DEBUG_COMMAND menu(uint16_t timeout) { | |||
GPSTRACKER_DEBUG_COMMAND command; | |||
size_t menuSize = flash::getArraySize(MENU_ENTRIES); | |||
do { | |||
for (uint8_t i = 0; i < menuSize; i++) { | |||
Serial.println(reinterpret_cast<const __FlashStringHelper *>(pgm_read_word_near(&MENU_ENTRIES[i]))); | |||
} | |||
while (!Serial.available()) { | |||
if (timeout > 0) { | |||
delay(MENU_INTERMEDIATE_TIMEOUT); | |||
timeout -= MENU_INTERMEDIATE_TIMEOUT; | |||
if (timeout <= 0) { | |||
NOTICE_MSG("menu", "Timeout expired."); | |||
return GPSTRACKER_DEBUG_COMMAND::RUN; | |||
} | |||
} | |||
} | |||
command = parseCommand(Serial.read()); | |||
while (Serial.available()) Serial.read(); //flushing input | |||
} while (command == GPSTRACKER_DEBUG_COMMAND::NONE); | |||
return command; | |||
} | |||
void getAndDisplayGpsPosition() { | |||
SIM808_GPS_STATUS gpsStatus = gps::acquireCurrentPosition(GPS_DEFAULT_TOTAL_TIMEOUT_MS); | |||
NOTICE_FORMAT("getAndDisplayGpsPosition", "%d %s", gpsStatus, gps::lastPosition); | |||
} | |||
void setFakeGpsPosition() { | |||
strlcpy_P(gps::lastPosition, FAKE_GPS_ENTRY, GPS_POSITION_SIZE); | |||
NOTICE_FORMAT("setFakeGpsPosition", "Last position set to : %s", gps::lastPosition); | |||
NOTICE_FORMAT("setFakeGpsPosition", "Speed : %d", gps::getVelocity()); | |||
NOTICE_FORMAT("setFakeGpsPosition", "Sleep time : %d", core::mapSleepTime(gps::getVelocity())); | |||
} | |||
void getAndDisplayBattery() { | |||
hardware::sim808::powerOn(); | |||
SIM808ChargingStatus status = hardware::sim808::device.getChargingState(); | |||
hardware::sim808::powerOff(); | |||
NOTICE_FORMAT("getAndDisplayBattery", "%d %d%% %dmV", status.state, status.level, status.voltage); | |||
} | |||
void getAndDisplayRtcTime() { | |||
tmElements_t time; | |||
rtc::getTime(time); | |||
NOTICE_FORMAT("getAndDisplayRtcTime", "%d/%d/%d %d:%d:%d %t %d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second, rtc::isAccurate(), rtc::getTemperature()); | |||
} | |||
void setRtcTime() { | |||
tmElements_t time; | |||
gps::getTime(time); | |||
rtc::setTime(time); | |||
} | |||
void getAndDisplaySleepTimes() { | |||
size_t arraySize = flash::getArraySize(config::defaultSleepTimings); | |||
sleepTimings_t maxSpeedTiming; | |||
utils::flash::read(&config::defaultSleepTimings[arraySize - 1], maxSpeedTiming); | |||
for (int i = 0; i <= maxSpeedTiming.speed; i++) { | |||
core::mapSleepTime(i); | |||
} | |||
NOTICE_MSG("getAndDisplaySleepTimes", "Done"); | |||
} | |||
void getAndDisplayEepromConfig() { | |||
config::main::setup(); //forcing read again | |||
} | |||
void getAndDisplayEepromContent() { | |||
char buffer[128]; | |||
hardware::i2c::powerOn(); | |||
for (int i = 0; i < 8; i++) { | |||
hardware::i2c::eeprom.read(128 * i, buffer, 128); | |||
for (int i = 0; i < 128; i++) { | |||
Serial.print(buffer[i], HEX); | |||
} | |||
} | |||
Serial.println(); | |||
hardware::i2c::powerOff(); | |||
NOTICE_MSG("getAndDisplayEepromContent", "Done"); | |||
} | |||
void getAndDisplayEepromPositions() { | |||
uint16_t currentEntryIndex = config::main::value.firstEntry; | |||
PositionEntry currentEntry; | |||
hardware::i2c::powerOn(); | |||
do { | |||
if (!positions::get(currentEntryIndex, currentEntry)) break; | |||
details::displayPosition(currentEntry); | |||
} while (positions::moveNext(currentEntryIndex)); | |||
hardware::i2c::powerOff(); | |||
} | |||
void getAndDisplayEepromLastPosition() { | |||
uint16_t lastEntryIndex = config::main::value.lastEntry; | |||
PositionEntry lastEntry; | |||
if(positions::get(lastEntryIndex, lastEntry)) details::displayPosition(lastEntry); | |||
else Log.notice(F("No position recorded\n")); | |||
} | |||
void addLastPositionToEeprom() { | |||
hardware::sim808::powerOn(); | |||
SIM808ChargingStatus status = hardware::sim808::device.getChargingState(); | |||
hardware::sim808::powerOff(); | |||
PositionEntryMetadata metadata = { | |||
status.level, | |||
status.voltage, | |||
rtc::getTemperature(), | |||
0, | |||
SIM808_GPS_STATUS::OFF | |||
}; | |||
for(int i = 0; i < 10; i++) positions::appendLast(metadata); | |||
} | |||
void notifyFailures() { | |||
PositionEntryMetadata metadata = {}; | |||
flash::read(&fakeMetadata, metadata); | |||
metadata.batteryLevel = 1; | |||
metadata.temperature = ALERT_SUSPICIOUS_RTC_TEMPERATURE; | |||
uint8_t alerts = core::notifyFailures(metadata); | |||
NOTICE_FORMAT("notifyFailures", "result : %B", alerts); | |||
alerts::add(alerts); | |||
} | |||
void clearAlerts() { | |||
PositionEntryMetadata metadata = {}; | |||
flash::read(&fakeMetadata, metadata); | |||
alerts::clear(metadata); | |||
} | |||
} |
@@ -1,61 +1,53 @@ | |||
#pragma once | |||
#include <Arduino.h> | |||
#include "Config.h" | |||
#include "Logging.h" | |||
#include "Core.h" | |||
#include "Hardware.h" | |||
#include "Gps.h" | |||
#include "Rtc.h" | |||
namespace debug { | |||
enum class GPSTRACKER_DEBUG_COMMAND : uint8_t { | |||
NONE, | |||
RUN, | |||
ONCE, | |||
RAM, | |||
BATTERY, | |||
GPS_ON, | |||
GPS_OFF, | |||
GPS_GET, | |||
GPS_SET, | |||
RTC_GET, | |||
RTC_SET, | |||
EEPROM_GET_CONFIG, | |||
EEPROM_RESET_CONFIG, | |||
EEPROM_GET_CONTENT, | |||
EEPROM_GET_LAST_ENTRY, | |||
EEPROM_GET_ENTRIES, | |||
EEPROM_ADD_ENTRY, | |||
EEPROM_BACKUP_ENTRIES, | |||
NOTIFY_FAILURES, | |||
CLEAR_ALERTS, | |||
SLEEP_DEEP | |||
}; | |||
int freeRam(); | |||
void displayFreeRam(); | |||
GPSTRACKER_DEBUG_COMMAND menu(uint16_t timeout); | |||
void getAndDisplayBattery(); | |||
void getAndDisplayGpsPosition(); | |||
void setFakeGpsPosition(); | |||
void getAndDisplayRtcTime(); | |||
void setRtcTime(); | |||
void getAndDisplaySleepTimes(); | |||
void getAndDisplayEepromConfig(); | |||
void getAndDisplayEepromContent(); | |||
void getAndDisplayEepromPositions(); | |||
void getAndDisplayEepromLastPosition(); | |||
void addLastPositionToEeprom(); | |||
void notifyFailures(); | |||
void clearAlerts(); | |||
} | |||
#pragma once | |||
#include <Arduino.h> | |||
namespace debug { | |||
enum class GPSTRACKER_DEBUG_COMMAND : uint8_t { | |||
NONE, | |||
RUN, | |||
ONCE, | |||
RAM, | |||
BATTERY, | |||
GPS_ON, | |||
GPS_OFF, | |||
GPS_GET, | |||
GPS_SET, | |||
RTC_GET, | |||
RTC_SET, | |||
EEPROM_GET_CONFIG, | |||
EEPROM_RESET_CONFIG, | |||
EEPROM_GET_CONTENT, | |||
EEPROM_GET_LAST_ENTRY, | |||
EEPROM_GET_ENTRIES, | |||
EEPROM_ADD_ENTRY, | |||
EEPROM_BACKUP_ENTRIES, | |||
NOTIFY_FAILURES, | |||
CLEAR_ALERTS, | |||
SLEEP_DEEP | |||
}; | |||
int freeRam(); | |||
void displayFreeRam(); | |||
GPSTRACKER_DEBUG_COMMAND menu(uint16_t timeout); | |||
void getAndDisplayBattery(); | |||
void getAndDisplayGpsPosition(); | |||
void setFakeGpsPosition(); | |||
void getAndDisplayRtcTime(); | |||
void setRtcTime(); | |||
void getAndDisplaySleepTimes(); | |||
void getAndDisplayEepromConfig(); | |||
void getAndDisplayEepromContent(); | |||
void getAndDisplayEepromPositions(); | |||
void getAndDisplayEepromLastPosition(); | |||
void addLastPositionToEeprom(); | |||
void notifyFailures(); | |||
void clearAlerts(); | |||
} |
@@ -1,118 +1,118 @@ | |||
#include "Gps.h" | |||
#include "Config.h" | |||
#include "Debug.h" | |||
#include "Hardware.h" | |||
#include "MainUnit.h" | |||
#include "math.h" | |||
#define LOGGER_NAME "Gps" | |||
#define TIME_YEAR_OFFSET 0 | |||
#define TIME_MONTH_OFFSET 4 | |||
#define TIME_DAY_OFFSET 6 | |||
#define TIME_HOUR_OFFSET 8 | |||
#define TIME_MINUTE_OFFSET 10 | |||
#define TIME_SECOND_OFFSET 12 | |||
#define EARTH_RADIUS 6371 //kilometers | |||
namespace gps { | |||
namespace details { | |||
uint8_t parseSubstring(char *buffer, char *start, uint8_t size) { | |||
strlcpy(buffer, start, size + 1); | |||
return static_cast<uint8_t>(strtoul(buffer, NULL, 10)); | |||
} | |||
} | |||
char lastPosition[GPS_POSITION_SIZE]; | |||
SIM808_GPS_STATUS lastStatus; | |||
float previousLat = 0; | |||
float previousLng = 0; | |||
SIM808_GPS_STATUS acquireCurrentPosition(int32_t timeout) { | |||
SIM808_GPS_STATUS currentStatus = SIM808_GPS_STATUS::OFF; | |||
do { | |||
currentStatus = hardware::sim808::device.getGpsStatus(); | |||
if (currentStatus > SIM808_GPS_STATUS::FIX) break; //if we have an accurate fix, break right now | |||
NOTICE_FORMAT("acquireCurrentPosition", "%d", currentStatus); | |||
mainunit::deepSleep(GPS_DEFAULT_INTERMEDIATE_TIMEOUT_MS / 1000); | |||
timeout -= GPS_DEFAULT_INTERMEDIATE_TIMEOUT_MS; | |||
} while (timeout > 1); | |||
if (currentStatus > SIM808_GPS_STATUS::NO_FIX) { | |||
lastStatus = currentStatus; | |||
hardware::sim808::device.getGpsPosition(lastPosition); | |||
} | |||
NOTICE_FORMAT("acquireCurrentPosition", "%d", currentStatus); | |||
return currentStatus; | |||
} | |||
void preserveCurrentCoordinates() { | |||
float lat, lng; | |||
if(!hardware::sim808::device.getGpsField(lastPosition, SIM808_GPS_FIELD::LATITUDE, &lat)) lat = 0; | |||
if(!hardware::sim808::device.getGpsField(lastPosition, SIM808_GPS_FIELD::LONGITUDE, &lng)) lng = 0; | |||
if (lat == 0 || lng == 0) return; | |||
previousLat = lat; | |||
previousLng = lng; | |||
} | |||
float getDistanceFromPrevious() { | |||
float lat1, lng1, lat2, lng2; | |||
if(!hardware::sim808::device.getGpsField(lastPosition, SIM808_GPS_FIELD::LATITUDE, &lat2)) return 0; | |||
if(!hardware::sim808::device.getGpsField(lastPosition, SIM808_GPS_FIELD::LONGITUDE, &lng2)) return 0; | |||
VERBOSE_FORMAT("distanceFromPrevious", "%s, %f, %f, %f, %f", lastPosition, previousLat, previousLng, lat2, lng2); | |||
lat1 = radians(previousLat); | |||
lng1 = radians(previousLng); | |||
lat2 = radians(lat2); | |||
lng2 = radians(lng2); | |||
float dlat = lat2 - lat1; | |||
float dlng = lng2 - lng1; | |||
float a = ( | |||
pow(sin(dlat / 2), 2) + | |||
cos(lat1) * cos(lat2) * pow(sin(dlng / 2), 2) | |||
); | |||
a = EARTH_RADIUS * (2 * atan2(sqrt(a), sqrt(1 - a))); //kilometers | |||
NOTICE_FORMAT("distanceFromPrevious", "%fkm", a); | |||
return a; | |||
} | |||
uint8_t getVelocity() { | |||
uint8_t velocity; | |||
if (!hardware::sim808::device.getGpsField(lastPosition, SIM808_GPS_FIELD::SPEED, &velocity)) velocity = 0; | |||
VERBOSE_FORMAT("getVelocity", "%d", velocity); | |||
return velocity; | |||
} | |||
void getTime(tmElements_t &time) { | |||
char *timeStr; | |||
char buffer[5]; | |||
hardware::sim808::device.getGpsField(lastPosition, SIM808_GPS_FIELD::UTC, &timeStr); | |||
VERBOSE_FORMAT("getTime", "%s", timeStr); | |||
time.Year = CalendarYrToTm(details::parseSubstring(buffer, timeStr + TIME_YEAR_OFFSET, 4)); | |||
time.Month = details::parseSubstring(buffer, timeStr + TIME_MONTH_OFFSET, 2); | |||
time.Day = details::parseSubstring(buffer, timeStr + TIME_DAY_OFFSET, 2); | |||
time.Hour = details::parseSubstring(buffer, timeStr + TIME_HOUR_OFFSET, 2); | |||
time.Minute = details::parseSubstring(buffer, timeStr + TIME_MINUTE_OFFSET, 2); | |||
time.Second = details::parseSubstring(buffer, timeStr + TIME_SECOND_OFFSET, 2); | |||
NOTICE_FORMAT("getTime", "%d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second); | |||
} | |||
#include "Gps.h" | |||
#include "Config.h" | |||
#include "Hardware.h" | |||
#include "MainUnit.h" | |||
#include "Logging.h" | |||
#include "math.h" | |||
#define LOGGER_NAME "Gps" | |||
#define TIME_YEAR_OFFSET 0 | |||
#define TIME_MONTH_OFFSET 4 | |||
#define TIME_DAY_OFFSET 6 | |||
#define TIME_HOUR_OFFSET 8 | |||
#define TIME_MINUTE_OFFSET 10 | |||
#define TIME_SECOND_OFFSET 12 | |||
#define EARTH_RADIUS 6371 //kilometers | |||
namespace gps { | |||
namespace details { | |||
uint8_t parseSubstring(char *buffer, char *start, uint8_t size) { | |||
strlcpy(buffer, start, size + 1); | |||
return static_cast<uint8_t>(strtoul(buffer, NULL, 10)); | |||
} | |||
} | |||
char lastPosition[GPS_POSITION_SIZE]; | |||
SIM808_GPS_STATUS lastStatus; | |||
float previousLat = 0; | |||
float previousLng = 0; | |||
SIM808_GPS_STATUS acquireCurrentPosition(int32_t timeout) { | |||
SIM808_GPS_STATUS currentStatus = SIM808_GPS_STATUS::OFF; | |||
do { | |||
currentStatus = hardware::sim808::device.getGpsStatus(); | |||
if (currentStatus > SIM808_GPS_STATUS::FIX) break; //if we have an accurate fix, break right now | |||
NOTICE_FORMAT("acquireCurrentPosition", "%d", currentStatus); | |||
mainunit::deepSleep(GPS_DEFAULT_INTERMEDIATE_TIMEOUT_MS / 1000); | |||
timeout -= GPS_DEFAULT_INTERMEDIATE_TIMEOUT_MS; | |||
} while (timeout > 1); | |||
if (currentStatus > SIM808_GPS_STATUS::NO_FIX) { | |||
lastStatus = currentStatus; | |||
hardware::sim808::device.getGpsPosition(lastPosition); | |||
} | |||
NOTICE_FORMAT("acquireCurrentPosition", "%d", currentStatus); | |||
return currentStatus; | |||
} | |||
void preserveCurrentCoordinates() { | |||
float lat, lng; | |||
if(!hardware::sim808::device.getGpsField(lastPosition, SIM808_GPS_FIELD::LATITUDE, &lat)) lat = 0; | |||
if(!hardware::sim808::device.getGpsField(lastPosition, SIM808_GPS_FIELD::LONGITUDE, &lng)) lng = 0; | |||
if (lat == 0 || lng == 0) return; | |||
previousLat = lat; | |||
previousLng = lng; | |||
} | |||
float getDistanceFromPrevious() { | |||
float lat1, lng1, lat2, lng2; | |||
if(!hardware::sim808::device.getGpsField(lastPosition, SIM808_GPS_FIELD::LATITUDE, &lat2)) return 0; | |||
if(!hardware::sim808::device.getGpsField(lastPosition, SIM808_GPS_FIELD::LONGITUDE, &lng2)) return 0; | |||
VERBOSE_FORMAT("distanceFromPrevious", "%s, %f, %f, %f, %f", lastPosition, previousLat, previousLng, lat2, lng2); | |||
lat1 = radians(previousLat); | |||
lng1 = radians(previousLng); | |||
lat2 = radians(lat2); | |||
lng2 = radians(lng2); | |||
float dlat = lat2 - lat1; | |||
float dlng = lng2 - lng1; | |||
float a = ( | |||
pow(sin(dlat / 2), 2) + | |||
cos(lat1) * cos(lat2) * pow(sin(dlng / 2), 2) | |||
); | |||
a = EARTH_RADIUS * (2 * atan2(sqrt(a), sqrt(1 - a))); //kilometers | |||
NOTICE_FORMAT("distanceFromPrevious", "%fkm", a); | |||
return a; | |||
} | |||
uint8_t getVelocity() { | |||
uint8_t velocity; | |||
if (!hardware::sim808::device.getGpsField(lastPosition, SIM808_GPS_FIELD::SPEED, &velocity)) velocity = 0; | |||
VERBOSE_FORMAT("getVelocity", "%d", velocity); | |||
return velocity; | |||
} | |||
void getTime(tmElements_t &time) { | |||
char *timeStr; | |||
char buffer[5]; | |||
hardware::sim808::device.getGpsField(lastPosition, SIM808_GPS_FIELD::UTC, &timeStr); | |||
VERBOSE_FORMAT("getTime", "%s", timeStr); | |||
time.Year = CalendarYrToTm(details::parseSubstring(buffer, timeStr + TIME_YEAR_OFFSET, 4)); | |||
time.Month = details::parseSubstring(buffer, timeStr + TIME_MONTH_OFFSET, 2); | |||
time.Day = details::parseSubstring(buffer, timeStr + TIME_DAY_OFFSET, 2); | |||
time.Hour = details::parseSubstring(buffer, timeStr + TIME_HOUR_OFFSET, 2); | |||
time.Minute = details::parseSubstring(buffer, timeStr + TIME_MINUTE_OFFSET, 2); | |||
time.Second = details::parseSubstring(buffer, timeStr + TIME_SECOND_OFFSET, 2); | |||
NOTICE_FORMAT("getTime", "%d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second); | |||
} | |||
} |
@@ -1,10 +0,0 @@ | |||
#pragma once | |||
#include <Arduino.h> | |||
#include <SIM808.h> | |||
#include "Debug.h" | |||
#include "Config.h" | |||
#include "Core.h" | |||
#define LOGGER_NAME "GpsTracker" |
@@ -1,95 +1,97 @@ | |||
#include "GpsTracker.h" | |||
#include "Positions.h" | |||
#if _DEBUG | |||
#define MENU_DEFAULT_TIMEOUT 0 | |||
#else | |||
#define MENU_DEFAULT_TIMEOUT 10000 | |||
#endif | |||
bool bypassMenu = false; | |||
uint16_t menuTimeout = MENU_DEFAULT_TIMEOUT; | |||
void setup() { | |||
logging::setup(); | |||
config::main::setup(); | |||
rtc::setup(); | |||
hardware::sim808::setup(); | |||
positions::setup(); | |||
} | |||
void loop() { | |||
debug::GPSTRACKER_DEBUG_COMMAND command = debug::GPSTRACKER_DEBUG_COMMAND::RUN; | |||
if (Serial && !bypassMenu) command = debug::menu(menuTimeout); | |||
if (command == debug::GPSTRACKER_DEBUG_COMMAND::RUN) bypassMenu = true; | |||
else menuTimeout = 0; //disable timeout once a command has been entered | |||
bypassMenu = command == debug::GPSTRACKER_DEBUG_COMMAND::RUN; | |||
switch (command) { | |||
case debug::GPSTRACKER_DEBUG_COMMAND::RUN: | |||
case debug::GPSTRACKER_DEBUG_COMMAND::ONCE: | |||
core::main(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::RAM: | |||
debug::displayFreeRam(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::BATTERY: | |||
debug::getAndDisplayBattery(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::GPS_ON: | |||
gps::powerOn(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::GPS_OFF: | |||
gps::powerOff(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::GPS_GET: | |||
debug::getAndDisplayGpsPosition(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::GPS_SET: | |||
debug::setFakeGpsPosition(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::RTC_GET: | |||
debug::getAndDisplayRtcTime(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::RTC_SET: | |||
debug::setRtcTime(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_CONFIG: | |||
debug::getAndDisplayEepromConfig(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_RESET_CONFIG: | |||
config::main::reset(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_CONTENT: | |||
debug::getAndDisplayEepromContent(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_ENTRIES: | |||
debug::getAndDisplayEepromPositions(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_LAST_ENTRY: | |||
debug::getAndDisplayEepromLastPosition(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_ADD_ENTRY: | |||
debug::addLastPositionToEeprom(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_BACKUP_ENTRIES: | |||
positions::doBackup(true); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::NOTIFY_FAILURES: | |||
debug::notifyFailures(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::CLEAR_ALERTS: | |||
debug::clearAlerts(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP: | |||
mainunit::deepSleep(10); | |||
break; | |||
default: | |||
NOTICE_MSG("loop", "Unsupported"); | |||
} | |||
} | |||
#include <Arduino.h> | |||
#include <SIM808.h> | |||
#include "Debug.h" | |||
#include "Config.h" | |||
#include "Core.h" | |||
#include "Positions.h" | |||
#include "Logging.h" | |||
#define LOGGER_NAME "GpsTracker" | |||
bool bypassMenu = false; | |||
uint16_t menuTimeout = MENU_TIMEOUT; | |||
void setup() { | |||
logging::setup(); | |||
config::main::setup(); | |||
rtc::setup(); | |||
hardware::sim808::setup(); | |||
positions::setup(); | |||
} | |||
void loop() { | |||
debug::GPSTRACKER_DEBUG_COMMAND command = debug::GPSTRACKER_DEBUG_COMMAND::RUN; | |||
if (Serial && !bypassMenu) command = debug::menu(menuTimeout); | |||
if (command == debug::GPSTRACKER_DEBUG_COMMAND::RUN) bypassMenu = true; | |||
else menuTimeout = 0; //disable timeout once a command has been entered | |||
bypassMenu = command == debug::GPSTRACKER_DEBUG_COMMAND::RUN; | |||
switch (command) { | |||
case debug::GPSTRACKER_DEBUG_COMMAND::RUN: | |||
case debug::GPSTRACKER_DEBUG_COMMAND::ONCE: | |||
core::main(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::RAM: | |||
debug::displayFreeRam(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::BATTERY: | |||
debug::getAndDisplayBattery(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::GPS_ON: | |||
gps::powerOn(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::GPS_OFF: | |||
gps::powerOff(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::GPS_GET: | |||
debug::getAndDisplayGpsPosition(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::GPS_SET: | |||
debug::setFakeGpsPosition(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::RTC_GET: | |||
debug::getAndDisplayRtcTime(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::RTC_SET: | |||
debug::setRtcTime(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_CONFIG: | |||
debug::getAndDisplayEepromConfig(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_RESET_CONFIG: | |||
config::main::reset(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_CONTENT: | |||
debug::getAndDisplayEepromContent(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_ENTRIES: | |||
debug::getAndDisplayEepromPositions(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_LAST_ENTRY: | |||
debug::getAndDisplayEepromLastPosition(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_ADD_ENTRY: | |||
debug::addLastPositionToEeprom(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_BACKUP_ENTRIES: | |||
positions::doBackup(true); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::NOTIFY_FAILURES: | |||
debug::notifyFailures(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::CLEAR_ALERTS: | |||
debug::clearAlerts(); | |||
break; | |||
case debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP: | |||
mainunit::deepSleep(10); | |||
break; | |||
default: | |||
NOTICE_MSG("loop", "Unsupported"); | |||
} | |||
} |
@@ -1,22 +1,19 @@ | |||
#include "Config.h" | |||
#include "Hardware.h" | |||
#include "config/Pins.h" | |||
#include "Debug.h" | |||
#include "config/Hardware.h" | |||
#include "Logging.h" | |||
#include <SoftwareSerial.h> | |||
#include <SIM808.h> | |||
#include <SIM808_Types.h> | |||
#include <Wire.h> | |||
#include <E24.h> | |||
namespace hardware { | |||
#define LOGGER_NAME "Hardware::sim808" | |||
namespace sim808 { | |||
SoftwareSerial simSerial = SoftwareSerial(SIM_TX, SIM_RX); | |||
SIM_SERIAL_TYPE simSerial = SIM_SERIAL; | |||
SIM808 device = SIM808(SIM_RST, SIM_PWR, SIM_STATUS); | |||
uint8_t networkPoweredCount = 0; | |||
uint8_t gpsPoweredCount = 0; | |||
@@ -119,7 +116,7 @@ namespace hardware { | |||
namespace i2c { | |||
E24 eeprom = E24(E24Size_t::E24_512K); | |||
E24 eeprom = E24(E24Size_t::E24_512K, E24_ADDRESS); | |||
uint8_t poweredCount = 0; | |||
void powerOn() { | |||
@@ -1,31 +1,31 @@ | |||
#pragma once | |||
#include <SoftwareSerial.h> | |||
#include <SIM808.h> | |||
#include <E24.h> | |||
namespace hardware { | |||
namespace sim808 { | |||
extern SoftwareSerial simSerial; | |||
extern SIM808 device; | |||
void powerOn(); | |||
void powerOff(); | |||
void setup(); | |||
void gpsPowerOn(); | |||
void gpsPowerOff(); | |||
void networkPowerOn(); | |||
void networkPowerOff(); | |||
} | |||
namespace i2c { | |||
extern E24 eeprom; | |||
void powerOn(); | |||
void powerOff(bool forced = false); | |||
} | |||
#pragma once | |||
#include "config/Hardware.h" | |||
#include <SIM808.h> | |||
#include <E24.h> | |||
namespace hardware { | |||
namespace sim808 { | |||
extern SIM_SERIAL_TYPE simSerial; | |||
extern SIM808 device; | |||
void powerOn(); | |||
void powerOff(); | |||
void setup(); | |||
void gpsPowerOn(); | |||
void gpsPowerOff(); | |||
void networkPowerOn(); | |||
void networkPowerOff(); | |||
} | |||
namespace i2c { | |||
extern E24 eeprom; | |||
void powerOn(); | |||
void powerOff(bool forced = false); | |||
} | |||
} |
@@ -1,10 +1,13 @@ | |||
#include "MainUnit.h" | |||
#include "Rtc.h" | |||
#include "config/Pins.h" | |||
#include "Debug.h" | |||
#include "Hardware.h" | |||
#include "config/Hardware.h" | |||
#include "Logging.h" | |||
#define LOGGER_NAME "MainUnit" | |||
extern int __heap_start, *__brkval; | |||
namespace mainunit { | |||
namespace details { | |||
@@ -42,4 +45,9 @@ namespace mainunit { | |||
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); | |||
details::wokeUp(); | |||
} | |||
int freeRam() { | |||
int v; | |||
return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval); | |||
} | |||
} |
@@ -1,8 +1,9 @@ | |||
#pragma once | |||
#include <Arduino.h> | |||
#include <LowPower.h> | |||
namespace mainunit { | |||
void deepSleep(uint16_t seconds); | |||
#pragma once | |||
#include <Arduino.h> | |||
#include <LowPower.h> | |||
namespace mainunit { | |||
void deepSleep(uint16_t seconds); | |||
int freeRam(); | |||
} |
@@ -1,76 +1,76 @@ | |||
#include "Config.h" | |||
#include "Debug.h" | |||
#include "Network.h" | |||
#include "Hardware.h" | |||
#include "MainUnit.h" | |||
#include "Rtc.h" | |||
#define LOGGER_NAME "Network" | |||
namespace network { | |||
timestamp_t _poweredOnTime; | |||
void powerOn() { | |||
hardware::sim808::networkPowerOn(); | |||
_poweredOnTime = rtc::getTime(); | |||
} | |||
void powerOff() { | |||
hardware::sim808::networkPowerOff(); | |||
_poweredOnTime = 0; | |||
} | |||
__attribute__((__optimize__("O2"))) | |||
SIM808RegistrationStatus waitForRegistered(uint32_t timeout, bool relativeToPowerOnTime = true) { | |||
SIM808RegistrationStatus currentStatus; | |||
SIM808SignalQualityReport report; | |||
uint8_t noReliableNetwork = 0; | |||
if (relativeToPowerOnTime) timeout -= (rtc::getTime() - _poweredOnTime) * 1000; | |||
currentStatus = hardware::sim808::device.getNetworkRegistrationStatus(); | |||
report = hardware::sim808::device.getSignalQuality(); | |||
do { | |||
if (isAvailable(currentStatus.stat)) break; | |||
NOTICE_FORMAT("waitForRegistered", "%d, [%d %ddBm]", currentStatus.stat, report.ssri, report.attenuation); | |||
if (report.ssri < NETWORK_DEFAULT_NO_NETWORK_QUALITY_THRESHOLD) noReliableNetwork++; | |||
else noReliableNetwork = 0; | |||
if (noReliableNetwork > NETWORK_DEFAULT_NO_NETWORK_TRIES) { | |||
NOTICE_MSG("waitForRegistered", "No reliable signal"); | |||
break; //after a while, no network really means no network. Bailing out | |||
} | |||
mainunit::deepSleep(NETWORK_DEFAULT_INTERMEDIATE_TIMEOUT_MS / 1000); | |||
timeout -= NETWORK_DEFAULT_INTERMEDIATE_TIMEOUT_MS; | |||
currentStatus = hardware::sim808::device.getNetworkRegistrationStatus(); | |||
report = hardware::sim808::device.getSignalQuality(); | |||
} while (timeout > 1); | |||
NOTICE_FORMAT("waitForRegistered", "%d, [%d %ddBm]", currentStatus.stat, report.ssri, report.attenuation); | |||
return currentStatus; | |||
} | |||
bool isAvailable(SIM808_NETWORK_REGISTRATION_STATE state) { | |||
return static_cast<int8_t>(state) & | |||
(static_cast<int8_t>(SIM808_NETWORK_REGISTRATION_STATE::REGISTERED) | static_cast<int8_t>(SIM808_NETWORK_REGISTRATION_STATE::ROAMING)) | |||
!= 0; | |||
} | |||
bool enableGprs() { | |||
return hardware::sim808::device.enableGprs(config::main::value.network.apn); | |||
} | |||
bool sendSms(const char * msg) { | |||
const char * phoneNumber = config::main::value.contactPhone; | |||
NOTICE_FORMAT("sendSms", "%s, %s", phoneNumber, msg); | |||
return hardware::sim808::device.sendSms(phoneNumber, msg); | |||
} | |||
#include "Config.h" | |||
#include "Network.h" | |||
#include "Hardware.h" | |||
#include "MainUnit.h" | |||
#include "Rtc.h" | |||
#include "Logging.h" | |||
#define LOGGER_NAME "Network" | |||
namespace network { | |||
timestamp_t _poweredOnTime; | |||
void powerOn() { | |||
hardware::sim808::networkPowerOn(); | |||
_poweredOnTime = rtc::getTime(); | |||
} | |||
void powerOff() { | |||
hardware::sim808::networkPowerOff(); | |||
_poweredOnTime = 0; | |||
} | |||
__attribute__((__optimize__("O2"))) | |||
SIM808RegistrationStatus waitForRegistered(uint32_t timeout, bool relativeToPowerOnTime = true) { | |||
SIM808RegistrationStatus currentStatus; | |||
SIM808SignalQualityReport report; | |||
uint8_t noReliableNetwork = 0; | |||
if (relativeToPowerOnTime) timeout -= (rtc::getTime() - _poweredOnTime) * 1000; | |||
currentStatus = hardware::sim808::device.getNetworkRegistrationStatus(); | |||
report = hardware::sim808::device.getSignalQuality(); | |||
do { | |||
if (isAvailable(currentStatus.stat)) break; | |||
NOTICE_FORMAT("waitForRegistered", "%d, [%d %ddBm]", currentStatus.stat, report.ssri, report.attenuation); | |||
if (report.ssri < NETWORK_DEFAULT_NO_NETWORK_QUALITY_THRESHOLD) noReliableNetwork++; | |||
else noReliableNetwork = 0; | |||
if (noReliableNetwork > NETWORK_DEFAULT_NO_NETWORK_TRIES) { | |||
NOTICE_MSG("waitForRegistered", "No reliable signal"); | |||
break; //after a while, no network really means no network. Bailing out | |||
} | |||
mainunit::deepSleep(NETWORK_DEFAULT_INTERMEDIATE_TIMEOUT_MS / 1000); | |||
timeout -= NETWORK_DEFAULT_INTERMEDIATE_TIMEOUT_MS; | |||
currentStatus = hardware::sim808::device.getNetworkRegistrationStatus(); | |||
report = hardware::sim808::device.getSignalQuality(); | |||
} while (timeout > 1); | |||
NOTICE_FORMAT("waitForRegistered", "%d, [%d %ddBm]", currentStatus.stat, report.ssri, report.attenuation); | |||
return currentStatus; | |||
} | |||
bool isAvailable(SIM808_NETWORK_REGISTRATION_STATE state) { | |||
return static_cast<int8_t>(state) & | |||
(static_cast<int8_t>(SIM808_NETWORK_REGISTRATION_STATE::REGISTERED) | static_cast<int8_t>(SIM808_NETWORK_REGISTRATION_STATE::ROAMING)) | |||
!= 0; | |||
} | |||
bool enableGprs() { | |||
return hardware::sim808::device.enableGprs(config::main::value.network.apn); | |||
} | |||
bool sendSms(const char * msg) { | |||
const char * phoneNumber = config::main::value.contactPhone; | |||
NOTICE_FORMAT("sendSms", "%s, %s", phoneNumber, msg); | |||
return hardware::sim808::device.sendSms(phoneNumber, msg); | |||
} | |||
} |
@@ -1,112 +1,114 @@ | |||
#pragma once | |||
#include "Config.h" | |||
#if BACKUP_ENABLE_NETWORK | |||
#include "NetworkPositionsBackup.h" | |||
#include "Debug.h" | |||
#include "Hardware.h" | |||
#include "Network.h" | |||
#define LOGGER_NAME "Positions::backup::network" | |||
#define BUFFER_SIZE 170 | |||
namespace positions { | |||
namespace backup { | |||
namespace net { | |||
uint8_t networkUnavailableInARow = 0; | |||
uint8_t networkUnavailablePostpone = 1; | |||
bool NetworkPositionsBackup::isBackupNeeded(bool forPrepare) { | |||
config_t *config = &config::main::value; | |||
return (config->network.lastSavedEntry == 0xFFFF && config->lastEntry != 0xFFFF) || | |||
positions::count(config->network.lastSavedEntry) > (config->network.saveThreshold * networkUnavailablePostpone) - (forPrepare ? 1 : 0); | |||
} | |||
bool NetworkPositionsBackup::appendPosition(PositionEntry &entry) { | |||
char buffer[BUFFER_SIZE]; | |||
snprintf_P(buffer, BUFFER_SIZE, PSTR("%d,%d,%d,%d,%d,%d,%d,%s"), | |||
debug::freeRam(), | |||
hardware::sim808::device.getSignalQuality().attenuation, | |||
entry.metadata.batteryLevel, | |||
entry.metadata.batteryVoltage, | |||
entry.metadata.temperature, | |||
static_cast<uint8_t>(entry.metadata.status), | |||
entry.metadata.timeToFix, | |||
entry.position); | |||
NOTICE_FORMAT("appendPosition", "Sending : %s", buffer); | |||
uint16_t responseCode = hardware::sim808::device.httpPost( | |||
config::main::value.network.url, | |||
F("text/gpstracker"), | |||
buffer, | |||
buffer, | |||
BUFFER_SIZE | |||
); | |||
NOTICE_FORMAT("appendPosition", "Response : %d", responseCode); | |||
return responseCode == POSITIONS_CONFIG_NET_DEFAULT_EXPECTED_RESPONSE; | |||
} | |||
//__attribute__((__optimize__("O2"))) | |||
void NetworkPositionsBackup::appendPositions() { | |||
uint16_t currentEntryIndex = config::main::value.network.lastSavedEntry + 1; | |||
PositionEntry currentEntry; | |||
SIM808RegistrationStatus networkStatus; | |||
//avoid edge case where if 0, whole set of positions will be sent again | |||
if (!positions::count(config::main::value.network.lastSavedEntry)) return; | |||
network::powerOn(); | |||
networkStatus = network::waitForRegistered(NETWORK_DEFAULT_TOTAL_TIMEOUT_MS); | |||
if (!network::isAvailable(networkStatus.stat) || !network::enableGprs()) { | |||
networkUnavailableInARow = min(networkUnavailableInARow + 1, POSITIONS_CONFIG_NET_DEFAULT_UNAVAILABLE_NETWORK_POSTPONE_THRESHOLD + 1); //avoid increment overflow | |||
NOTICE_MSG("appendPositions", "network or gprs unavailable"); | |||
if (networkUnavailableInARow > POSITIONS_CONFIG_NET_DEFAULT_UNAVAILABLE_NETWORK_POSTPONE_THRESHOLD) { | |||
networkUnavailablePostpone++; | |||
} | |||
} | |||
else { | |||
networkUnavailableInARow = 0; | |||
networkUnavailablePostpone = 1; | |||
hardware::i2c::powerOn(); | |||
do { | |||
if (!positions::get(currentEntryIndex, currentEntry)) break; | |||
if (!appendPosition(currentEntry)) break; | |||
config::main::value.network.lastSavedEntry = currentEntryIndex; | |||
config::main::save(); | |||
} while (positions::moveNext(currentEntryIndex)); | |||
hardware::i2c::powerOff(); | |||
} | |||
network::powerOff(); | |||
} | |||
void NetworkPositionsBackup::setup() {} | |||
void NetworkPositionsBackup::prepare() { | |||
NOTICE("prepare"); | |||
if (!isBackupNeeded(true)) return; | |||
network::powerOn(); | |||
} | |||
void NetworkPositionsBackup::backup(bool force) { | |||
NOTICE("backup"); | |||
if (force || isBackupNeeded(false)) { | |||
appendPositions(); | |||
} | |||
network::powerOff(); | |||
} | |||
} | |||
} | |||
} | |||
#pragma once | |||
#include "Config.h" | |||
#if BACKUP_ENABLE_NETWORK | |||
#include "NetworkPositionsBackup.h" | |||
#include "MainUnit.h" | |||
#include "Hardware.h" | |||
#include "Network.h" | |||
#include "Logging.h" | |||
#define LOGGER_NAME "Positions::backup::network" | |||
#define BUFFER_SIZE 170 | |||
namespace positions { | |||
namespace backup { | |||
namespace net { | |||
uint8_t networkUnavailableInARow = 0; | |||
uint8_t networkUnavailablePostpone = 1; | |||
bool NetworkPositionsBackup::isBackupNeeded(bool forPrepare) { | |||
config_t *config = &config::main::value; | |||
return (config->network.lastSavedEntry == 0xFFFF && config->lastEntry != 0xFFFF) || | |||
positions::count(config->network.lastSavedEntry) > (config->network.saveThreshold * networkUnavailablePostpone) - (forPrepare ? 1 : 0); | |||
} | |||
bool NetworkPositionsBackup::appendPosition(PositionEntry &entry) { | |||
char buffer[BUFFER_SIZE]; | |||
snprintf_P(buffer, BUFFER_SIZE, PSTR("%d,%d,%d,%d,%d,%d,%d,%s"), | |||
mainunit::freeRam(), | |||
hardware::sim808::device.getSignalQuality().attenuation, | |||
entry.metadata.batteryLevel, | |||
entry.metadata.batteryVoltage, | |||
entry.metadata.temperature, | |||
static_cast<uint8_t>(entry.metadata.status), | |||
entry.metadata.timeToFix, | |||
entry.position); | |||
NOTICE_FORMAT("appendPosition", "Sending : %s", buffer); | |||
uint16_t responseCode = hardware::sim808::device.httpPost( | |||
config::main::value.network.url, | |||
F("text/gpstracker"), | |||
buffer, | |||
buffer, | |||
BUFFER_SIZE | |||
); | |||
NOTICE_FORMAT("appendPosition", "Response : %d", responseCode); | |||
return responseCode == POSITIONS_CONFIG_NET_DEFAULT_EXPECTED_RESPONSE; | |||
} | |||
//__attribute__((__optimize__("O2"))) | |||
void NetworkPositionsBackup::appendPositions() { | |||
uint16_t currentEntryIndex = config::main::value.network.lastSavedEntry + 1; | |||
PositionEntry currentEntry; | |||
SIM808RegistrationStatus networkStatus; | |||
//avoid edge case where if 0, whole set of positions will be sent again | |||
if (!positions::count(config::main::value.network.lastSavedEntry)) return; | |||
network::powerOn(); | |||
networkStatus = network::waitForRegistered(NETWORK_DEFAULT_TOTAL_TIMEOUT_MS); | |||
if (!network::isAvailable(networkStatus.stat) || !network::enableGprs()) { | |||
networkUnavailableInARow = min(networkUnavailableInARow + 1, POSITIONS_CONFIG_NET_DEFAULT_UNAVAILABLE_NETWORK_POSTPONE_THRESHOLD + 1); //avoid increment overflow | |||
NOTICE_MSG("appendPositions", "network or gprs unavailable"); | |||
if (networkUnavailableInARow > POSITIONS_CONFIG_NET_DEFAULT_UNAVAILABLE_NETWORK_POSTPONE_THRESHOLD) { | |||
networkUnavailablePostpone++; | |||
} | |||
} | |||
else { | |||
networkUnavailableInARow = 0; | |||
networkUnavailablePostpone = 1; | |||
hardware::i2c::powerOn(); | |||
do { | |||
if (!positions::get(currentEntryIndex, currentEntry)) break; | |||
if (!appendPosition(currentEntry)) break; | |||
config::main::value.network.lastSavedEntry = currentEntryIndex; | |||
config::main::save(); | |||
} while (positions::moveNext(currentEntryIndex)); | |||
hardware::i2c::powerOff(); | |||
} | |||
network::powerOff(); | |||
} | |||
void NetworkPositionsBackup::setup() {} | |||
void NetworkPositionsBackup::prepare() { | |||
NOTICE("prepare"); | |||
if (!isBackupNeeded(true)) return; | |||
network::powerOn(); | |||
} | |||
void NetworkPositionsBackup::backup(bool force) { | |||
NOTICE("backup"); | |||
if (force || isBackupNeeded(false)) { | |||
appendPositions(); | |||
} | |||
network::powerOff(); | |||
} | |||
} | |||
} | |||
} | |||
#endif |
@@ -1,195 +1,196 @@ | |||
#include "Config.h" | |||
#include "Debug.h" | |||
#include "Positions.h" | |||
#include "Gps.h" | |||
#if BACKUP_ENABLE_SDCARD || BACKUP_ENABLE_NETWORK | |||
#define BACKUPS_ENABLED (BACKUP_ENABLE_SDCARD + BACKUP_ENABLE_NETWORK) | |||
#endif | |||
#if BACKUP_ENABLE_SDCARD | |||
#include "SdPositionsBackup.h" | |||
#endif | |||
#if BACKUP_ENABLE_NETWORK | |||
#include "NetworkPositionsBackup.h" | |||
#endif | |||
#define LOGGER_NAME "Positions" | |||
#define ENTRY_RESERVED_SIZE 128 | |||
#define ENTRIES_ADDR CONFIG_RESERVED_SIZE | |||
namespace positions { | |||
#if BACKUPS_ENABLED > 1 | |||
backup::PositionsBackup **_backups; | |||
#elif BACKUPS_ENABLED == 1 | |||
backup::PositionsBackup * _backup; | |||
#endif | |||
namespace details { | |||
uint16_t maxEntryIndex = 0; | |||
uint16_t getEntryAddress(uint16_t index) { | |||
if (index > maxEntryIndex) return -1; | |||
return ENTRIES_ADDR + (ENTRY_RESERVED_SIZE * index); | |||
} | |||
} | |||
void setup() { | |||
details::maxEntryIndex = (E24_MAX_ADDRESS(hardware::i2c::eeprom.getSize()) - ENTRIES_ADDR) / ENTRY_RESERVED_SIZE; | |||
#if BACKUPS_ENABLED > 0 | |||
backup::PositionsBackup * backup = NULL; | |||
#if BACKUPS_ENABLED > 1 | |||
uint8_t backupIdx = 0; | |||
_backups = new backup::PositionsBackup*[BACKUPS_ENABLED]; | |||
#endif //BACKUPS_ENABLED > 1 | |||
#if BACKUP_ENABLE_SDCARD | |||
backup = new backup::sd::SdPositionsBackup(); | |||
backup->setup(); | |||
#if BACKUPS_ENABLED > 1 | |||
_backups[backupIdx] = backup; | |||
backupIdx++; | |||
#endif //BACKUPS_ENABLED > 1 | |||
#endif //BACKUP_ENABLE_SDCARD | |||
#if BACKUP_ENABLE_NETWORK | |||
backup = new backup::net::NetworkPositionsBackup(); | |||
backup->setup(); | |||
#if BACKUPS_ENABLED > 1 | |||
_backups[backupIdx] = backup; | |||
backupIdx++; | |||
#endif //BACKUPS_ENABLED > 1 | |||
#endif //BACKUP_ENABLE_NETWORK | |||
#if BACKUPS_ENABLED == 1 | |||
_backup = backup; | |||
#endif //BACKUPS_ENABLED == 1 | |||
#endif //BACKUPS_ENABLED > 0 | |||
} | |||
bool acquire(PositionEntryMetadata &metadata) { | |||
NOTICE("acquire"); | |||
timestamp_t before; | |||
gps::powerOn(); | |||
before = rtc::getTime(); | |||
SIM808_GPS_STATUS gpsStatus = gps::acquireCurrentPosition(GPS_DEFAULT_TOTAL_TIMEOUT_MS); | |||
uint16_t timeToFix = rtc::getTime() - before; | |||
SIM808ChargingStatus battery = hardware::sim808::device.getChargingState(); | |||
gps::powerOff(); | |||
bool acquired = gpsStatus >= SIM808_GPS_STATUS::FIX; //prety useless wins 14 bytes on the hex size rather than return gpStatus >= ... | |||
NOTICE_FORMAT("acquire", "Status : %d", gpsStatus); | |||
metadata = { | |||
battery.level, | |||
battery.voltage, | |||
rtc::getTemperature(), | |||
timeToFix, | |||
gpsStatus | |||
}; | |||
return acquired; | |||
} | |||
void appendLast(const PositionEntryMetadata &metadata) { | |||
VERBOSE("appendLast"); | |||
uint16_t entryIndex; | |||
uint16_t entryAddress; | |||
PositionEntry entry = { metadata }; | |||
strlcpy(entry.position, gps::lastPosition, POSITION_SIZE); | |||
config_t* config = &config::main::value; | |||
entryIndex = config->lastEntry + 1; | |||
entryAddress = details::getEntryAddress(entryIndex); | |||
hardware::i2c::powerOn(); | |||
hardware::i2c::eeprom.writeBlock(entryAddress, entry); | |||
NOTICE_FORMAT("appendLast", "Saved @ %X : %d,%d,%d,%d,%d,%s", | |||
entryAddress, | |||
entry.metadata.batteryLevel, | |||
entry.metadata.batteryVoltage, | |||
entry.metadata.temperature, | |||
static_cast<uint8_t>(entry.metadata.status), | |||
entry.metadata.timeToFix, | |||
entry.position); | |||
config->lastEntry++; | |||
if (config->lastEntry > details::maxEntryIndex) config->lastEntry = 0; | |||
if (config->lastEntry == config->firstEntry) config->firstEntry++; | |||
if (config->firstEntry > details::maxEntryIndex) config->firstEntry = 0; | |||
config::main::save(); | |||
hardware::i2c::powerOff(); | |||
} | |||
bool get(uint16_t index, PositionEntry &entry) { | |||
VERBOSE("get"); | |||
uint16_t entryAddress = details::getEntryAddress(index); | |||
if (entryAddress == -1) return false; | |||
VERBOSE_FORMAT("get", "Reading entry %d @ %X", index, entryAddress); | |||
hardware::i2c::powerOn(); | |||
hardware::i2c::eeprom.readBlock(entryAddress, entry); | |||
hardware::i2c::powerOff(); | |||
NOTICE_FORMAT("get", "Read from EEPROM @ %X : %d,%d,%d,%d,%d,%s", | |||
entryAddress, | |||
entry.metadata.batteryLevel, | |||
entry.metadata.batteryVoltage, | |||
entry.metadata.temperature, | |||
static_cast<uint8_t>(entry.metadata.status), | |||
entry.metadata.timeToFix, | |||
entry.position); | |||
return true; | |||
} | |||
bool moveNext(uint16_t &index) { | |||
if (index == config::main::value.lastEntry) return false; | |||
if (index == details::maxEntryIndex) index = 0; //could use a modulo but easier to understand that way | |||
else index++; | |||
return true; | |||
} | |||
uint16_t count(uint16_t fromIndex) { | |||
config_t *config = &config::main::value; | |||
uint16_t lastEntry = config->lastEntry; | |||
if (lastEntry < fromIndex) { lastEntry += details::maxEntryIndex; } | |||
return lastEntry - fromIndex; | |||
} | |||
void prepareBackup() { | |||
#if BACKUPS_ENABLED > 1 | |||
for (int i = 0; i < BACKUPS_ENABLED; i++) { | |||
_backups[i]->prepare(); | |||
} | |||
#elif BACKUPS_ENABLED == 1 | |||
_backup->prepare(); | |||
#endif | |||
} | |||
void doBackup(bool force) { | |||
#if BACKUPS_ENABLED > 1 | |||
for (int i = 0; i < BACKUPS_ENABLED; i++) { | |||
_backups[i]->backup(force); | |||
} | |||
#elif BACKUPS_ENABLED == 1 | |||
_backup->backup(force); | |||
#endif | |||
} | |||
#include "Config.h" | |||
#include "Positions.h" | |||
#include "Gps.h" | |||
#include "Rtc.h" | |||
#include "Logging.h" | |||
#if BACKUP_ENABLE_SDCARD || BACKUP_ENABLE_NETWORK | |||
#define BACKUPS_ENABLED (BACKUP_ENABLE_SDCARD + BACKUP_ENABLE_NETWORK) | |||
#endif | |||
#if BACKUP_ENABLE_SDCARD | |||
#include "SdPositionsBackup.h" | |||
#endif | |||
#if BACKUP_ENABLE_NETWORK | |||
#include "NetworkPositionsBackup.h" | |||
#endif | |||
#define LOGGER_NAME "Positions" | |||
#define ENTRY_RESERVED_SIZE 128 | |||
#define ENTRIES_ADDR CONFIG_RESERVED_SIZE | |||
namespace positions { | |||
#if BACKUPS_ENABLED > 1 | |||
backup::PositionsBackup **_backups; | |||
#elif BACKUPS_ENABLED == 1 | |||
backup::PositionsBackup * _backup; | |||
#endif | |||
namespace details { | |||
uint16_t maxEntryIndex = 0; | |||
uint16_t getEntryAddress(uint16_t index) { | |||
if (index > maxEntryIndex) return -1; | |||
return ENTRIES_ADDR + (ENTRY_RESERVED_SIZE * index); | |||
} | |||
} | |||
void setup() { | |||
details::maxEntryIndex = (E24_MAX_ADDRESS(hardware::i2c::eeprom.getSize()) - ENTRIES_ADDR) / ENTRY_RESERVED_SIZE; | |||
#if BACKUPS_ENABLED > 0 | |||
backup::PositionsBackup * backup = NULL; | |||
#if BACKUPS_ENABLED > 1 | |||
uint8_t backupIdx = 0; | |||
_backups = new backup::PositionsBackup*[BACKUPS_ENABLED]; | |||
#endif //BACKUPS_ENABLED > 1 | |||
#if BACKUP_ENABLE_SDCARD | |||
backup = new backup::sd::SdPositionsBackup(); | |||
backup->setup(); | |||
#if BACKUPS_ENABLED > 1 | |||
_backups[backupIdx] = backup; | |||
backupIdx++; | |||
#endif //BACKUPS_ENABLED > 1 | |||
#endif //BACKUP_ENABLE_SDCARD | |||
#if BACKUP_ENABLE_NETWORK | |||
backup = new backup::net::NetworkPositionsBackup(); | |||
backup->setup(); | |||
#if BACKUPS_ENABLED > 1 | |||
_backups[backupIdx] = backup; | |||
backupIdx++; | |||
#endif //BACKUPS_ENABLED > 1 | |||
#endif //BACKUP_ENABLE_NETWORK | |||
#if BACKUPS_ENABLED == 1 | |||
_backup = backup; | |||
#endif //BACKUPS_ENABLED == 1 | |||
#endif //BACKUPS_ENABLED > 0 | |||
} | |||
bool acquire(PositionEntryMetadata &metadata) { | |||
NOTICE("acquire"); | |||
timestamp_t before; | |||
gps::powerOn(); | |||
before = rtc::getTime(); | |||
SIM808_GPS_STATUS gpsStatus = gps::acquireCurrentPosition(GPS_DEFAULT_TOTAL_TIMEOUT_MS); | |||
uint16_t timeToFix = rtc::getTime() - before; | |||
SIM808ChargingStatus battery = hardware::sim808::device.getChargingState(); | |||
gps::powerOff(); | |||
bool acquired = gpsStatus >= SIM808_GPS_STATUS::FIX; //prety useless wins 14 bytes on the hex size rather than return gpStatus >= ... | |||
NOTICE_FORMAT("acquire", "Status : %d", gpsStatus); | |||
metadata = { | |||
battery.level, | |||
battery.voltage, | |||
rtc::getTemperature(), | |||
timeToFix, | |||
gpsStatus | |||
}; | |||
return acquired; | |||
} | |||
void appendLast(const PositionEntryMetadata &metadata) { | |||
VERBOSE("appendLast"); | |||
uint16_t entryIndex; | |||
uint16_t entryAddress; | |||
PositionEntry entry = { metadata }; | |||
strlcpy(entry.position, gps::lastPosition, POSITION_SIZE); | |||
config_t* config = &config::main::value; | |||
entryIndex = config->lastEntry + 1; | |||
entryAddress = details::getEntryAddress(entryIndex); | |||
hardware::i2c::powerOn(); | |||
hardware::i2c::eeprom.writeBlock(entryAddress, entry); | |||
NOTICE_FORMAT("appendLast", "Saved @ %X : %d,%d,%d,%d,%d,%s", | |||
entryAddress, | |||
entry.metadata.batteryLevel, | |||
entry.metadata.batteryVoltage, | |||
entry.metadata.temperature, | |||
static_cast<uint8_t>(entry.metadata.status), | |||
entry.metadata.timeToFix, | |||
entry.position); | |||
config->lastEntry++; | |||
if (config->lastEntry > details::maxEntryIndex) config->lastEntry = 0; | |||
if (config->lastEntry == config->firstEntry) config->firstEntry++; | |||
if (config->firstEntry > details::maxEntryIndex) config->firstEntry = 0; | |||
config::main::save(); | |||
hardware::i2c::powerOff(); | |||
} | |||
bool get(uint16_t index, PositionEntry &entry) { | |||
VERBOSE("get"); | |||
uint16_t entryAddress = details::getEntryAddress(index); | |||
if (entryAddress == -1) return false; | |||
VERBOSE_FORMAT("get", "Reading entry %d @ %X", index, entryAddress); | |||
hardware::i2c::powerOn(); | |||
hardware::i2c::eeprom.readBlock(entryAddress, entry); | |||
hardware::i2c::powerOff(); | |||
NOTICE_FORMAT("get", "Read from EEPROM @ %X : %d,%d,%d,%d,%d,%s", | |||
entryAddress, | |||
entry.metadata.batteryLevel, | |||
entry.metadata.batteryVoltage, | |||
entry.metadata.temperature, | |||
static_cast<uint8_t>(entry.metadata.status), | |||
entry.metadata.timeToFix, | |||
entry.position); | |||
return true; | |||
} | |||
bool moveNext(uint16_t &index) { | |||
if (index == config::main::value.lastEntry) return false; | |||
if (index == details::maxEntryIndex) index = 0; //could use a modulo but easier to understand that way | |||
else index++; | |||
return true; | |||
} | |||
uint16_t count(uint16_t fromIndex) { | |||
config_t *config = &config::main::value; | |||
uint16_t lastEntry = config->lastEntry; | |||
if (lastEntry < fromIndex) { lastEntry += details::maxEntryIndex; } | |||
return lastEntry - fromIndex; | |||
} | |||
void prepareBackup() { | |||
#if BACKUPS_ENABLED > 1 | |||
for (int i = 0; i < BACKUPS_ENABLED; i++) { | |||
_backups[i]->prepare(); | |||
} | |||
#elif BACKUPS_ENABLED == 1 | |||
_backup->prepare(); | |||
#endif | |||
} | |||
void doBackup(bool force) { | |||
#if BACKUPS_ENABLED > 1 | |||
for (int i = 0; i < BACKUPS_ENABLED; i++) { | |||
_backups[i]->backup(force); | |||
} | |||
#elif BACKUPS_ENABLED == 1 | |||
_backup->backup(force); | |||
#endif | |||
} | |||
} |
@@ -1,7 +1,7 @@ | |||
#include "Debug.h" | |||
#include "Rtc.h" | |||
#include "config/Pins.h" | |||
#include "config/Hardware.h" | |||
#include "Hardware.h" | |||
#include "Logging.h" | |||
#include <Wire.h> | |||
#include <uDS3231.h> | |||
@@ -2,7 +2,7 @@ | |||
#if BACKUP_ENABLE_SDCARD | |||
#include "SdCard.h" | |||
#include "config/Pins.h" | |||
#include "config/Hardware.h" | |||
namespace hardware { | |||
namespace sdcard { | |||
@@ -1,119 +1,119 @@ | |||
#include "SdPositionsBackup.h" | |||
#include "SdPositionsConfig.h" | |||
#include "SdCard.h" | |||
#include "Hardware.h" | |||
#include "Config.h" | |||
#include "Positions.h" | |||
#include "Debug.h" | |||
#define LOGGER_NAME "Positions::backup::sd" | |||
#if BACKUP_ENABLE_SDCARD | |||
namespace positions { | |||
namespace backup { | |||
namespace sd { | |||
namespace details { | |||
bool isBackupNeeded(SdPositionConfig_t &sdConfig) { | |||
Config_t referenceConfig = config::main::value; | |||
sdConfig = config::backup::sd::get(); | |||
return sdConfig.lastSavedEntry == 0xFFFF || | |||
positions::count(sdConfig.lastSavedEntry) > sdConfig.saveThreshold; | |||
} | |||
void getPositionsFileName(uint16_t fileIndex, char *buffer) { | |||
sprintf(buffer, POSITIONS_FILENAME, fileIndex); | |||
} | |||
void ensurePositionsFolder() { | |||
char positionsFolder[] = POSITIONS_FOLDER; | |||
hardware::sdcard::filesystem.chdir(); | |||
if (!hardware::sdcard::filesystem.exists(positionsFolder)) { | |||
hardware::sdcard::filesystem.mkdir(positionsFolder, true); | |||
} | |||
hardware::sdcard::filesystem.chdir(positionsFolder); | |||
} | |||
void selectFile(SdPositionConfig_t &sdConfig, File &file) { | |||
char positionFileName[POSITIONS_FILENAME_LENGTH]; | |||
if (sdConfig.fileRecords >= sdConfig.maxRecordsPerFile) { | |||
if (file.isOpen()) { | |||
file.close(); | |||
config::backup::sd::set(sdConfig); | |||
} | |||
sdConfig.fileIndex++; | |||
sdConfig.filePosition = 0; | |||
sdConfig.fileRecords = 0; | |||
} | |||
if (!file.isOpen()) { | |||
ensurePositionsFolder(); | |||
getPositionsFileName(sdConfig.fileIndex, positionFileName); | |||
file.open(positionFileName, O_RDWR | O_CREAT); | |||
} | |||
} | |||
void appendPosition(File &file, SdPositionConfig_t &sdConfig, PositionEntry &entry) { | |||
VERBOSE("appendPosition"); | |||
const char fieldTerminator = ','; | |||
file.printField(entry.metadata.batteryLevel, fieldTerminator); | |||
file.printField(entry.metadata.batteryVoltage, fieldTerminator); | |||
file.printField(entry.metadata.temperature, fieldTerminator); | |||
file.printField(entry.metadata.timeToFix, fieldTerminator); | |||
file.printField(static_cast<uint8_t>(entry.metadata.status), fieldTerminator); | |||
file.println(entry.position); | |||
sdConfig.filePosition = file.position(); | |||
} | |||
void appendPositions(SdPositionConfig_t &sdConfig) { | |||
VERBOSE("appendPositions"); | |||
uint16_t currentEntryIndex = sdConfig.lastSavedEntry + 1; | |||
PositionEntry currentEntry; | |||
File file; | |||
hardware::i2c::powerOn(); | |||
do { | |||
if (!positions::get(currentEntryIndex, currentEntry)) break; | |||
selectFile(sdConfig, file); | |||
appendPosition(file, sdConfig, currentEntry); | |||
sdConfig.lastSavedEntry = currentEntryIndex; | |||
} while (positions::moveNext(currentEntryIndex)); | |||
hardware::i2c::powerOff(); | |||
if (file.isOpen()) file.close(); | |||
config::backup::sd::set(sdConfig); | |||
} | |||
} | |||
void SdPositionsBackup::setup() { | |||
hardware::sdcard::setup(); | |||
} | |||
void SdPositionsBackup::backup(bool force) { | |||
VERBOSE("backup"); | |||
if (!hardware::sdcard::available) { | |||
VERBOSE_MSG("backup", "not available"); | |||
return; | |||
} | |||
SdPositionConfig_t sdConfig; | |||
if (!details::isBackupNeeded(sdConfig)) return; | |||
details::appendPositions(sdConfig); | |||
} | |||
} | |||
} | |||
} | |||
#include "SdPositionsBackup.h" | |||
#include "SdPositionsConfig.h" | |||
#include "SdCard.h" | |||
#include "Hardware.h" | |||
#include "Config.h" | |||
#include "Positions.h" | |||
#include "Logging.h" | |||
#define LOGGER_NAME "Positions::backup::sd" | |||
#if BACKUP_ENABLE_SDCARD | |||
namespace positions { | |||
namespace backup { | |||
namespace sd { | |||
namespace details { | |||
bool isBackupNeeded(SdPositionConfig_t &sdConfig) { | |||
Config_t referenceConfig = config::main::value; | |||
sdConfig = config::backup::sd::get(); | |||
return sdConfig.lastSavedEntry == 0xFFFF || | |||
positions::count(sdConfig.lastSavedEntry) > sdConfig.saveThreshold; | |||
} | |||
void getPositionsFileName(uint16_t fileIndex, char *buffer) { | |||
sprintf(buffer, POSITIONS_FILENAME, fileIndex); | |||
} | |||
void ensurePositionsFolder() { | |||
char positionsFolder[] = POSITIONS_FOLDER; | |||
hardware::sdcard::filesystem.chdir(); | |||
if (!hardware::sdcard::filesystem.exists(positionsFolder)) { | |||
hardware::sdcard::filesystem.mkdir(positionsFolder, true); | |||
} | |||
hardware::sdcard::filesystem.chdir(positionsFolder); | |||
} | |||
void selectFile(SdPositionConfig_t &sdConfig, File &file) { | |||
char positionFileName[POSITIONS_FILENAME_LENGTH]; | |||
if (sdConfig.fileRecords >= sdConfig.maxRecordsPerFile) { | |||
if (file.isOpen()) { | |||
file.close(); | |||
config::backup::sd::set(sdConfig); | |||
} | |||
sdConfig.fileIndex++; | |||
sdConfig.filePosition = 0; | |||
sdConfig.fileRecords = 0; | |||
} | |||
if (!file.isOpen()) { | |||
ensurePositionsFolder(); | |||
getPositionsFileName(sdConfig.fileIndex, positionFileName); | |||
file.open(positionFileName, O_RDWR | O_CREAT); | |||
} | |||
} | |||
void appendPosition(File &file, SdPositionConfig_t &sdConfig, PositionEntry &entry) { | |||
VERBOSE("appendPosition"); | |||
const char fieldTerminator = ','; | |||
file.printField(entry.metadata.batteryLevel, fieldTerminator); | |||
file.printField(entry.metadata.batteryVoltage, fieldTerminator); | |||
file.printField(entry.metadata.temperature, fieldTerminator); | |||
file.printField(entry.metadata.timeToFix, fieldTerminator); | |||
file.printField(static_cast<uint8_t>(entry.metadata.status), fieldTerminator); | |||
file.println(entry.position); | |||
sdConfig.filePosition = file.position(); | |||
} | |||
void appendPositions(SdPositionConfig_t &sdConfig) { | |||
VERBOSE("appendPositions"); | |||
uint16_t currentEntryIndex = sdConfig.lastSavedEntry + 1; | |||
PositionEntry currentEntry; | |||
File file; | |||
hardware::i2c::powerOn(); | |||
do { | |||
if (!positions::get(currentEntryIndex, currentEntry)) break; | |||
selectFile(sdConfig, file); | |||
appendPosition(file, sdConfig, currentEntry); | |||
sdConfig.lastSavedEntry = currentEntryIndex; | |||
} while (positions::moveNext(currentEntryIndex)); | |||
hardware::i2c::powerOff(); | |||
if (file.isOpen()) file.close(); | |||
config::backup::sd::set(sdConfig); | |||
} | |||
} | |||
void SdPositionsBackup::setup() { | |||
hardware::sdcard::setup(); | |||
} | |||
void SdPositionsBackup::backup(bool force) { | |||
VERBOSE("backup"); | |||
if (!hardware::sdcard::available) { | |||
VERBOSE_MSG("backup", "not available"); | |||
return; | |||
} | |||
SdPositionConfig_t sdConfig; | |||
if (!details::isBackupNeeded(sdConfig)) return; | |||
details::appendPositions(sdConfig); | |||
} | |||
} | |||
} | |||
} | |||
#endif |
@@ -1,71 +1,71 @@ | |||
#include "SdPositionsConfig.h" | |||
#include "SdCard.h" | |||
#include "Debug.h" | |||
#define LOGGER_NAME "Config::backup::sd" | |||
#if BACKUP_ENABLE_SDCARD | |||
namespace config { | |||
namespace backup { | |||
namespace sd { | |||
SdPositionConfig_t value; | |||
File configFile; | |||
namespace details { | |||
void ensureOpened() { | |||
if (!configFile.isOpen()) { | |||
hardware::sdcard::filesystem.chdir(); | |||
configFile.open(POSITIONS_CONFIG_FILENAME, O_RDWR | O_CREAT); | |||
} | |||
configFile.rewind(); | |||
} | |||
void read() { | |||
VERBOSE("read"); | |||
ensureOpened(); | |||
configFile.read((void*)&value, sizeof(value)); | |||
if (value.seed != POSITIONS_CONFIG_SEED) reset(); | |||
} | |||
void write() { | |||
VERBOSE("write"); | |||
ensureOpened(); | |||
configFile.write((void*)&value, sizeof(value)); | |||
} | |||
} | |||
SdPositionConfig_t get() { | |||
if (value.seed != POSITIONS_CONFIG_SEED) details::read(); | |||
return value; | |||
} | |||
void set(SdPositionConfig_t config) { | |||
value = config; | |||
details::write(); | |||
} | |||
void reset() { | |||
VERBOSE("reset"); | |||
SdPositionConfig_t config = { | |||
POSITIONS_CONFIG_SEED, | |||
POSITIONS_CONFIG_DEFAULT_SAVE_THRESHOLD, | |||
POSITIONS_CONFIG_DEFAULT_MAX_RECORDS_PER_FILE, | |||
0xFFFF, | |||
0, | |||
0, | |||
0 | |||
}; | |||
value = config; | |||
details::write(); | |||
} | |||
} | |||
} | |||
} | |||
#include "SdPositionsConfig.h" | |||
#include "SdCard.h" | |||
#include "Logging.h" | |||
#define LOGGER_NAME "Config::backup::sd" | |||
#if BACKUP_ENABLE_SDCARD | |||
namespace config { | |||
namespace backup { | |||
namespace sd { | |||
SdPositionConfig_t value; | |||
File configFile; | |||
namespace details { | |||
void ensureOpened() { | |||
if (!configFile.isOpen()) { | |||
hardware::sdcard::filesystem.chdir(); | |||
configFile.open(POSITIONS_CONFIG_FILENAME, O_RDWR | O_CREAT); | |||
} | |||
configFile.rewind(); | |||
} | |||
void read() { | |||
VERBOSE("read"); | |||
ensureOpened(); | |||
configFile.read((void*)&value, sizeof(value)); | |||
if (value.seed != POSITIONS_CONFIG_SEED) reset(); | |||
} | |||
void write() { | |||
VERBOSE("write"); | |||
ensureOpened(); | |||
configFile.write((void*)&value, sizeof(value)); | |||
} | |||
} | |||
SdPositionConfig_t get() { | |||
if (value.seed != POSITIONS_CONFIG_SEED) details::read(); | |||
return value; | |||
} | |||
void set(SdPositionConfig_t config) { | |||
value = config; | |||
details::write(); | |||
} | |||
void reset() { | |||
VERBOSE("reset"); | |||
SdPositionConfig_t config = { | |||
POSITIONS_CONFIG_SEED, | |||
POSITIONS_CONFIG_DEFAULT_SAVE_THRESHOLD, | |||
POSITIONS_CONFIG_DEFAULT_MAX_RECORDS_PER_FILE, | |||
0xFFFF, | |||
0, | |||
0, | |||
0 | |||
}; | |||
value = config; | |||
details::write(); | |||
} | |||
} | |||
} | |||
} | |||
#endif |
@@ -3,6 +3,9 @@ | |||
*/ | |||
#pragma once | |||
#include <E24.h> | |||
#include <SoftwareSerial.h> | |||
#define SIM_RST 5 ///< SIM808 RESET | |||
#define SIM_RX 6 ///< SIM808 RXD | |||
#define SIM_TX 7 ///< SIM808 TXD | |||
@@ -14,3 +17,8 @@ | |||
#define SIM_RI 2 ///< Interrupt pin connected to SIM RI. | |||
#define RTC_WAKE 3 ///< Interrupt pin connected to DS3231 !INT/SQW | |||
#define E24_ADDRESS E24_DEFAULT_ADDR ///< I2C address of the 24xxx chip | |||
#define SIM_SERIAL_TYPE SoftwareSerial ///< Type of variable that holds the Serial communication with SIM808 | |||
#define SIM_SERIAL SIM_SERIAL_TYPE(SIM_TX, SIM_RX) ///< Definition of the instance that holds the Serial communication with SIM808 |
@@ -34,4 +34,10 @@ | |||
When hooked up on Serial port, determine how much milliseconds | |||
to wait for a user input before proceeding. | |||
*/ | |||
#define MENU_TIMEOUT 20000 | |||
#if _DEBUG | |||
#define MENU_TIMEOUT 0 | |||
#else | |||
#define MENU_TIMEOUT 20000 | |||
#endif | |||
#define MENU_INTERMEDIATE_TIMEOUT 50 |