Bladeren bron

Merge branch 'network-backup'

tags/v1.2.0
Bertrand Lemasle 7 jaren geleden
bovenliggende
commit
589acf16d8
32 gewijzigde bestanden met toevoegingen van 908 en 224 verwijderingen
  1. +58
    -37
      GpsTracker/Config.cpp
  2. +64
    -23
      GpsTracker/Config.h
  3. +30
    -11
      GpsTracker/Core.cpp
  4. +2
    -2
      GpsTracker/Core.h
  5. +52
    -37
      GpsTracker/Debug.cpp
  6. +28
    -50
      GpsTracker/Debug.h
  7. +6
    -4
      GpsTracker/Gps.cpp
  8. +1
    -1
      GpsTracker/Gps.h
  9. +0
    -1
      GpsTracker/GpsTracker.h
  10. +20
    -10
      GpsTracker/GpsTracker.ino
  11. +6
    -11
      GpsTracker/Hardware.cpp
  12. +2
    -0
      GpsTracker/Hardware.h
  13. +18
    -0
      GpsTracker/Logging.cpp
  14. +35
    -0
      GpsTracker/Logging.h
  15. +23
    -6
      GpsTracker/MainUnit.cpp
  16. +45
    -1
      GpsTracker/Network.cpp
  17. +4
    -0
      GpsTracker/Network.h
  18. +93
    -0
      GpsTracker/NetworkPositionsBackup.cpp
  19. +18
    -0
      GpsTracker/NetworkPositionsBackup.h
  20. +15
    -0
      GpsTracker/NetworkPositionsConfig.h
  21. +75
    -27
      GpsTracker/Positions.cpp
  22. +4
    -2
      GpsTracker/Positions.h
  23. +9
    -0
      GpsTracker/PositionsBackup.cpp
  24. +14
    -0
      GpsTracker/PositionsBackup.h
  25. +10
    -1
      GpsTracker/Rtc.cpp
  26. +1
    -0
      GpsTracker/Rtc.h
  27. +18
    -0
      GpsTracker/SdCard.cpp
  28. +14
    -0
      GpsTracker/SdCard.h
  29. +119
    -0
      GpsTracker/SdPositionsBackup.cpp
  30. +18
    -0
      GpsTracker/SdPositionsBackup.h
  31. +71
    -0
      GpsTracker/SdPositionsConfig.cpp
  32. +35
    -0
      GpsTracker/SdPositionsConfig.h

+ 58
- 37
GpsTracker/Config.cpp Bestand weergeven

@@ -5,53 +5,74 @@
#define LOGGER_NAME "Config"

