Browse Source

Moved defines and include around

tags/v1.2.2
Bertrand Lemasle 6 years ago
parent
commit
ffc030d011
22 changed files with 1494 additions and 1497 deletions
  1. +50
    -50
      src/Alerts.cpp
  2. +85
    -85
      src/Config.cpp
  3. +160
    -159
      src/Core.cpp
  4. +0
    -2
      src/Core.h
  5. +290
    -299
      src/Debug.cpp
  6. +53
    -61
      src/Debug.h
  7. +117
    -117
      src/Gps.cpp
  8. +0
    -10
      src/GpsTracker.h
  9. +97
    -95
      src/GpsTracker.ino
  10. +4
    -7
      src/Hardware.cpp
  11. +30
    -30
      src/Hardware.h
  12. +10
    -2
      src/MainUnit.cpp
  13. +8
    -7
      src/MainUnit.h
  14. +75
    -75
      src/Network.cpp
  15. +113
    -111
      src/NetworkPositionsBackup.cpp
  16. +195
    -194
      src/Positions.cpp
  17. +3
    -3
      src/Rtc.cpp
  18. +1
    -1
      src/SdCard.cpp
  19. +118
    -118
      src/SdPositionsBackup.cpp
  20. +70
    -70
      src/SdPositionsConfig.cpp
  21. +8
    -0
      src/config/Hardware.h
  22. +7
    -1
      src/config/System.h

+ 50
- 50
src/Alerts.cpp View File

@@ -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();
}
}

+ 85
- 85
src/Config.cpp View File

@@ -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();
}
}
} }

+ 160
- 159
src/Core.cpp View File

@@ -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;
}
} }

+ 0
- 2
src/Core.h View File

@@ -2,12 +2,10 @@
#include <Arduino.h> #include <Arduino.h>
#include "Debug.h"
#include "Gps.h" #include "Gps.h"
#include "MainUnit.h" #include "MainUnit.h"
#include "Network.h" #include "Network.h"
#include "Rtc.h" #include "Rtc.h"
#include "config/Pins.h"
#include "Positions.h" #include "Positions.h"
enum class TRACKER_MOVING_STATE : uint8_t { enum class TRACKER_MOVING_STATE : uint8_t {


+ 290
- 299
src/Debug.cpp View File

@@ -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);
}
} }

+ 53
- 61
src/Debug.h View File

@@ -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();
}

+ 117
- 117
src/Gps.cpp View File

@@ -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);
}
} }

+ 0
- 10
src/GpsTracker.h View File

@@ -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"

+ 97
- 95
src/GpsTracker.ino View File

@@ -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");
}
}

+ 4
- 7
src/Hardware.cpp View File

@@ -1,22 +1,19 @@
#include "Config.h" #include "Config.h"
#include "Hardware.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.h>
#include <SIM808_Types.h>
#include <Wire.h> #include <Wire.h>
#include <E24.h> #include <E24.h>
namespace hardware { namespace hardware {
#define LOGGER_NAME "Hardware::sim808" #define LOGGER_NAME "Hardware::sim808"
namespace 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); SIM808 device = SIM808(SIM_RST, SIM_PWR, SIM_STATUS);
uint8_t networkPoweredCount = 0; uint8_t networkPoweredCount = 0;
uint8_t gpsPoweredCount = 0; uint8_t gpsPoweredCount = 0;
@@ -119,7 +116,7 @@ namespace hardware {
namespace i2c { namespace i2c {
E24 eeprom = E24(E24Size_t::E24_512K);
E24 eeprom = E24(E24Size_t::E24_512K, E24_ADDRESS);
uint8_t poweredCount = 0; uint8_t poweredCount = 0;
void powerOn() { void powerOn() {


+ 30
- 30
src/Hardware.h View File

@@ -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);
}
} }

+ 10
- 2
src/MainUnit.cpp View File

@@ -1,10 +1,13 @@
#include "MainUnit.h" #include "MainUnit.h"
#include "Rtc.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" #define LOGGER_NAME "MainUnit"
extern int __heap_start, *__brkval;
namespace mainunit { namespace mainunit {
namespace details { namespace details {
@@ -42,4 +45,9 @@ namespace mainunit {
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
details::wokeUp(); details::wokeUp();
} }
int freeRam() {
int v;
return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
}
} }

+ 8
- 7
src/MainUnit.h View File

@@ -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();
} }

+ 75
- 75
src/Network.cpp View File

@@ -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);
}
} }

+ 113
- 111
src/NetworkPositionsBackup.cpp View File

@@ -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 #endif

+ 195
- 194
src/Positions.cpp View File

@@ -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
}
} }

+ 3
- 3
src/Rtc.cpp View File

@@ -1,7 +1,7 @@
#include "Debug.h"
#include "Rtc.h" #include "Rtc.h"
#include "config/Pins.h"
#include "config/Hardware.h"
#include "Hardware.h"
#include "Logging.h"
#include <Wire.h> #include <Wire.h>
#include <uDS3231.h> #include <uDS3231.h>


+ 1
- 1
src/SdCard.cpp View File

@@ -2,7 +2,7 @@
#if BACKUP_ENABLE_SDCARD #if BACKUP_ENABLE_SDCARD
#include "SdCard.h" #include "SdCard.h"
#include "config/Pins.h"
#include "config/Hardware.h"
namespace hardware { namespace hardware {
namespace sdcard { namespace sdcard {


+ 118
- 118
src/SdPositionsBackup.cpp View File

@@ -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 #endif

+ 70
- 70
src/SdPositionsConfig.cpp View File

@@ -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 #endif

src/config/Pins.h → src/config/Hardware.h View File

@@ -3,6 +3,9 @@
*/ */
#pragma once #pragma once
#include <E24.h>
#include <SoftwareSerial.h>
#define SIM_RST 5 ///< SIM808 RESET #define SIM_RST 5 ///< SIM808 RESET
#define SIM_RX 6 ///< SIM808 RXD #define SIM_RX 6 ///< SIM808 RXD
#define SIM_TX 7 ///< SIM808 TXD #define SIM_TX 7 ///< SIM808 TXD
@@ -14,3 +17,8 @@
#define SIM_RI 2 ///< Interrupt pin connected to SIM RI. #define SIM_RI 2 ///< Interrupt pin connected to SIM RI.
#define RTC_WAKE 3 ///< Interrupt pin connected to DS3231 !INT/SQW #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

+ 7
- 1
src/config/System.h View File

@@ -34,4 +34,10 @@
When hooked up on Serial port, determine how much milliseconds When hooked up on Serial port, determine how much milliseconds
to wait for a user input before proceeding. 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

Loading…
Cancel
Save