@@ -1,112 +1,33 @@ | |||
#pragma once | |||
#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 14 | |||
#define VERSION "1.20" | |||
#define SLEEP_TIMING_TIME(hours, minutes) hours * 60 + minutes | |||
#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 CONFIG_DEFAULT_BATTERY_ALERT_LEVEL1 45 | |||
#define CONFIG_DEFAULT_BATTERY_ALERT_LEVEL2 38 | |||
#define CONFIG_DEFAULT_BATTERY_ALERT_CLEAR 60 | |||
#define CONFIG_DEFAULT_ACTIVE_ALERTS 0 | |||
#define CONFIG_DEFAULT_CONTACT_PHONE "+642568452" | |||
#define SLEEP_DEFAULT_TIME_SECONDS 1800 | |||
#define SLEEP_DEFAULT_STOPPED_THRESHOLD 5 | |||
#define SLEEP_DEFAULT_PAUSING_TIME_SECONDS 270 | |||
#define SLEEP_TIMING_MIN SLEEP_TIMING_TIME(0, 0) | |||
#define SLEEP_TIMING_MAX SLEEP_TIMING_TIME(23, 59) | |||
#define SLEEP_TIMING_MIN_MOVING_VELOCITY 5 | |||
#define GPS_DEFAULT_INTERMEDIATE_TIMEOUT_MS 10000L | |||
#define GPS_DEFAULT_TOTAL_TIMEOUT_MS 80000L | |||
#define GPS_DEFAULT_MISSED_POSITION_GAP_KM 2 | |||
#define NETWORK_DEFAULT_INTERMEDIATE_TIMEOUT_MS 10000L | |||
#define NETWORK_DEFAULT_TOTAL_TIMEOUT_MS 80000L | |||
#define NETWORK_DEFAULT_NO_NETWORK_QUALITY_THRESHOLD 8 | |||
#define NETWORK_DEFAULT_NO_NETWORK_TRIES 5 | |||
#define ALERTS_ON_SERIAL_IF_AVAILABLE 1 | |||
/** | |||
\def ALERTS_ON_SERIAL_IF_AVAILABLE | |||
Display alerts on serial when connected rather than sending an SMS. | |||
Useful for debugging purpose and avoid costs related to SMS sending. | |||
*/ | |||
#define ALERT_SUSPICIOUS_RTC_TEMPERATURE 0 | |||
#pragma endregion | |||
struct sleepTimings_t { | |||
uint8_t speed; | |||
uint16_t timeMin; | |||
uint16_t timeMax; | |||
uint16_t seconds; | |||
}; | |||
struct config_t { | |||
uint8_t seed; //sizeof = 1 | |||
char version[5]; //sizeof = 5 | |||
uint16_t firstEntry; //sizeof = 2 | |||
uint16_t lastEntry; //sizeof = 2 | |||
#if BACKUP_ENABLE_NETWORK | |||
networkConfig_t network; //sizeof = 73 | |||
#else | |||
char reserved[73]; | |||
#endif | |||
uint8_t alertBatteryLevel1; //sizeof = 1 | |||
uint8_t alertBatteryLevel2; //sizeof = 1 | |||
uint8_t alertBatteryLevelClear; //sizeof = 1 | |||
uint8_t activeAlerts; //sizeof = 1 | |||
char contactPhone[15]; //sizeof = 15 | |||
}; //sizeof = 29 + 73 = 102 | |||
namespace config { | |||
static const sleepTimings_t defaultSleepTimings[] PROGMEM = { | |||
{ 0, SLEEP_TIMING_TIME(16, 00), SLEEP_TIMING_TIME(19, 59), 3600 }, | |||
{ 0, SLEEP_TIMING_TIME(20, 00), SLEEP_TIMING_MAX, SLEEP_DEFAULT_TIME_SECONDS }, | |||
{ 0, SLEEP_TIMING_MIN, SLEEP_TIMING_TIME(8, 29), SLEEP_DEFAULT_TIME_SECONDS }, | |||
{ 0, SLEEP_TIMING_TIME(8, 30), SLEEP_TIMING_TIME(15, 59), 10800 }, | |||
{ SLEEP_TIMING_MIN_MOVING_VELOCITY, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 540 }, | |||
{ 10, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 270 }, | |||
{ 20, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 225 }, | |||
{ 30, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 240 }, | |||
{ 45, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 280 }, | |||
{ 65, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 276 }, | |||
{ 85, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 225 } | |||
}; | |||
namespace main { | |||
extern config_t value; | |||
void setup(); | |||
void save(); | |||
void reset(); | |||
} | |||
#pragma once | |||
#include <Arduino.h> | |||
#include "config/Main.h" | |||
struct config_t { | |||
uint8_t seed; //sizeof = 1 | |||
char version[5]; //sizeof = 5 | |||
uint16_t firstEntry; //sizeof = 2 | |||
uint16_t lastEntry; //sizeof = 2 | |||
#if BACKUP_ENABLE_NETWORK | |||
networkConfig_t network; //sizeof = 73 | |||
#else | |||
char reserved[73]; | |||
#endif | |||
uint8_t alertBatteryLevel1; //sizeof = 1 | |||
uint8_t alertBatteryLevel2; //sizeof = 1 | |||
uint8_t alertBatteryLevelClear; //sizeof = 1 | |||
uint8_t activeAlerts; //sizeof = 1 | |||
char contactPhone[15]; //sizeof = 15 | |||
}; //sizeof = 29 + 73 = 102 | |||
namespace config { | |||
namespace main { | |||
extern config_t value; | |||
void setup(); | |||
void save(); | |||
void reset(); | |||
} | |||
} |
@@ -1,29 +1,29 @@ | |||
#pragma once | |||
#include <Arduino.h> | |||
#include "Debug.h" | |||
#include "Gps.h" | |||
#include "MainUnit.h" | |||
#include "Network.h" | |||
#include "Rtc.h" | |||
#include "Pins.h" | |||
#include "Positions.h" | |||
enum class TRACKER_MOVING_STATE : uint8_t { | |||
MOVING = 0, | |||
PAUSED = 1, | |||
STOPPED = 2, | |||
STATIC = 3 | |||
}; | |||
namespace core { | |||
extern uint16_t sleepTime; | |||
void main(); | |||
void updateRtcTime(); | |||
TRACKER_MOVING_STATE updateSleepTime(); | |||
uint16_t mapSleepTime(uint8_t velocity); | |||
uint8_t notifyFailures(PositionEntryMetadata &metadata); | |||
#pragma once | |||
#include <Arduino.h> | |||
#include "Debug.h" | |||
#include "Gps.h" | |||
#include "MainUnit.h" | |||
#include "Network.h" | |||
#include "Rtc.h" | |||
#include "config/Pins.h" | |||
#include "Positions.h" | |||
enum class TRACKER_MOVING_STATE : uint8_t { | |||
MOVING = 0, | |||
PAUSED = 1, | |||
STOPPED = 2, | |||
STATIC = 3 | |||
}; | |||
namespace core { | |||
extern uint16_t sleepTime; | |||
void main(); | |||
void updateRtcTime(); | |||
TRACKER_MOVING_STATE updateSleepTime(); | |||
uint16_t mapSleepTime(uint8_t velocity); | |||
uint8_t notifyFailures(PositionEntryMetadata &metadata); | |||
} |
@@ -1,159 +1,159 @@ | |||
#include "Config.h" | |||
#include "Hardware.h" | |||
#include "Pins.h" | |||
#include "Debug.h" | |||
#include <SoftwareSerial.h> | |||
#include <SIM808.h> | |||
#include <SIM808_Types.h> | |||
#include <Wire.h> | |||
#include <E24.h> | |||
namespace hardware { | |||
#define LOGGER_NAME "Hardware::sim808" | |||
namespace sim808 { | |||
SoftwareSerial simSerial = SoftwareSerial(SIM_TX, SIM_RX); | |||
SIM808 device = SIM808(SIM_RST, SIM_PWR, SIM_STATUS); | |||
uint8_t networkPoweredCount = 0; | |||
uint8_t gpsPoweredCount = 0; | |||
void powerOn() { | |||
VERBOSE("powerOn"); | |||
bool poweredOn = device.powerOnOff(true); | |||
if (!poweredOn) return; | |||
device.init(); | |||
networkPoweredCount = gpsPoweredCount = 0; | |||
} | |||
void powerOff() { | |||
VERBOSE("powerOff"); | |||
device.powerOnOff(false); | |||
networkPoweredCount = gpsPoweredCount = 0; | |||
} | |||
void powerOffIfUnused() { | |||
//does not rely on count for safety | |||
//if there is a bug somewhere, the device will consume more battery, | |||
//but will not fail due to an over aggressive battery saving strategy | |||
bool gpsPowered = false; | |||
if ((!device.getGpsPowerState(&gpsPowered) || !gpsPowered) && | |||
(device.getPhoneFunctionality() != SIM808_PHONE_FUNCTIONALITY::FULL)) { | |||
powerOff(); | |||
} | |||
} | |||
void setup() { | |||
NOTICE("setup"); | |||
simSerial.begin(SIM808_BAUDRATE); | |||
device.begin(simSerial); | |||
powerOff(); //ensure powerOff on start | |||
} | |||
void gpsPowerOn() { | |||
if(gpsPoweredCount) { | |||
gpsPoweredCount++; | |||
return; | |||
} | |||
VERBOSE("gpsPowerOn"); | |||
powerOn(); | |||
if(!networkPoweredCount) { | |||
//SIM808 turns phone on by default but we don't need it for gps only | |||
device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::MINIMUM); | |||
} | |||
device.enableGps(); | |||
} | |||
void gpsPowerOff() { | |||
if (!device.powered()) { | |||
networkPoweredCount = gpsPoweredCount = 0; //just to be sure counts == 0 | |||
return; | |||
} | |||
if(gpsPoweredCount > 1) { | |||
gpsPoweredCount--; | |||
return; | |||
} | |||
VERBOSE("gpsPowerOff"); | |||
device.disableGps(); | |||
powerOffIfUnused(); | |||
} | |||
void networkPowerOn() { | |||
if(networkPoweredCount) { | |||
networkPoweredCount++; | |||
return; | |||
} | |||
VERBOSE("networkPowerOn"); | |||
powerOn(); | |||
device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::FULL); | |||
} | |||
void networkPowerOff() { | |||
if (!device.powered()) { | |||
networkPoweredCount = gpsPoweredCount = 0; //just to be sure counts == 0 | |||
return; | |||
} | |||
if(networkPoweredCount > 1) { | |||
networkPoweredCount--; | |||
return; | |||
} | |||
VERBOSE("networkPowerOff"); | |||
device.disableGprs(); | |||
device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::MINIMUM); | |||
powerOffIfUnused(); | |||
} | |||
} | |||
#define LOGGER_NAME "Hardware::i2c" | |||
namespace i2c { | |||
E24 eeprom = E24(E24Size_t::E24_512K); | |||
uint8_t poweredCount = 0; | |||
void powerOn() { | |||
if(poweredCount) { | |||
poweredCount++; | |||
return; | |||
} | |||
VERBOSE("powerOn"); | |||
digitalWrite(I2C_PWR, HIGH); | |||
pinMode(I2C_PWR, OUTPUT); | |||
Wire.begin(); | |||
poweredCount = 1; | |||
} | |||
void powerOff(bool forced = false) { | |||
if(poweredCount > 1 && !forced) { | |||
poweredCount--; | |||
return; | |||
} | |||
VERBOSE("powerOff"); | |||
pinMode(I2C_PWR, INPUT); | |||
digitalWrite(I2C_PWR, LOW); | |||
//turn off i2c | |||
TWCR &= ~(bit(TWEN) | bit(TWIE) | bit(TWEA)); | |||
//disable i2c internal pull ups | |||
digitalWrite(A4, LOW); | |||
digitalWrite(A5, LOW); | |||
poweredCount = 0; | |||
} | |||
} | |||
} | |||
#include "Config.h" | |||
#include "Hardware.h" | |||
#include "config/Pins.h" | |||
#include "Debug.h" | |||
#include <SoftwareSerial.h> | |||
#include <SIM808.h> | |||
#include <SIM808_Types.h> | |||
#include <Wire.h> | |||
#include <E24.h> | |||
namespace hardware { | |||
#define LOGGER_NAME "Hardware::sim808" | |||
namespace sim808 { | |||
SoftwareSerial simSerial = SoftwareSerial(SIM_TX, SIM_RX); | |||
SIM808 device = SIM808(SIM_RST, SIM_PWR, SIM_STATUS); | |||
uint8_t networkPoweredCount = 0; | |||
uint8_t gpsPoweredCount = 0; | |||
void powerOn() { | |||
VERBOSE("powerOn"); | |||
bool poweredOn = device.powerOnOff(true); | |||
if (!poweredOn) return; | |||
device.init(); | |||
networkPoweredCount = gpsPoweredCount = 0; | |||
} | |||
void powerOff() { | |||
VERBOSE("powerOff"); | |||
device.powerOnOff(false); | |||
networkPoweredCount = gpsPoweredCount = 0; | |||
} | |||
void powerOffIfUnused() { | |||
//does not rely on count for safety | |||
//if there is a bug somewhere, the device will consume more battery, | |||
//but will not fail due to an over aggressive battery saving strategy | |||
bool gpsPowered = false; | |||
if ((!device.getGpsPowerState(&gpsPowered) || !gpsPowered) && | |||
(device.getPhoneFunctionality() != SIM808_PHONE_FUNCTIONALITY::FULL)) { | |||
powerOff(); | |||
} | |||
} | |||
void setup() { | |||
NOTICE("setup"); | |||
simSerial.begin(SIM808_BAUDRATE); | |||
device.begin(simSerial); | |||
powerOff(); //ensure powerOff on start | |||
} | |||
void gpsPowerOn() { | |||
if(gpsPoweredCount) { | |||
gpsPoweredCount++; | |||
return; | |||
} | |||
VERBOSE("gpsPowerOn"); | |||
powerOn(); | |||
if(!networkPoweredCount) { | |||
//SIM808 turns phone on by default but we don't need it for gps only | |||
device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::MINIMUM); | |||
} | |||
device.enableGps(); | |||
} | |||
void gpsPowerOff() { | |||
if (!device.powered()) { | |||
networkPoweredCount = gpsPoweredCount = 0; //just to be sure counts == 0 | |||
return; | |||
} | |||
if(gpsPoweredCount > 1) { | |||
gpsPoweredCount--; | |||
return; | |||
} | |||
VERBOSE("gpsPowerOff"); | |||
device.disableGps(); | |||
powerOffIfUnused(); | |||
} | |||
void networkPowerOn() { | |||
if(networkPoweredCount) { | |||
networkPoweredCount++; | |||
return; | |||
} | |||
VERBOSE("networkPowerOn"); | |||
powerOn(); | |||
device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::FULL); | |||
} | |||
void networkPowerOff() { | |||
if (!device.powered()) { | |||
networkPoweredCount = gpsPoweredCount = 0; //just to be sure counts == 0 | |||
return; | |||
} | |||
if(networkPoweredCount > 1) { | |||
networkPoweredCount--; | |||
return; | |||
} | |||
VERBOSE("networkPowerOff"); | |||
device.disableGprs(); | |||
device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::MINIMUM); | |||
powerOffIfUnused(); | |||
} | |||
} | |||
#define LOGGER_NAME "Hardware::i2c" | |||
namespace i2c { | |||
E24 eeprom = E24(E24Size_t::E24_512K); | |||
uint8_t poweredCount = 0; | |||
void powerOn() { | |||
if(poweredCount) { | |||
poweredCount++; | |||
return; | |||
} | |||
VERBOSE("powerOn"); | |||
digitalWrite(I2C_PWR, HIGH); | |||
pinMode(I2C_PWR, OUTPUT); | |||
Wire.begin(); | |||
poweredCount = 1; | |||
} | |||
void powerOff(bool forced = false) { | |||
if(poweredCount > 1 && !forced) { | |||
poweredCount--; | |||
return; | |||
} | |||
VERBOSE("powerOff"); | |||
pinMode(I2C_PWR, INPUT); | |||
digitalWrite(I2C_PWR, LOW); | |||
//turn off i2c | |||
TWCR &= ~(bit(TWEN) | bit(TWIE) | bit(TWEA)); | |||
//disable i2c internal pull ups | |||
digitalWrite(A4, LOW); | |||
digitalWrite(A5, LOW); | |||
poweredCount = 0; | |||
} | |||
} | |||
} |
@@ -1,45 +1,45 @@ | |||
#include "MainUnit.h" | |||
#include "Rtc.h" | |||
#include "Pins.h" | |||
#include "Debug.h" | |||
#define LOGGER_NAME "MainUnit" | |||
namespace mainunit { | |||
namespace details { | |||
void prepareSleep() { | |||
hardware::sim808::simSerial.end(); //avoid woke up by SoftwareSerial interrupt | |||
delay(5); //ensure log messages 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)); | |||
} | |||
void interruptIn(uint16_t seconds) { | |||
rtc::setAlarm(seconds); | |||
pinMode(RTC_WAKE, INPUT); | |||
attachInterrupt(digitalPinToInterrupt(RTC_WAKE), interrupt, FALLING); | |||
} | |||
void deepSleep(uint16_t seconds) { | |||
NOTICE_FORMAT("deepSleep", "%d seconds", seconds); | |||
interruptIn(seconds); | |||
details::prepareSleep(); | |||
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); | |||
details::wokeUp(); | |||
} | |||
#include "MainUnit.h" | |||
#include "Rtc.h" | |||
#include "config/Pins.h" | |||
#include "Debug.h" | |||
#define LOGGER_NAME "MainUnit" | |||
namespace mainunit { | |||
namespace details { | |||
void prepareSleep() { | |||
hardware::sim808::simSerial.end(); //avoid woke up by SoftwareSerial interrupt | |||
delay(5); //ensure log messages 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)); | |||
} | |||
void interruptIn(uint16_t seconds) { | |||
rtc::setAlarm(seconds); | |||
pinMode(RTC_WAKE, INPUT); | |||
attachInterrupt(digitalPinToInterrupt(RTC_WAKE), interrupt, FALLING); | |||
} | |||
void deepSleep(uint16_t seconds) { | |||
NOTICE_FORMAT("deepSleep", "%d seconds", seconds); | |||
interruptIn(seconds); | |||
details::prepareSleep(); | |||
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); | |||
details::wokeUp(); | |||
} | |||
} |
@@ -1,26 +1,26 @@ | |||
#pragma once | |||
#include "PositionsBackup.h" | |||
#include "Time2.h" | |||
#include "Positions.h" | |||
namespace positions { | |||
namespace backup { | |||
namespace net { | |||
class NetworkPositionsBackup : public PositionsBackup { | |||
private: | |||
bool isBackupNeeded(bool forPrepare); | |||
bool appendPosition(PositionEntry &entry); | |||
void appendPositions(); | |||
public: | |||
void setup(); | |||
void prepare(); | |||
void backup(bool force); | |||
}; | |||
} | |||
} | |||
#pragma once | |||
#include "PositionsBackup.h" | |||
#include "Time2.h" | |||
#include "Positions.h" | |||
namespace positions { | |||
namespace backup { | |||
namespace net { | |||
class NetworkPositionsBackup : public PositionsBackup { | |||
private: | |||
bool isBackupNeeded(bool forPrepare); | |||
bool appendPosition(PositionEntry &entry); | |||
void appendPositions(); | |||
public: | |||
void setup(); | |||
void prepare(); | |||
void backup(bool force); | |||
}; | |||
} | |||
} | |||
} |
@@ -1,16 +0,0 @@ | |||
#pragma once | |||
#define POSITIONS_CONFIG_NET_DEFAULT_SAVE_THRESHOLD 30 | |||
#define POSITIONS_CONFIG_NET_DEFAULT_APN "Vodafone" | |||
#define POSITIONS_CONFIG_NET_DEFAULT_URL "https://yourserver.com/endpoint" | |||
#define POSITIONS_CONFIG_NET_DEFAULT_EXPECTED_RESPONSE 201 | |||
#define POSITIONS_CONFIG_NET_DEFAULT_UNAVAILABLE_NETWORK_POSTPONE_THRESHOLD 5 | |||
struct networkConfig_t { | |||
uint8_t saveThreshold; //sizeof = 1 | |||
uint16_t lastSavedEntry; //sizeof = 2 | |||
char apn[20]; //sizeof = 20 | |||
char url[50]; //sizeof = 50 | |||
}; //sizeof = 73 |
@@ -1,13 +0,0 @@ | |||
#pragma once | |||
#define SIM_RST 5 | |||
#define SIM_RX 6 | |||
#define SIM_TX 7 | |||
#define SIM_PWR 9 | |||
#define SIM_STATUS 8 | |||
#define I2C_PWR A0 | |||
#define SD_SS SS | |||
#define SIM_RI 2 | |||
#define RTC_WAKE 3 |
@@ -1,86 +1,86 @@ | |||
#include "Debug.h" | |||
#include "Rtc.h" | |||
#include "Pins.h" | |||
#include <Wire.h> | |||
#include <uDS3231.h> | |||
#define LOGGER_NAME "Rtc" | |||
using namespace utils; | |||
namespace rtc { | |||
void setup() { | |||
VERBOSE("setup"); | |||
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 ON | |||
hardware::i2c::powerOff(); | |||
} | |||
int16_t getTemperature() { | |||
hardware::i2c::powerOn(); | |||
float temperature = RTC.readTempRegister(); | |||
hardware::i2c::powerOff(); | |||
return static_cast<int16_t>(temperature * 100); | |||
} | |||
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); | |||
return time::makeTimestamp(time); | |||
} | |||
void getTime(tmElements_t &time) { | |||
hardware::i2c::powerOn(); | |||
RTC.readTime(time); | |||
hardware::i2c::powerOff(); | |||
VERBOSE_FORMAT("getTime", "%d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second); | |||
} | |||
void setTime(const tmElements_t &time) { | |||
VERBOSE_FORMAT("setTime", "%d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second); | |||
hardware::i2c::powerOn(); | |||
RTC.writeTime(time); | |||
RTC.control(DS3231_HALTED_FLAG, DS3231_OFF); | |||
hardware::i2c::powerOff(); | |||
} | |||
void setAlarm(uint16_t seconds) { | |||
tmElements_t currentTime; | |||
tmElements_t alarmTime; | |||
getTime(currentTime); | |||
time::breakTime(time::makeTimestamp(currentTime) + seconds, alarmTime); | |||
setAlarm(alarmTime); | |||
} | |||
void setAlarm(const tmElements_t &time) { | |||
hardware::i2c::powerOn(); | |||
RTC.writeAlarm1(DS3231_ALM_HMS, time); | |||
RTC.control(DS3231_A1_FLAG, DS3231_OFF); //reset Alarm 1 flag | |||
RTC.control(DS3231_A1_INT_ENABLE, DS3231_ON); //Alarm 1 ON | |||
RTC.control(DS3231_INT_ENABLE, DS3231_ON); //INTCN ON | |||
NOTICE_FORMAT("setAlarm", "Next alarm : %d:%d:%d", time.Hour, time.Minute, time.Second); | |||
hardware::i2c::powerOff(); | |||
} | |||
#include "Debug.h" | |||
#include "Rtc.h" | |||
#include "config/Pins.h" | |||
#include <Wire.h> | |||
#include <uDS3231.h> | |||
#define LOGGER_NAME "Rtc" | |||
using namespace utils; | |||
namespace rtc { | |||
void setup() { | |||
VERBOSE("setup"); | |||
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 ON | |||
hardware::i2c::powerOff(); | |||
} | |||
int16_t getTemperature() { | |||
hardware::i2c::powerOn(); | |||
float temperature = RTC.readTempRegister(); | |||
hardware::i2c::powerOff(); | |||
return static_cast<int16_t>(temperature * 100); | |||
} | |||
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); | |||
return time::makeTimestamp(time); | |||
} | |||
void getTime(tmElements_t &time) { | |||
hardware::i2c::powerOn(); | |||
RTC.readTime(time); | |||
hardware::i2c::powerOff(); | |||
VERBOSE_FORMAT("getTime", "%d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second); | |||
} | |||
void setTime(const tmElements_t &time) { | |||
VERBOSE_FORMAT("setTime", "%d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second); | |||
hardware::i2c::powerOn(); | |||
RTC.writeTime(time); | |||
RTC.control(DS3231_HALTED_FLAG, DS3231_OFF); | |||
hardware::i2c::powerOff(); | |||
} | |||
void setAlarm(uint16_t seconds) { | |||
tmElements_t currentTime; | |||
tmElements_t alarmTime; | |||
getTime(currentTime); | |||
time::breakTime(time::makeTimestamp(currentTime) + seconds, alarmTime); | |||
setAlarm(alarmTime); | |||
} | |||
void setAlarm(const tmElements_t &time) { | |||
hardware::i2c::powerOn(); | |||
RTC.writeAlarm1(DS3231_ALM_HMS, time); | |||
RTC.control(DS3231_A1_FLAG, DS3231_OFF); //reset Alarm 1 flag | |||
RTC.control(DS3231_A1_INT_ENABLE, DS3231_ON); //Alarm 1 ON | |||
RTC.control(DS3231_INT_ENABLE, DS3231_ON); //INTCN ON | |||
NOTICE_FORMAT("setAlarm", "Next alarm : %d:%d:%d", time.Hour, time.Minute, time.Second); | |||
hardware::i2c::powerOff(); | |||
} | |||
} |
@@ -1,18 +1,19 @@ | |||
#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); | |||
} | |||
} | |||
} | |||
#include "Config.h" | |||
#if BACKUP_ENABLE_SDCARD | |||
#include "SdCard.h" | |||
#include "config/Pins.h" | |||
namespace hardware { | |||
namespace sdcard { | |||
SdFat filesystem; | |||
bool available = false; | |||
void setup() { | |||
available = filesystem.begin(SD_SS); | |||
} | |||
} | |||
} | |||
#endif |
@@ -1,14 +1,13 @@ | |||
#pragma once | |||
#include <SdFat.h> | |||
#include "Pins.h" | |||
namespace hardware { | |||
namespace sdcard { | |||
extern SdFat filesystem; | |||
extern bool available; | |||
void setup(); | |||
} | |||
#pragma once | |||
#include <SdFat.h> | |||
namespace hardware { | |||
namespace sdcard { | |||
extern SdFat filesystem; | |||
extern bool available; | |||
void setup(); | |||
} | |||
} |
@@ -0,0 +1,32 @@ | |||
#pragma once | |||
/** | |||
* Configure the values used for alerts triggering. | |||
* Note that the battery level percentage are quite high, | |||
* because the reading provided by the SIM808 module are | |||
* not accurate and the device shuts itself off way before reaching 0%. | |||
* The clearance level is also well above the first alert level, because | |||
* the reading is so inaccurate that sometimes the battery can gain 5% | |||
* between readings. Setting a clearance level much higher avoid | |||
* clearing the levels and retriggering them the next time. | |||
*/ | |||
#define CONFIG_DEFAULT_BATTERY_ALERT_LEVEL1 45 ///< Battery percentage at which to trigger the first low battery alert. | |||
#define CONFIG_DEFAULT_BATTERY_ALERT_LEVEL2 38 ///< Battery percentage at which to trigger the final low battery alert. | |||
#define CONFIG_DEFAULT_BATTERY_ALERT_CLEAR 60 ///< Battery percentage at which to clear all battery alerts. | |||
#define CONFIG_DEFAULT_ACTIVE_ALERTS 0 ///< Default active alerts | |||
#define CONFIG_DEFAULT_CONTACT_PHONE "+642568452" ///< Default phone number to send the alert SMS to. | |||
/** | |||
\def ALERTS_ON_SERIAL_IF_AVAILABLE | |||
Display alerts on serial when connected rather than sending an SMS. | |||
Useful for debugging purpose and avoid costs related to SMS sending. | |||
*/ | |||
#define ALERTS_ON_SERIAL_IF_AVAILABLE 1 | |||
/** | |||
\def ALERT_SUSPICIOUS_RTC_TEMPERATURE | |||
Temperature at which to consider the RTC module as failling. | |||
When the backup battery is dead or nearly dead, the reading | |||
of the temperature fails and returns 0. | |||
*/ | |||
#define ALERT_SUSPICIOUS_RTC_TEMPERATURE 0 |
@@ -0,0 +1,24 @@ | |||
/** | |||
* Configure how the positions are backuped with the network | |||
*/ | |||
#pragma once | |||
#define POSITIONS_CONFIG_NET_DEFAULT_SAVE_THRESHOLD 30 ///< Determines how many positions will be saved before a network backup is needed (only when not moving though). | |||
#define POSITIONS_CONFIG_NET_DEFAULT_APN "Vodafone" ///< APN used for GPRS context | |||
#define POSITIONS_CONFIG_NET_DEFAULT_URL "https://yourserver.com/endpoint" ///< URL to which positions data will be send through an HTTP POST request | |||
#define POSITIONS_CONFIG_NET_DEFAULT_EXPECTED_RESPONSE 201 ///< Expected response code from the server that indicates that the positions has been successfully backuped. | |||
/** | |||
\def POSITIONS_CONFIG_NET_DEFAULT_UNAVAILABLE_NETWORK_POSTPONE_THRESHOLD | |||
Determines how many times to deal with an unreliable network before postponing the backup. | |||
In an area where cell reception isn't good, this avoid to try to backup the positions | |||
every single time, which would rapidly consumes all the batty. | |||
*/ | |||
#define POSITIONS_CONFIG_NET_DEFAULT_UNAVAILABLE_NETWORK_POSTPONE_THRESHOLD 5 | |||
struct networkConfig_t { | |||
uint8_t saveThreshold; //sizeof = 1 | |||
uint16_t lastSavedEntry; //sizeof = 2 | |||
char apn[20]; //sizeof = 20 | |||
char url[50]; //sizeof = 50 | |||
}; //sizeof = 73 |
@@ -0,0 +1 @@ | |||
#pragma once |
@@ -0,0 +1,17 @@ | |||
/** | |||
* Configure how the system waits for the GPS signal. | |||
*/ | |||
#pragma once | |||
#define GPS_DEFAULT_INTERMEDIATE_TIMEOUT_MS 10000L ///< Time to sleeps between each GPS signal assessment. | |||
#define GPS_DEFAULT_TOTAL_TIMEOUT_MS 80000L ///< Timeout after which to stop trying to get a GPS signal. | |||
/** | |||
\def GPS_DEFAULT_MISSED_POSITION_GAP_KM | |||
Gap between the current and previous position above which to consider | |||
that the tracker has moved. Even if stopped, this will trigger a whole | |||
new "cycle" of positions acquisition, and will avoid missing positions | |||
because while moving, the tracker woke up while stopped at a light traffic for instance. | |||
*/ | |||
#define GPS_DEFAULT_MISSED_POSITION_GAP_KM 2 |
@@ -0,0 +1,28 @@ | |||
#pragma once | |||
#include "System.h" | |||
#include "Sleeps.h" | |||
#include "Gps.h" | |||
#include "Network.h" | |||
#include "Alerts.h" | |||
/** | |||
\def BACKUP_ENABLE_SDCARD | |||
Enable (1) or disable (0) the backup of positions using an sd card. | |||
Note: This code has never been finished properly because of the lack of space | |||
on the ATMega | |||
*/ | |||
#define BACKUP_ENABLE_SDCARD 0 | |||
/** | |||
\def BACKUP_ENABLE_NETWORK | |||
Enable (1) or disable (0) the backup of positions using the network. | |||
*/ | |||
#define BACKUP_ENABLE_NETWORK 1 | |||
#if BACKUP_ENABLE_SDCARD | |||
#include "BackupSd.h" | |||
#endif | |||
#if BACKUP_ENABLE_NETWORK | |||
#include "BackupNetwork.h" | |||
#endif |
@@ -0,0 +1,10 @@ | |||
/** | |||
* Configure how the system waits for the network. | |||
*/ | |||
#pragma onces | |||
#define NETWORK_DEFAULT_NO_NETWORK_QUALITY_THRESHOLD 8 ///< Minimum signal quality to consider the cellphone reception as reliable. | |||
#define NETWORK_DEFAULT_NO_NETWORK_TRIES 5 ///< Maximum tries before considering an unreliable cellphone reception as no reception at all. | |||
#define NETWORK_DEFAULT_INTERMEDIATE_TIMEOUT_MS 10000L ///< Intermediate time to sleep between each cellphone reception assessment. | |||
#define NETWORK_DEFAULT_TOTAL_TIMEOUT_MS 80000L ///< Timeout after which to stop trying to register to the network. |
@@ -0,0 +1,16 @@ | |||
/** | |||
* Defines Arduino pins number connected to external systems. | |||
*/ | |||
#pragma once | |||
#define SIM_RST 5 ///< SIM808 RESET | |||
#define SIM_RX 6 ///< SIM808 RXD | |||
#define SIM_TX 7 ///< SIM808 TXD | |||
#define SIM_PWR 9 ///< SIM808 PWRKEY | |||
#define SIM_STATUS 8 ///< SIM808 STATUS | |||
#define I2C_PWR A0 ///< Used to drive I2C power supply | |||
#define SD_SS SS | |||
#define SIM_RI 2 ///< Interrupt pin connected to SIM RI. | |||
#define RTC_WAKE 3 ///< Interrupt pin connected to DS3231 !INT/SQW |
@@ -0,0 +1,53 @@ | |||
/** | |||
* Controls how and when the device goes to sleep. | |||
*/ | |||
#pragma once | |||
#define SLEEP_TIMING_TIME(hours, minutes) hours * 60 + minutes | |||
#define SLEEP_DEFAULT_TIME_SECONDS 1800 ///< Default sleep time | |||
#define SLEEP_TIMING_MIN_MOVING_VELOCITY 5 ///< Speed under which to consider the tracker as not moving | |||
#define SLEEP_DEFAULT_PAUSING_TIME_SECONDS 270 ///< Sleep time to use when not moving | |||
#define SLEEP_DEFAULT_STOPPED_THRESHOLD 5 ///< Number of successive positions acquired as not moving before considering the tracker as stopped | |||
#define SLEEP_TIMING_MIN SLEEP_TIMING_TIME(0, 0) | |||
#define SLEEP_TIMING_MAX SLEEP_TIMING_TIME(23, 59) | |||
/** | |||
* Represents a single entry in a larger parametization | |||
* of how long the tracker will go the sleep based on its speed | |||
* and the time of the day. | |||
*/ | |||
struct sleepTimings_t { | |||
uint8_t speed; ///< Minimum speed (NOT maximum, the logic is reversed for code efficiency) | |||
uint16_t timeMin; ///< Minimum time of the day (UTC) | |||
uint16_t timeMax; ///< Maximum time of the day (UTC) | |||
uint16_t seconds; ///< Sleep duration in seconds | |||
}; | |||
namespace config { | |||
/** | |||
* Describes for how long the tracker should sleep before the next position | |||
* acquisition based on the sleepTimings_t structure | |||
*/ | |||
static const sleepTimings_t defaultSleepTimings[] PROGMEM = { | |||
// Sleep timings when not moving | |||
{ 0, SLEEP_TIMING_TIME(16, 00), SLEEP_TIMING_TIME(19, 59), 3600 }, ///< 1 hour between 16:00 and 20:00 UTC (04:00 to 08:00 UTC+12) | |||
{ 0, SLEEP_TIMING_TIME(20, 00), SLEEP_TIMING_MAX, SLEEP_DEFAULT_TIME_SECONDS }, ///< default (30 minutes) between 20:00 and 00:00 UTC (08:00 to 12:00 UTC+12) | |||
{ 0, SLEEP_TIMING_MIN, SLEEP_TIMING_TIME(8, 29), SLEEP_DEFAULT_TIME_SECONDS }, ///< default (30 minutes) between 00:00 and 8:30 UTC (12:00 to 20:30 UTC+12) | |||
{ 0, SLEEP_TIMING_TIME(8, 30), SLEEP_TIMING_TIME(15, 59), 10800 }, ///< 3 hours between 20:30 and 16:00 UTC (20:30 to 04:00 UTC+12) | |||
// Sleep timings while moving | |||
{ SLEEP_TIMING_MIN_MOVING_VELOCITY, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 540 }, ///< 540 seconds when speed > SLEEP_TIMING_MIN_MOVING_VELOCITY (5km/h) | |||
{ 10, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 270 }, ///< 270 seconds when speed > 10 km/h | |||
{ 20, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 225 }, ///< 225 seconds when speed > 20 km/h | |||
{ 30, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 240 }, ///< 240 seconds when speed > 30 km/h | |||
{ 45, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 280 }, ///< 280 seconds when speed > 45 km/h | |||
{ 65, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 276 }, ///< 276 seconds when speed > 65 km/h | |||
{ 85, SLEEP_TIMING_MIN, SLEEP_TIMING_MAX, 225 } ///< 2225 seconds when speed > 85 km/h | |||
}; | |||
} |
@@ -0,0 +1,37 @@ | |||
#pragma once | |||
/** | |||
\def SIM808_BAUDRATE | |||
Control the baudrate use to communicate with the SIM808 module | |||
*/ | |||
#define SIM808_BAUDRATE 4800 | |||
/** | |||
\def CONFIG_ADDR | |||
Address of the config block in the I2C EEPROM chip. | |||
*/ | |||
#define CONFIG_ADDR 0 | |||
/** | |||
\def CONFIG_RESERVED_SIZE | |||
Reserved size for the config block in the I2C EEPROM chip. | |||
*/ | |||
#define CONFIG_RESERVED_SIZE 128 | |||
/** | |||
\def CONFIG_SEED | |||
Seed use to detect invalid or outdate configuration data. | |||
Changing this value will reset the configuration block. | |||
*/ | |||
#define CONFIG_SEED 14 | |||
/** | |||
\def VERSION | |||
Version string, only used for indicative purpose | |||
*/ | |||
#define VERSION "1.20" | |||
/** | |||
\def MENU_TIMEOUT | |||
When hooked up on Serial port, determine how much milliseconds | |||
to wait for a user input before proceeding. | |||
*/ | |||
#define MENU_TIMEOUT 20000 |