namespace config {
Config value;
namespace main {

namespace details {
config_t value;

void read() {
VERBOSE("read");
hardware::i2c::powerOn();
hardware::i2c::eeprom.readBlock(CONFIG_ADDR, value);
if (!String(CONFIG_SEED).equals(value.seed)) reset();
hardware::i2c::powerOff();
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", value.seed, value.version, value.firstEntry, value.lastEntry);
#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
}

void write() {
NOTICE_FORMAT("write", "%d, %s, %d, %d", value.seed, value.version, value.firstEntry, value.lastEntry);
#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 write() {
VERBOSE_FORMAT("write", "%s, %s, %s, %d, %d", value.seed, value.version, value.apn, value.firstEntry, value.lastEntry);
void setup() {
details::read();
//details::write();
}

hardware::i2c::powerOn();
int written = hardware::i2c::eeprom.writeBlock(CONFIG_ADDR, value);
hardware::i2c::powerOff();
void save() {
details::write();
}
}

Config get() {
if (value.seed[0] == '\0') details::read();
void reset() {
VERBOSE("reset");

VERBOSE_FORMAT("get", "%s, %s, %s, %d, %d", value.seed, value.version, value.apn, value.firstEntry, value.lastEntry);
return value;
}
config_t config = {
CONFIG_SEED,
VERSION,
0xFFFF,
0xFFFF,
#if BACKUP_ENABLE_NETWORK
{
POSITIONS_CONFIG_NET_DEFAULT_SAVE_THRESHOLD,
0xFFFF,
POSITIONS_CONFIG_NET_DEFAULT_APN,
POSITIONS_CONFIG_NET_DEFAULT_URL,
},
#endif
};

void set(Config config) {
value = config;
details::write();
}
value = config;
save();
}

void reset() {
VERBOSE("reset");
Config config = {
CONFIG_SEED,
VERSION,
"Vodafone", //TODO : read from SD
0xFFFF,
0xFFFF,
};

value = config;
details::write();
}

}

+ 64
- 23
GpsTracker/Config.h Bestand weergeven

@@ -2,44 +2,85 @@

#include <Arduino.h>

#define BACKUP_ENABLE_SDCARD 0
#define BACKUP_ENABLE_NETWORK 1

#if BACKUP_ENABLE_NETWORK
#include "NetworkPositionsConfig.h"
#endif

#define SIM808_BAUDRATE 4800

#define CONFIG_ADDR 0
#define CONFIG_RESERVED_SIZE 128
#define CONFIG_SEED 13
#define VERSION "1.00"

#pragma region Default configuration values

#define MENU_TIMEOUT 10000
/**
\def SLEEP_DEFAULT_TIME_SECONDS
Hard coded value for default sleep time between position acquisitions.
Exprimed in seconds
*/
#define SLEEP_DEFAULT_TIME_SECONDS 1800
#define SLEEP_DEFAULT_INCREASE_THRESHOLD 3

#define GPS_DEFAULT_INTERMEDIATE_TIMEOUT_MS 10000
#define GPS_DEFAULT_TOTAL_TIMEOUT_MS 180000

#define NETWORK_DEFAULT_INTERMEDIATE_TIMEOUT_MS 6000
#define NETWORK_DEFAULT_TOTAL_TIMEOUT_MS 180000
#define NETWORK_DEFAULT_NO_NETWORK_QUALIRY_THRESHOLD 8
#define NETWORK_DEFAULT_NO_NETWORK_TRIES 5

#pragma endregion

#define SLEEP_TIMING_TIME(hours, minutes) hours * 60 + minutes
#define SLEEP_TIMING_MIN SLEEP_TIMING_TIME(0, 0)
#define SLEEP_TIMING_MAX SLEEP_TIMING_TIME(23, 59)

struct sleepTimings_t {
uint8_t speed;
uint16_t timeMin;
uint16_t timeMax;
uint16_t seconds;
};

struct Config {
char seed[5];
struct config_t {
uint8_t seed;
char version[5];
char apn[20];
uint16_t firstEntry;
uint16_t lastEntry;
#if BACKUP_ENABLE_NETWORK
networkConfig_t network;
#endif
};

#define CONFIG_ADDR 0
#define CONFIG_SEED "UIYA"
#define VERSION "1.00"

#define SLEEP_DEFAULT_TIME_SECONDS 1800

#define GPS_DEFAULT_INTERMEDIATE_TIMEOUT_MS 10000
#define GPS_DEFAULT_TOTAL_TIMEOUT_MS 180000

namespace config {

static const sleepTimings_t defaultSleepTimings[] PROGMEM = {
{ 5, SLEEP_DEFAULT_TIME_SECONDS },
{ 10, 1200 },
{ 20, 600 },
{ 30, 540 },
{ 50, 480 },
{ 80, 240 },
{ 100, 210 },
{ 180, 180 },
{ 3, SLEEP_TIMING_TIME(16, 00), SLEEP_TIMING_TIME(19, 59), 3600 },
{ 3, SLEEP_TIMING_TIME(20, 00), SLEEP_TIMING_MAX, SLEEP_DEFAULT_TIME_SECONDS },
{ 3, SLEEP_TIMING_MIN, SLEEP_TIMING_TIME(8, 29), SLEEP_DEFAULT_TIME_SECONDS },
{ 3, SLEEP_TIMING_TIME(8, 30), SLEEP_TIMING_TIME(15, 59), 10800 },

{ 5, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 900 },
{ 20, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 600 },
{ 30, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 540 },
{ 50, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 480 },
{ 80, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 240 },
{ 100, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 210 },
{ 180, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 180 },
};

Config get();
void set(Config config);
namespace main {
extern config_t value;

void reset();
void setup();
void save();

void reset();
}
}

+ 30
- 11
GpsTracker/Core.cpp Bestand weergeven

@@ -8,38 +8,57 @@ using namespace utils;

namespace core {
uint16_t sleepTime = SLEEP_DEFAULT_TIME_SECONDS;;
uint8_t increaseInARow = 0;

void main() {
VERBOSE("main");

PositionEntryMetadata metadata;
if (positions::acquire(metadata)) {
positions::appendLast(metadata);
setSleepTime();
updateSleepTime(gps::getVelocity());
}

if (positions::needsToSend()) {
positions::send();
}
positions::doBackup();
mainunit::deepSleep(sleepTime);
}

void setSleepTime() {
setSleepTime(gps::getVelocity());
void updateSleepTime(uint8_t velocity) {
uint16_t result = computeSleepTime(velocity);

if (result > sleepTime) {
increaseInARow++;
if (increaseInARow < SLEEP_DEFAULT_INCREASE_THRESHOLD) return;

}
else increaseInARow = 0;

sleepTime = result;
NOTICE_FORMAT("updateSleepTime", "%dkmh => %d seconds", velocity, sleepTime);
}

void setSleepTime(uint8_t velocity) {
sleepTime = SLEEP_DEFAULT_TIME_SECONDS;
uint16_t computeSleepTime(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 = 0; 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;

sleepTime = timing.seconds;
result = timing.seconds;
break;
}

VERBOSE_FORMAT("setSleepTime", "%d", sleepTime);
VERBOSE_FORMAT("computeSleepTime", "%d,%d", velocity, result);
return result;
}
}

+ 2
- 2
GpsTracker/Core.h Bestand weergeven

@@ -14,6 +14,6 @@ namespace core {
extern uint16_t sleepTime;

void main();
void setSleepTime(uint8_t velocity);
void setSleepTime();
void updateSleepTime(uint8_t velocity);
uint16_t computeSleepTime(uint8_t velocity);
}

+ 52
- 37
GpsTracker/Debug.cpp Bestand weergeven

@@ -1,15 +1,16 @@
#include "Debug.h"
#include "Flash.h"
#include "Positions.h"
#include "Core.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,67.99,172.6,1,,1.3,2.2,1.8,,11,7,,,37,,";
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, "-- Debug Menu --");
MENU_ENTRY(SEPARATOR, "----");
MENU_ENTRY(HEADER, "========================\n-- Menu --");
MENU_ENTRY(SEPARATOR, "----");

MENU_ENTRY(RUN, "[R] Run");
MENU_ENTRY(RUN_ONCE, "[r] Run once");
@@ -21,13 +22,13 @@ 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(SD_WRITE_TEST, "[W] Write to test file");
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(SLEEP, "[S] Sleep for 8s");
MENU_ENTRY(SLEEP_DEEP, "[s] Deep sleep for 10s");
MENU_ENTRY(QUESTION, "?");
@@ -43,13 +44,13 @@ const PROGMEM uint8_t commandIdMapping[] = {
'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),
'W', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::SD_WRITE_TEST),
'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),
'S', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::SLEEP),
's', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP),
};
@@ -78,17 +79,13 @@ const char * const MENU_ENTRIES[] PROGMEM = {

MENU_SEPARATOR,

MENU_SD_WRITE_TEST,

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_SLEEP,
@@ -109,20 +106,18 @@ namespace debug {

namespace details {
inline void displayPosition(PositionEntry entry) {
Log.notice(F("%d%%, %dmV, %f°C, %ds %d, %s\n"), entry.metadata.batteryLevel, entry.metadata.batteryVoltage, entry.metadata.temperature, entry.metadata.timeToFix, entry.metadata.status, entry.position);
Log.notice(F("%d%%, %dmV, %f°C, %ds, %d, %s\n"), entry.metadata.batteryLevel, entry.metadata.batteryVoltage, entry.metadata.temperature, entry.metadata.timeToFix, entry.metadata.status, entry.position);
}
}

void waitForSerial() {
while (!Serial);
Serial.begin(DEBUG_SERIAL_SPEED);
Serial.println("Starting !");
}

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;
@@ -135,20 +130,28 @@ namespace debug {
return GPSTRACKER_DEBUG_COMMAND::NONE;
}

GPSTRACKER_DEBUG_COMMAND menu() {
if (!Serial) return GPSTRACKER_DEBUG_COMMAND::RUN;

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());
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();
while (Serial.available()) Serial.read(); //flushing input
} while (command == GPSTRACKER_DEBUG_COMMAND::NONE);
return command;
@@ -164,6 +167,8 @@ namespace debug {
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::computeSleepTime(gps::getVelocity()));
}

void getAndDisplayBattery() {
@@ -181,8 +186,26 @@ namespace debug {
NOTICE_FORMAT("getAndDisplayRtcTime", "%d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second);
}

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::computeSleepTime(i);
}

NOTICE_MSG("getAndDisplaySleepTimes", "Done");
}

void getAndDisplayEepromConfig() {
config::get();
config::main::setup(); //forcing read again
}

void getAndDisplayEepromContent() {
@@ -202,7 +225,7 @@ namespace debug {
}

void getAndDisplayEepromPositions() {
uint16_t currentEntryIndex = config::get().firstEntry;
uint16_t currentEntryIndex = config::main::value.firstEntry;
PositionEntry currentEntry;

hardware::i2c::powerOn();
@@ -214,11 +237,11 @@ namespace debug {
}

void getAndDisplayEepromLastPosition() {
uint16_t lastEntryIndex = config::get().lastEntry;
uint16_t lastEntryIndex = config::main::value.lastEntry;
PositionEntry lastEntry;

positions::get(lastEntryIndex, lastEntry);
details::displayPosition(lastEntry);
if(positions::get(lastEntryIndex, lastEntry)) details::displayPosition(lastEntry);
else Log.notice(F("No position recorded\n"));
}

void addLastPositionToEeprom() {
@@ -234,14 +257,6 @@ namespace debug {
SIM808_GPS_STATUS::OFF
};

positions::appendLast(metadata);
}

void setRtcTime() {
tmElements_t time;
gps::getTime(time);
rtc::setTime(time);

NOTICE_MSG("setRtcTime", "Done");
for(int i = 0; i < 10; i++) positions::appendLast(metadata);
}
}

+ 28
- 50
GpsTracker/Debug.h Bestand weergeven

@@ -1,67 +1,44 @@
#pragma once

#include <Arduino.h>
#include <ArduinoLog.h>

#include "Config.h"
#include "Logging.h"

#include "Core.h"

#include "Hardware.h"
#include "Gps.h"
#include "Rtc.h"

#define LOG(level, f) Log.level(F("[" LOGGER_NAME "::" f "]\n"))
#define LOG_MSG(level, f, msg) Log.level(F("[" LOGGER_NAME "::" f "] " msg "\n"))
#define LOG_FORMAT(level, f, msg, ...) Log.level(F("[" LOGGER_NAME "::" f "] " msg "\n"), __VA_ARGS__)

#ifdef _DEBUG

#define VERBOSE(f) LOG(verbose, f)
#define VERBOSE_MSG(f, msg) LOG_MSG(verbose, f, msg)
#define VERBOSE_FORMAT(f, msg, ...) LOG_FORMAT(verbose, f, msg, __VA_ARGS__)
#else

#define DISABLE_LOGGING 1 //TODO : does nothing if not included before ArduinoLog.h

#define VERBOSE(f)
#define VERBOSE_MSG(f, msg)
#define VERBOSE_FORMAT(f, msg, ...)

#endif

#define NOTICE(f) LOG(notice, f)
#define NOTICE_MSG(f, msg) LOG_MSG(notice, f, msg)
#define NOTICE_FORMAT(f, msg, ...) LOG_FORMAT(notice, f, msg, __VA_ARGS__)

#define DEBUG_SERIAL_SPEED 115200

namespace debug {

enum class GPSTRACKER_DEBUG_COMMAND : uint8_t {
NONE = 0,
RUN = 1,
ONCE = 2,
RAM = 3,
BATTERY = 4,
GPS_ON = 5,
GPS_OFF = 6,
GPS_GET = 7,
GPS_SET = 8,
RTC_GET = 11,
RTC_SET = 12,
SD_WRITE_TEST = 13,
EEPROM_GET_CONFIG = 14,
EEPROM_RESET_CONFIG = 15,
EEPROM_GET_CONTENT = 16,
EEPROM_GET_LAST_ENTRY = 17,
EEPROM_GET_ENTRIES = 18,
EEPROM_ADD_ENTRY = 19,
SLEEP = 20,
SLEEP_DEEP = 21
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,
SLEEP,
SLEEP_DEEP
};

void waitForSerial();
int freeRam();
void displayFreeRam();

GPSTRACKER_DEBUG_COMMAND menu();
GPSTRACKER_DEBUG_COMMAND menu(uint16_t timeout);

void getAndDisplayBattery();
void getAndDisplayGpsPosition();
@@ -70,12 +47,13 @@ namespace debug {
void getAndDisplayRtcTime();
void setRtcTime();

void getAndDisplaySleepTimes();

void getAndDisplayEepromConfig();
void getAndDisplayEepromContent();
void getAndDisplayEepromPositions();
void getAndDisplayEepromLastPosition();
void addLastPositionToEeprom();

inline void displayFreeRam() { Serial.println(freeRam()); }

}

+ 6
- 4
GpsTracker/Gps.cpp Bestand weergeven

@@ -25,13 +25,14 @@ namespace gps {
char lastPosition[GPS_POSITION_SIZE];
SIM808_GPS_STATUS lastStatus;

SIM808_GPS_STATUS acquireCurrentPosition(uint16_t timeout) {
SIM808_GPS_STATUS acquireCurrentPosition(uint32_t timeout) {
SIM808_GPS_STATUS currentStatus = SIM808_GPS_STATUS::OFF;

do {
currentStatus = hardware::sim808::device.getGpsStatus();
if (currentStatus > SIM808_GPS_STATUS::NO_FIX) break;
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);
@@ -41,12 +42,13 @@ namespace gps {
hardware::sim808::device.getGpsPosition(lastPosition);
}

NOTICE_FORMAT("acquireCurrentPosition", "%d", currentStatus);
return currentStatus;
}

uint8_t getVelocity() {
uint8_t velocity;
hardware::sim808::device.getGpsField(lastPosition, SIM808_GPS_FIELD::SPEED, &velocity);
if (!hardware::sim808::device.getGpsField(lastPosition, SIM808_GPS_FIELD::SPEED, &velocity)) velocity = 0;

VERBOSE_FORMAT("getVelocity", "%d", velocity);

@@ -67,6 +69,6 @@ namespace gps {
time.Minute = details::parseSubstring(buffer, timeStr + TIME_MINUTE_OFFSET, 2);
time.Second = details::parseSubstring(buffer, timeStr + TIME_SECOND_OFFSET, 2);

VERBOSE_FORMAT("getTime", "%d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second);
NOTICE_FORMAT("getTime", "%d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second);
}
}

+ 1
- 1
GpsTracker/Gps.h Bestand weergeven

@@ -15,7 +15,7 @@ namespace gps {
inline void powerOn() { hardware::sim808::gpsPowerOn(); }
inline void powerOff() { hardware::sim808::gpsPowerOff(); }

SIM808_GPS_STATUS acquireCurrentPosition(uint16_t timeout);
SIM808_GPS_STATUS acquireCurrentPosition(uint32_t timeout);

uint8_t getVelocity();
void getTime(tmElements_t &time);

+ 0
- 1
GpsTracker/GpsTracker.h Bestand weergeven

@@ -1,7 +1,6 @@
#pragma once

#include <Arduino.h>
#include <SoftwareSerial.h>
#include <SIM808.h>

#include "Debug.h"


+ 20
- 10
GpsTracker/GpsTracker.ino Bestand weergeven

@@ -1,24 +1,32 @@
#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() {
#ifdef _DEBUG
debug::waitForSerial();
Log.begin(LOG_LEVEL_VERBOSE, &Serial);
#else
if(Serial) Log.begin(LOG_LEVEL_NOTICE, &Serial);
#endif
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(!bypassMenu) command = debug::menu();
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;

@@ -55,7 +63,7 @@ void loop() {
debug::getAndDisplayEepromConfig();
break;
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_RESET_CONFIG:
config::reset();
config::main::reset();
break;
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_CONTENT:
debug::getAndDisplayEepromContent();
@@ -69,14 +77,16 @@ void loop() {
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_ADD_ENTRY:
debug::addLastPositionToEeprom();
break;
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_BACKUP_ENTRIES:
positions::doBackup();
break;
case debug::GPSTRACKER_DEBUG_COMMAND::SLEEP:
mainunit::sleep(period_t::SLEEP_8S);
break;
case debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP:
mainunit::deepSleep(10);
break;
case debug::GPSTRACKER_DEBUG_COMMAND::SD_WRITE_TEST:
default:
Serial.println(F("Unsupported command !"));
NOTICE_MSG("loop", "Unsupported");
}
}

+ 6
- 11
GpsTracker/Hardware.cpp Bestand weergeven

@@ -1,3 +1,4 @@
#include "Config.h"
#include "Hardware.h"
#include "Pins.h"
#include "Debug.h"
@@ -41,12 +42,10 @@ namespace hardware {
}

void setup() {
VERBOSE("setup");
device.powerOnOff(true);
simSerial.begin(4800);

NOTICE("setup");
simSerial.begin(SIM808_BAUDRATE);
device.begin(simSerial);
device.powerOnOff(false);
powerOff(); //ensure powerOff on start
}

void gpsPowerOn() {
@@ -56,7 +55,7 @@ namespace hardware {
}

void gpsPowerOff() {
VERBOSE("gpsPowerOff");
NOTICE("gpsPowerOff");
device.disableGps();
powerOffIfUnused();
}
@@ -65,13 +64,12 @@ namespace hardware {
VERBOSE("networkPowerOn");
powerOn();
device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::FULL);
device.enableGprs(config::get().apn);
}

void networkPowerOff() {
VERBOSE("networkPowerOff");
device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::MINIMUM);
device.disableGprs();
device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::MINIMUM);

powerOffIfUnused();
}
@@ -82,11 +80,8 @@ namespace hardware {
namespace i2c {

E24 eeprom = E24(E24Size_t::E24_512K);

uint8_t poweredCount = 0;

//inline void powered() { digitalRead(I2C_PWR) == HIGH; } //TODO = replace enum with just reading the output pin ?

void powerOn() {
if (!poweredCount) {
VERBOSE("powerOn");


+ 2
- 0
GpsTracker/Hardware.h Bestand weergeven

@@ -1,11 +1,13 @@
#pragma once

#include <SoftwareSerial.h>
#include <SIM808.h>
#include <E24.h>

namespace hardware {

namespace sim808 {
extern SoftwareSerial simSerial;
extern SIM808 device;

void powerOn();


+ 18
- 0
GpsTracker/Logging.cpp Bestand weergeven

@@ -0,0 +1,18 @@
#include "Logging.h"

namespace logging {

void setup() {
#if _DEBUG
while (!Serial);
#endif

if (Serial) {
Serial.begin(LOG_SERIAL_SPEED);
Log.begin(LOG_LEVEL, &Serial);

Log.notice(F("Starting...\n"));
}
}

}

+ 35
- 0
GpsTracker/Logging.h Bestand weergeven

@@ -0,0 +1,35 @@
#pragma once
#include "Config.h"

//#define DISABLE_LOGGING 1
#include <ArduinoLog.h>

#define LOG_SERIAL_SPEED 115200
#if _DEBUG
#define LOG_LEVEL LOG_LEVEL_VERBOSE
#else
#define LOG_LEVEL LOG_LEVEL_NOTICE
#endif

#define LOG(level, f) Log.level(F("[" LOGGER_NAME "::" f "]\n"))
#define LOG_MSG(level, f, msg) Log.level(F("[" LOGGER_NAME "::" f "] " msg "\n"))
#define LOG_FORMAT(level, f, msg, ...) Log.level(F("[" LOGGER_NAME "::" f "] " msg "\n"), __VA_ARGS__)

#if _DEBUG
#define VERBOSE(f) LOG(verbose, f)
#define VERBOSE_MSG(f, msg) LOG_MSG(verbose, f, msg)
#define VERBOSE_FORMAT(f, msg, ...) LOG_FORMAT(verbose, f, msg, __VA_ARGS__)
#else
#define VERBOSE(f)
#define VERBOSE_MSG(f, msg)
#define VERBOSE_FORMAT(f, msg, ...)
#endif

#define NOTICE(f) LOG(notice, f)
#define NOTICE_MSG(f, msg) LOG_MSG(notice, f, msg)
#define NOTICE_FORMAT(f, msg, ...) LOG_FORMAT(notice, f, msg, __VA_ARGS__)


namespace logging {
void setup();
}

+ 23
- 6
GpsTracker/MainUnit.cpp Bestand weergeven

@@ -7,6 +7,23 @@

namespace mainunit {

namespace details {

void prepareSleep() {
hardware::sim808::simSerial.end(); //avoid woke up by SoftwareSerial interrupt
delay(5); //ensure message have been printed out
}

void wokeUp() {
tmElements_t wokeUpTime;
rtc::getTime(wokeUpTime);
VERBOSE_FORMAT("wokeUp", "%d:%d:%d", wokeUpTime.Hour, wokeUpTime.Minute, wokeUpTime.Second);

hardware::sim808::simSerial.listen();
}

}

void interrupt() {
detachInterrupt(digitalPinToInterrupt(RTC_WAKE));
}
@@ -19,18 +36,18 @@ namespace mainunit {
}

void sleep(period_t period) {
NOTICE_FORMAT("sleep", "Sleeping for period : %d", period);
delay(5);
NOTICE_FORMAT("sleep", "Period : %d", period);
details::prepareSleep();
LowPower.powerDown(period, ADC_OFF, BOD_OFF);
NOTICE_MSG("sleep", "Woke up");
details::wokeUp();

}

void deepSleep(uint16_t seconds) {
NOTICE_FORMAT("deepSleep", "Deep sleeping for %d seconds", seconds);
NOTICE_FORMAT("deepSleep", "%d seconds", seconds);
interruptIn(seconds);
delay(5);
details::prepareSleep();
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
NOTICE_MSG("deepSleep", "Woke up");
details::wokeUp();
}
}

+ 45
- 1
GpsTracker/Network.cpp Bestand weergeven

@@ -1,8 +1,52 @@
#include "Config.h"

#if BACKUP_ENABLE_NETWORK
#include "Debug.h"
#include "Network.h"
#include "Hardware.h"
#include "MainUnit.h"

#define LOGGER_NAME "Network"

namespace network {

SIM808RegistrationStatus waitForRegistered(uint32_t timeout) {
VERBOSE("waitForRegistered");

SIM808RegistrationStatus currentStatus;
uint8_t noReliableNetwork = 0;

do {
currentStatus = hardware::sim808::device.getNetworkRegistrationStatus();
if (isAvailable(currentStatus.stat)) break;

SIM808SignalQualityReport report = hardware::sim808::device.getSignalQuality();
NOTICE_FORMAT("waitForRegistered", "%d, [%d %ddBm]", currentStatus.stat, report.ssri, report.attenuation);
if (report.ssri < NETWORK_DEFAULT_NO_NETWORK_QUALIRY_THRESHOLD) noReliableNetwork++;
else noReliableNetwork = 0;
if (noReliableNetwork > NETWORK_DEFAULT_NO_NETWORK_TRIES) {
NOTICE_MSG("waitForRegistered", "No reliable signal");
break; //after a while, not network really means no network. Bailing out
}

mainunit::deepSleep(NETWORK_DEFAULT_INTERMEDIATE_TIMEOUT_MS / 1000);
timeout -= NETWORK_DEFAULT_INTERMEDIATE_TIMEOUT_MS;
} 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 state == SIM808_NETWORK_REGISTRATION_STATE::REGISTERED ||
state == SIM808_NETWORK_REGISTRATION_STATE::ROAMING;
}

bool enableGprs() {
return hardware::sim808::device.enableGprs(config::main::value.network.apn);
}
}
}
#endif

+ 4
- 0
GpsTracker/Network.h Bestand weergeven

@@ -6,4 +6,8 @@ namespace network {

inline void powerOn() { hardware::sim808::networkPowerOn(); }
inline void powerOff() { hardware::sim808::networkPowerOff(); }

SIM808RegistrationStatus waitForRegistered(uint32_t timeout);
bool isAvailable(SIM808_NETWORK_REGISTRATION_STATE state);
bool enableGprs();
}

+ 93
- 0
GpsTracker/NetworkPositionsBackup.cpp Bestand weergeven

@@ -0,0 +1,93 @@
#pragma once

#include "Config.h"

#if BACKUP_ENABLE_NETWORK
#include "NetworkPositionsBackup.h"
#include "Debug.h"
#include "Positions.h"
#include "Hardware.h"
#include "Network.h"

#define LOGGER_NAME "Positions::backup::network"
#define BUFFER_SIZE 170

namespace positions {
namespace backup {
namespace net {

namespace details {

bool isBackupNeeded() {
config_t *config = &config::main::value;
return (config->network.lastSavedEntry == 0xFFFF && config ->lastEntry != 0xFFFF) ||
positions::count(config->network.lastSavedEntry) > config->network.saveThreshold;
}

bool appendPosition(PositionEntry &entry) {
char buffer[BUFFER_SIZE];
snprintf(buffer, BUFFER_SIZE, "%d,%d,%d,%d,%d,%d,",
debug::freeRam(),
hardware::sim808::device.getSignalQuality().attenuation,
entry.metadata.batteryLevel,
entry.metadata.batteryVoltage,
static_cast<uint16_t>(entry.metadata.temperature * 100),
static_cast<uint8_t>(entry.metadata.status));

strcat(buffer, entry.position);

NOTICE_FORMAT("appendPosition", "Sending : %s", buffer);
uint16_t responseCode = hardware::sim808::device.httpPost(
config::main::value.network.url,
F("text/csv"),
buffer,
buffer,
BUFFER_SIZE
) == POSITIONS_CONFIG_NET_DEFAULT_EXPECTED_RESPONSE;

NOTICE_FORMAT("appendPosition", "Response : %d", responseCode);
return responseCode;
}

void appendPositions() {
uint16_t currentEntryIndex = config::main::value.network.lastSavedEntry + 1;
PositionEntry currentEntry;
SIM808RegistrationStatus networkStatus;

network::powerOn();
networkStatus = network::waitForRegistered(NETWORK_DEFAULT_TOTAL_TIMEOUT_MS);

if (!network::isAvailable(networkStatus.stat)) NOTICE_MSG("appendPositions", "network unavailable");
else if (!network::enableGprs()) NOTICE_MSG("appendPositions", "gprs unavailable");
else {
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() {
NOTICE("setup");
}

void NetworkPositionsBackup::backup() {
NOTICE("backup");

if (!details::isBackupNeeded()) return;
details::appendPositions();
}
}
}
}
#endif

+ 18
- 0
GpsTracker/NetworkPositionsBackup.h Bestand weergeven

@@ -0,0 +1,18 @@
#pragma once

#include "PositionsBackup.h"

namespace positions {
namespace backup {
namespace net {

class NetworkPositionsBackup : public PositionsBackup {
private:
public:
void setup();
void backup();
};

}
}
}

+ 15
- 0
GpsTracker/NetworkPositionsConfig.h Bestand weergeven

@@ -0,0 +1,15 @@
#pragma once


#define POSITIONS_CONFIG_NET_DEFAULT_SAVE_THRESHOLD 10
#define POSITIONS_CONFIG_NET_DEFAULT_APN "Vodafone"
#define POSITIONS_CONFIG_NET_DEFAULT_URL "http://yourserver.com/endpoint"
#define POSITIONS_CONFIG_NET_DEFAULT_EXPECTED_RESPONSE 201


struct networkConfig_t {
uint8_t saveThreshold;
uint16_t lastSavedEntry;
char apn[20];
char url[50];
};

+ 75
- 27
GpsTracker/Positions.cpp Bestand weergeven

@@ -1,26 +1,60 @@
#include "Positions.h"

#include "Debug.h"
#include "Config.h"
#include "Debug.h"
#include "Positions.h"
#include "Gps.h"
#include "Network.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 ENTRY_RESERVED_SIZE
#define ENTRIES_ADDR CONFIG_RESERVED_SIZE

namespace positions {
#ifdef BACKUPS_ENABLED
backup::PositionsBackup **_backups;
#endif

uint16_t _maxEntryIndex = (E24_MAX_ADDRESS(hardware::i2c::eeprom.getSize()) - ENTRIES_ADDR) / ENTRY_RESERVED_SIZE;
namespace details {
uint16_t maxEntryIndex = 0;

uint16_t getEntryAddress(uint16_t index) {
if (index > _maxEntryIndex) return -1;
return ENTRIES_ADDR + (ENTRY_RESERVED_SIZE * index);
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;
#ifdef BACKUPS_ENABLED
uint8_t backupIdx = 0;
_backups = new backup::PositionsBackup*[BACKUPS_ENABLED];

#if BACKUP_ENABLE_SDCARD
_backups[backupIdx] = new backup::sd::SdPositionsBackup();
_backups[backupIdx]->setup();
backupIdx++;
#endif
#if BACKUP_ENABLE_NETWORK
_backups[backupIdx] = new backup::net::NetworkPositionsBackup();
_backups[backupIdx]->setup();
backupIdx++;
#endif
#endif
}

bool acquire(PositionEntryMetadata &metadata) {
VERBOSE("acquire");
NOTICE("acquire");

timestamp_t before;

@@ -30,6 +64,8 @@ namespace positions {
SIM808ChargingStatus battery = hardware::sim808::device.getChargingState();
gps::powerOff();

NOTICE_FORMAT("acquire", "Status : %d", gpsStatus);

if (gpsStatus < SIM808_GPS_STATUS::FIX) return false;

uint16_t timeToFix = rtc::getTime() - before;
@@ -52,29 +88,34 @@ namespace positions {
void appendLast(const PositionEntryMetadata &metadata) {
VERBOSE("appendLast");

uint16_t entryIndex;
uint16_t entryAddress;
PositionEntry entry = { metadata };
strlcpy(entry.position, gps::lastPosition, POSITION_SIZE);

hardware::i2c::powerOn();
Config config = config::get();
config_t* config = &config::main::value;
entryIndex = config->lastEntry + 1;

config.lastEntry++;
if (config.lastEntry > _maxEntryIndex) config.lastEntry = 0;
if (config.lastEntry == config.firstEntry) config.firstEntry++;
if (config.firstEntry > _maxEntryIndex) config.firstEntry = 0;
entryAddress = details::getEntryAddress(entryIndex);

entryAddress = getEntryAddress(config.lastEntry);
hardware::i2c::powerOn();
hardware::i2c::eeprom.writeBlock(entryAddress, entry);

VERBOSE_FORMAT("appendLast", "Written to EEPROM @ %X : [%d%% @ %dmV] [%f°C] [TTF : %d, Status : %d, Position : %s]", entryAddress, entry.metadata.batteryLevel, entry.metadata.batteryVoltage, entry.metadata.temperature, entry.metadata.timeToFix, entry.metadata.status, entry.position);
NOTICE_FORMAT("appendLast", "Saved @ %X : [%d%% @ %dmV] [%f°C] [TTF : %d, Status : %d, Position : %s]", entryAddress, entry.metadata.batteryLevel, entry.metadata.batteryVoltage, entry.metadata.temperature, entry.metadata.timeToFix, entry.metadata.status, entry.position);

config::set(config);
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) {
uint16_t entryAddress = getEntryAddress(index);
VERBOSE("get");

uint16_t entryAddress = details::getEntryAddress(index);
if (entryAddress == -1) return false;

VERBOSE_FORMAT("get", "Reading entry n°%d @ %X", index, entryAddress);
@@ -83,24 +124,31 @@ namespace positions {
hardware::i2c::eeprom.readBlock(entryAddress, entry);
hardware::i2c::powerOff();

VERBOSE_FORMAT("get", "Read from EEPROM @ %X : [%d%% @ %dmV] [%f°C] [%d, %s]", entryAddress, entry.metadata.batteryLevel, entry.metadata.batteryVoltage, entry.metadata.temperature, entry.metadata.timeToFix, entry.metadata.status, entry.position);
NOTICE_FORMAT("get", "Read from EEPROM @ %X : [%d%% @ %dmV] [%f°C] [TTF : %d, Status : %d, Position : %s]", entryAddress, entry.metadata.batteryLevel, entry.metadata.batteryVoltage, entry.metadata.temperature, entry.metadata.timeToFix, entry.metadata.status, entry.position);
return true;
}

bool moveNext(uint16_t &index) {
if (index == config::get().lastEntry) return false;
if (index == config::main::value.lastEntry) return false;
if (index == _maxEntryIndex) index = 0; //could use a modulo but easier to understand that way
if (index == details::maxEntryIndex) index = 0; //could use a modulo but easier to understand that way
else index++;

return true;
}

bool needsToSend() {
return false;
}
uint16_t count(uint16_t fromIndex) {
config_t *config = &config::main::value;
if (config->lastEntry < config->firstEntry) { config->lastEntry += details::maxEntryIndex; }

void send() {
return config->lastEntry - fromIndex;
}

void doBackup() {
#ifdef BACKUPS_ENABLED
for (int i = 0; i < BACKUPS_ENABLED; i++) {
_backups[i]->backup();
}
#endif
}
}

+ 4
- 2
GpsTracker/Positions.h Bestand weergeven

@@ -18,12 +18,14 @@ struct PositionEntry {
}; //sizeof = 125

namespace positions {

void setup();
bool acquire(PositionEntryMetadata &metadata);
void appendLast(const PositionEntryMetadata &metadata);

bool get(uint16_t index, PositionEntry &entry);
bool moveNext(uint16_t &index);
uint16_t count(uint16_t fromIndex);

bool needsToSend();
void send();
void doBackup();
}

+ 9
- 0
GpsTracker/PositionsBackup.cpp Bestand weergeven

@@ -0,0 +1,9 @@
#include "PositionsBackup.h"

namespace positions {
namespace backup {

PositionsBackup::~PositionsBackup() {}

}
}

+ 14
- 0
GpsTracker/PositionsBackup.h Bestand weergeven

@@ -0,0 +1,14 @@
#pragma once

namespace positions {
namespace backup {

class PositionsBackup {
public:
~PositionsBackup();
virtual void setup()=0;
virtual void backup()=0;
};

}
}

+ 10
- 1
GpsTracker/Rtc.cpp Bestand weergeven

@@ -17,7 +17,7 @@ namespace rtc {
hardware::i2c::powerOn();
RTC.control(DS3231_12H, DS3231_OFF); //24 hours clock
RTC.control(DS3231_A1_INT_ENABLE, DS3231_OFF); //Alarm 1 OFF
RTC.control(DS3231_INT_ENABLE, DS3231_ON); //INTCN OFF
RTC.control(DS3231_INT_ENABLE, DS3231_ON); //INTCN ON
hardware::i2c::powerOff();

//TODO : check wether the osc has been halted (meaning the battery could be dead)
@@ -31,6 +31,14 @@ namespace rtc {
return temperature;
}

bool isAccurate() {
hardware::i2c::powerOn();
bool accurate = RTC.status(DS3231_HALTED_FLAG) == DS3231_OFF;
hardware::i2c::powerOff();

return accurate;
}

timestamp_t getTime() {
tmElements_t time;
getTime(time);
@@ -50,6 +58,7 @@ namespace rtc {

hardware::i2c::powerOn();
RTC.writeTime(time);
RTC.control(DS3231_HALTED_FLAG, DS3231_OFF);
hardware::i2c::powerOff();
}



+ 1
- 0
GpsTracker/Rtc.h Bestand weergeven

@@ -7,6 +7,7 @@ namespace rtc {

float getTemperature();

bool isAccurate();
timestamp_t getTime();
void getTime(tmElements_t &time);
void setTime(const tmElements_t &time);


+ 18
- 0
GpsTracker/SdCard.cpp Bestand weergeven

@@ -0,0 +1,18 @@
#include "Config.h"

#if BACKUP_ENABLE_SDCARD
#include "SdCard.h"

namespace hardware {
namespace sdcard {

SdFat filesystem;
bool available = false;

void setup() {
available = filesystem.begin(SD_SS);
}

}
}
#endif

+ 14
- 0
GpsTracker/SdCard.h Bestand weergeven

@@ -0,0 +1,14 @@
#pragma once

#include <SdFat.h>
#include "Pins.h"

namespace hardware {
namespace sdcard {

extern SdFat filesystem;
extern bool available;

void setup();
}
}

+ 119
- 0
GpsTracker/SdPositionsBackup.cpp Bestand weergeven

@@ -0,0 +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() {
VERBOSE("backup");

if (!hardware::sdcard::available) {
VERBOSE_MSG("backup", "not available");
return;
}

SdPositionConfig_t sdConfig;

if (!details::isBackupNeeded(sdConfig)) return;
details::appendPositions(sdConfig);
}

}
}
}
#endif

+ 18
- 0
GpsTracker/SdPositionsBackup.h Bestand weergeven

@@ -0,0 +1,18 @@
#pragma once

#include "PositionsBackup.h"

namespace positions {
namespace backup {
namespace sd {

class SdPositionsBackup : public PositionsBackup {
private:
public:
void setup();
void backup();
};

}
}
}

+ 71
- 0
GpsTracker/SdPositionsConfig.cpp Bestand weergeven

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

}
}
}
#endif

+ 35
- 0
GpsTracker/SdPositionsConfig.h Bestand weergeven

@@ -0,0 +1,35 @@
#pragma once

#include <Arduino.h>

#define POSITIONS_FOLDER "positions"
#define POSITIONS_FILENAME "positions-%05d.csv"
#define POSITIONS_FILENAME_LENGTH 19
#define POSITIONS_CONFIG_FILENAME "positions.config"
#define POSITIONS_CONFIG_SEED 45
#define POSITIONS_CONFIG_DEFAULT_SAVE_THRESHOLD 10
#define POSITIONS_CONFIG_DEFAULT_MAX_RECORDS_PER_FILE 5

struct SdPositionConfig_t {
uint8_t seed;
uint8_t saveThreshold;
uint8_t maxRecordsPerFile;
uint16_t lastSavedEntry;
uint16_t fileIndex;
uint32_t filePosition;
size_t fileRecords;
};

namespace config {
namespace backup {
namespace sd {

void setup();

SdPositionConfig_t get();
void set(SdPositionConfig_t config);
void reset();

}
}
}

Laden…
Annuleren
Opslaan