@@ -1,267 +1,5 @@ | |||||
## Ignore Visual Studio temporary files, build results, and | |||||
## files generated by popular Visual Studio add-ons. | |||||
# User-specific files | |||||
*.suo | |||||
*.user | |||||
*.userosscache | |||||
*.sln.docstates | |||||
# User-specific files (MonoDevelop/Xamarin Studio) | |||||
*.userprefs | |||||
# Build results | # Build results | ||||
[Dd]ebug/ | |||||
[Dd]ebugPublic/ | |||||
[Rr]elease/ | |||||
[Rr]eleases/ | |||||
x64/ | |||||
x86/ | |||||
bld/ | |||||
[Bb]in/ | [Bb]in/ | ||||
[Oo]bj/ | |||||
[Ll]og/ | |||||
# Visual Studio 2015 cache/options directory | |||||
.vs/ | |||||
# Uncomment if you have tasks that create the project's static files in wwwroot | |||||
#wwwroot/ | |||||
# MSTest test Results | |||||
[Tt]est[Rr]esult*/ | |||||
[Bb]uild[Ll]og.* | |||||
# NUNIT | |||||
*.VisualState.xml | |||||
TestResult.xml | |||||
# Build Results of an ATL Project | |||||
[Dd]ebugPS/ | |||||
[Rr]eleasePS/ | |||||
dlldata.c | |||||
# DNX | |||||
project.lock.json | |||||
project.fragment.lock.json | |||||
artifacts/ | |||||
*_i.c | |||||
*_p.c | |||||
*_i.h | |||||
*.ilk | |||||
*.meta | |||||
*.obj | |||||
*.pch | |||||
*.pdb | |||||
*.pgc | |||||
*.pgd | |||||
*.rsp | |||||
*.sbr | |||||
*.tlb | |||||
*.tli | |||||
*.tlh | |||||
*.tmp | |||||
*.tmp_proj | |||||
*.log | |||||
*.vspscc | |||||
*.vssscc | |||||
.builds | |||||
*.pidb | |||||
*.svclog | |||||
*.scc | |||||
# Chutzpah Test files | |||||
_Chutzpah* | |||||
# Visual C++ cache files | |||||
ipch/ | |||||
*.aps | |||||
*.ncb | |||||
*.opendb | |||||
*.opensdf | |||||
*.sdf | |||||
*.cachefile | |||||
*.VC.db | |||||
*.VC.VC.opendb | |||||
# Visual Studio profiler | |||||
*.psess | |||||
*.vsp | |||||
*.vspx | |||||
*.sap | |||||
# TFS 2012 Local Workspace | |||||
$tf/ | |||||
# Guidance Automation Toolkit | |||||
*.gpState | |||||
# ReSharper is a .NET coding add-in | |||||
_ReSharper*/ | |||||
*.[Rr]e[Ss]harper | |||||
*.DotSettings.user | |||||
# JustCode is a .NET coding add-in | |||||
.JustCode | |||||
# TeamCity is a build add-in | |||||
_TeamCity* | |||||
# DotCover is a Code Coverage Tool | |||||
*.dotCover | |||||
# NCrunch | |||||
_NCrunch_* | |||||
.*crunch*.local.xml | |||||
nCrunchTemp_* | |||||
# MightyMoose | |||||
*.mm.* | |||||
AutoTest.Net/ | |||||
# Web workbench (sass) | |||||
.sass-cache/ | |||||
# Installshield output folder | |||||
[Ee]xpress/ | |||||
# DocProject is a documentation generator add-in | |||||
DocProject/buildhelp/ | |||||
DocProject/Help/*.HxT | |||||
DocProject/Help/*.HxC | |||||
DocProject/Help/*.hhc | |||||
DocProject/Help/*.hhk | |||||
DocProject/Help/*.hhp | |||||
DocProject/Help/Html2 | |||||
DocProject/Help/html | |||||
# Click-Once directory | |||||
publish/ | |||||
# Publish Web Output | |||||
*.[Pp]ublish.xml | |||||
*.azurePubxml | |||||
# TODO: Comment the next line if you want to checkin your web deploy settings | |||||
# but database connection strings (with potential passwords) will be unencrypted | |||||
#*.pubxml | |||||
*.publishproj | |||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to | |||||
# checkin your Azure Web App publish settings, but sensitive information contained | |||||
# in these scripts will be unencrypted | |||||
PublishScripts/ | |||||
# NuGet Packages | |||||
*.nupkg | |||||
# The packages folder can be ignored because of Package Restore | |||||
**/packages/* | |||||
# except build/, which is used as an MSBuild target. | |||||
!**/packages/build/ | |||||
# Uncomment if necessary however generally it will be regenerated when needed | |||||
#!**/packages/repositories.config | |||||
# NuGet v3's project.json files produces more ignoreable files | |||||
*.nuget.props | |||||
*.nuget.targets | |||||
# Microsoft Azure Build Output | |||||
csx/ | |||||
*.build.csdef | |||||
# Microsoft Azure Emulator | |||||
ecf/ | |||||
rcf/ | |||||
# Windows Store app package directories and files | |||||
AppPackages/ | |||||
BundleArtifacts/ | |||||
Package.StoreAssociation.xml | |||||
_pkginfo.txt | |||||
# Visual Studio cache files | |||||
# files ending in .cache can be ignored | |||||
*.[Cc]ache | |||||
# but keep track of directories ending in .cache | |||||
!*.[Cc]ache/ | |||||
# Others | |||||
ClientBin/ | |||||
~$* | |||||
*~ | |||||
*.dbmdl | |||||
*.dbproj.schemaview | |||||
*.jfm | |||||
*.pfx | |||||
*.publishsettings | |||||
node_modules/ | |||||
orleans.codegen.cs | |||||
# Since there are multiple workflows, uncomment next line to ignore bower_components | |||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) | |||||
#bower_components/ | |||||
# RIA/Silverlight projects | |||||
Generated_Code/ | |||||
# Backup & report files from converting an old project file | |||||
# to a newer Visual Studio version. Backup files are not needed, | |||||
# because we have git ;-) | |||||
_UpgradeReport_Files/ | |||||
Backup*/ | |||||
UpgradeLog*.XML | |||||
UpgradeLog*.htm | |||||
# SQL Server files | |||||
*.mdf | |||||
*.ldf | |||||
# Business Intelligence projects | |||||
*.rdl.data | |||||
*.bim.layout | |||||
*.bim_*.settings | |||||
# Microsoft Fakes | |||||
FakesAssemblies/ | |||||
# GhostDoc plugin setting file | |||||
*.GhostDoc.xml | |||||
# Node.js Tools for Visual Studio | |||||
.ntvs_analysis.dat | |||||
# Visual Studio 6 build log | |||||
*.plg | |||||
# Visual Studio 6 workspace options file | |||||
*.opt | |||||
# Visual Studio LightSwitch build output | |||||
**/*.HTMLClient/GeneratedArtifacts | |||||
**/*.DesktopClient/GeneratedArtifacts | |||||
**/*.DesktopClient/ModelManifest.xml | |||||
**/*.Server/GeneratedArtifacts | |||||
**/*.Server/ModelManifest.xml | |||||
_Pvt_Extensions | |||||
# Paket dependency manager | |||||
.paket/paket.exe | |||||
paket-files/ | |||||
# FAKE - F# Make | |||||
.fake/ | |||||
# JetBrains Rider | |||||
.idea/ | |||||
*.sln.iml | |||||
# CodeRush | |||||
.cr/ | |||||
# Python Tools for Visual Studio (PTVS) | |||||
__pycache__/ | |||||
*.pyc | |||||
#VisualMicro | |||||
__vm/ | |||||
#Line endings unifier | |||||
.leu | |||||
#Visual Studio code | |||||
.vscode/ |
@@ -0,0 +1,22 @@ | |||||
{ | |||||
"configurations": [ | |||||
{ | |||||
"name": "Win32", | |||||
"includePath": [ | |||||
"${workspaceFolder}/**", | |||||
"${workspaceFolder}/../libraries/SIM808", | |||||
"${workspaceFolder}/../libraries/uDS3231", | |||||
"${workspaceFolder}/../libraries/E24", | |||||
"${workspaceFolder}/../libraries/Low-Power", | |||||
"${workspaceFolder}/../libraries/ArduinoLog", | |||||
"${config:arduino.path}/tools/**", | |||||
"${config:arduino.path}/hardware/arduino/avr/**", | |||||
"${config:arduino.path}/hardware/tools/avr/avr/include/**" | |||||
], | |||||
"intelliSenseMode": "clang-x64", | |||||
"cStandard": "c11", | |||||
"cppStandard": "c++11" | |||||
} | |||||
], | |||||
"version": 4 | |||||
} |
@@ -0,0 +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(); | |||||
} | |||||
} |
@@ -0,0 +1,15 @@ | |||||
#pragma once | |||||
#include "Positions.h" | |||||
#define ALERT_BATTERY_LEVEL_1 0 | |||||
#define ALERT_BATTERY_LEVEL_2 1 | |||||
#define ALERT_RTC_TEMPERATURE_FAILURE 2 | |||||
#define ALERT_RTC_CLOCK_FAILURE 3 | |||||
namespace alerts { | |||||
uint8_t getTriggered(PositionEntryMetadata &metadata); | |||||
void add(uint8_t mask); | |||||
void clear(PositionEntryMetadata &metadata); | |||||
} |
@@ -0,0 +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(); | |||||
} | |||||
} | |||||
} |
@@ -14,7 +14,7 @@ | |||||
#define CONFIG_ADDR 0 | #define CONFIG_ADDR 0 | ||||
#define CONFIG_RESERVED_SIZE 128 | #define CONFIG_RESERVED_SIZE 128 | ||||
#define CONFIG_SEED 13 | #define CONFIG_SEED 13 | ||||
#define VERSION "1.00" | |||||
#define VERSION "1.10" | |||||
#define SLEEP_TIMING_TIME(hours, minutes) hours * 60 + minutes | #define SLEEP_TIMING_TIME(hours, minutes) hours * 60 + minutes | ||||
@@ -26,8 +26,15 @@ | |||||
Hard coded value for default sleep time between position acquisitions. | Hard coded value for default sleep time between position acquisitions. | ||||
Exprimed in seconds | 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_TIME_SECONDS 1800 | ||||
#define SLEEP_DEFAULT_STOPPED_THRESHOLD 5 | |||||
#define SLEEP_DEFAULT_STOPPED_THRESHOLD 5 | |||||
#define SLEEP_DEFAULT_PAUSING_TIME_SECONDS 270 | #define SLEEP_DEFAULT_PAUSING_TIME_SECONDS 270 | ||||
#define SLEEP_TIMING_MIN SLEEP_TIMING_TIME(0, 0) | #define SLEEP_TIMING_MIN SLEEP_TIMING_TIME(0, 0) | ||||
@@ -43,6 +50,14 @@ | |||||
#define NETWORK_DEFAULT_NO_NETWORK_QUALITY_THRESHOLD 8 | #define NETWORK_DEFAULT_NO_NETWORK_QUALITY_THRESHOLD 8 | ||||
#define NETWORK_DEFAULT_NO_NETWORK_TRIES 5 | #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 | #pragma endregion | ||||
struct sleepTimings_t { | struct sleepTimings_t { | ||||
@@ -53,14 +68,21 @@ struct sleepTimings_t { | |||||
}; | }; | ||||
struct config_t { | struct config_t { | ||||
uint8_t seed; | |||||
char version[5]; | |||||
uint16_t firstEntry; | |||||
uint16_t lastEntry; | |||||
uint8_t seed; //sizeof = 1 | |||||
char version[5]; //sizeof = 5 | |||||
uint16_t firstEntry; //sizeof = 2 | |||||
uint16_t lastEntry; //sizeof = 2 | |||||
#if BACKUP_ENABLE_NETWORK | #if BACKUP_ENABLE_NETWORK | ||||
networkConfig_t network; | |||||
networkConfig_t network; //sizeof = 73 | |||||
#else | |||||
char reserved[73]; | |||||
#endif | #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 config { | ||||
@@ -0,0 +1,155 @@ | |||||
#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; | |||||
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 forceBackup = false; | |||||
bool acquired = false; | |||||
PositionEntryMetadata metadata; | |||||
positions::prepareBackup(); | |||||
acquired = positions::acquire(metadata); | |||||
if (acquired) { | |||||
positions::appendLast(metadata); | |||||
forceBackup = updateSleepTime(); | |||||
gps::preserveCurrentCoordinates(); | |||||
} | |||||
alerts::clear(metadata); | |||||
alerts::add(notifyFailures(metadata)); | |||||
positions::doBackup(forceBackup); | |||||
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"), static_cast<uint16_t>(metadata.temperature * 100), 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); | |||||
} | |||||
bool updateSleepTime() { | |||||
bool goingLongSleep = false; | |||||
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; | |||||
} | |||||
else if (stoppedInARow == SLEEP_DEFAULT_STOPPED_THRESHOLD) goingLongSleep = true; | |||||
} | |||||
else stoppedInARow = 0; | |||||
NOTICE_FORMAT("updateSleepTime", "%dkmh => %d seconds", velocity, sleepTime); | |||||
return goingLongSleep; | |||||
} | |||||
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; | |||||
} | |||||
} |
@@ -14,6 +14,9 @@ namespace core { | |||||
extern uint16_t sleepTime; | extern uint16_t sleepTime; | ||||
void main(); | void main(); | ||||
void updateRtcTime(); | |||||
bool updateSleepTime(); | bool updateSleepTime(); | ||||
uint16_t mapSleepTime(uint8_t velocity); | uint16_t mapSleepTime(uint8_t velocity); | ||||
uint8_t notifyFailures(PositionEntryMetadata &metadata); | |||||
} | } |
@@ -2,6 +2,7 @@ | |||||
#include "Flash.h" | #include "Flash.h" | ||||
#include "Positions.h" | #include "Positions.h" | ||||
#include "Core.h" | #include "Core.h" | ||||
#include "Alerts.h" | |||||
#define LOGGER_NAME "Debug" | #define LOGGER_NAME "Debug" | ||||
@@ -29,7 +30,8 @@ MENU_ENTRY(EEPROM_GET_ENTRIES, "[P] Get EEPROM entries"); | |||||
MENU_ENTRY(EEPROM_GET_LAST_ENTRY, "[p] Get EEPROM last entry"); | 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_ADD_ENTRY, "[a] Add last entry to EEPROM"); | ||||
MENU_ENTRY(EEPROM_BACKUP_ENTRIES, "[B] Backup EEPROM entries"); | MENU_ENTRY(EEPROM_BACKUP_ENTRIES, "[B] Backup EEPROM entries"); | ||||
MENU_ENTRY(SLEEP, "[S] Sleep for 8s"); | |||||
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(SLEEP_DEEP, "[s] Deep sleep for 10s"); | ||||
MENU_ENTRY(QUESTION, "?"); | MENU_ENTRY(QUESTION, "?"); | ||||
@@ -51,7 +53,8 @@ const PROGMEM uint8_t commandIdMapping[] = { | |||||
'p', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_LAST_ENTRY), | '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), | 'a', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_ADD_ENTRY), | ||||
'B', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_BACKUP_ENTRIES), | 'B', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_BACKUP_ENTRIES), | ||||
'S', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::SLEEP), | |||||
'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), | 's', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP), | ||||
}; | }; | ||||
@@ -88,7 +91,10 @@ const char * const MENU_ENTRIES[] PROGMEM = { | |||||
MENU_EEPROM_BACKUP_ENTRIES, | MENU_EEPROM_BACKUP_ENTRIES, | ||||
MENU_SEPARATOR, | MENU_SEPARATOR, | ||||
MENU_SLEEP, | |||||
MENU_NOTIFY_FAILURES, | |||||
MENU_CLEAR_ALERTS, | |||||
MENU_SEPARATOR, | |||||
MENU_SLEEP_DEEP, | MENU_SLEEP_DEEP, | ||||
MENU_QUESTION | MENU_QUESTION | ||||
@@ -106,7 +112,7 @@ namespace debug { | |||||
namespace details { | namespace details { | ||||
inline void displayPosition(PositionEntry entry) { | 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); | |||||
} | } | ||||
} | } | ||||
@@ -122,7 +128,7 @@ namespace debug { | |||||
size_t mappingArraySize = flash::getArraySize(commandIdMapping); | size_t mappingArraySize = flash::getArraySize(commandIdMapping); | ||||
char commandId; | char commandId; | ||||
for (uint8_t i = 0; i < mappingArraySize; i += 2) { | |||||
for (uint8_t i = 0; i < mappingArraySize; i += 2) { | |||||
commandId = pgm_read_byte_near(commandIdMapping + i); | commandId = pgm_read_byte_near(commandIdMapping + i); | ||||
if (commandId == id) return static_cast<GPSTRACKER_DEBUG_COMMAND>(pgm_read_byte_near(commandIdMapping + i + 1)); | if (commandId == id) return static_cast<GPSTRACKER_DEBUG_COMMAND>(pgm_read_byte_near(commandIdMapping + i + 1)); | ||||
} | } | ||||
@@ -135,7 +141,7 @@ namespace debug { | |||||
size_t menuSize = flash::getArraySize(MENU_ENTRIES); | size_t menuSize = flash::getArraySize(MENU_ENTRIES); | ||||
uint8_t intermediate_timeout = 50; | uint8_t intermediate_timeout = 50; | ||||
do { | |||||
do { | |||||
for (uint8_t i = 0; i < menuSize; i++) { | for (uint8_t i = 0; i < menuSize; i++) { | ||||
Serial.println(reinterpret_cast<const __FlashStringHelper *>(pgm_read_word_near(&MENU_ENTRIES[i]))); | Serial.println(reinterpret_cast<const __FlashStringHelper *>(pgm_read_word_near(&MENU_ENTRIES[i]))); | ||||
} | } | ||||
@@ -153,7 +159,7 @@ namespace debug { | |||||
command = parseCommand(Serial.read()); | command = parseCommand(Serial.read()); | ||||
while (Serial.available()) Serial.read(); //flushing input | while (Serial.available()) Serial.read(); //flushing input | ||||
} while (command == GPSTRACKER_DEBUG_COMMAND::NONE); | } while (command == GPSTRACKER_DEBUG_COMMAND::NONE); | ||||
return command; | return command; | ||||
} | } | ||||
@@ -183,7 +189,7 @@ namespace debug { | |||||
tmElements_t time; | tmElements_t time; | ||||
rtc::getTime(time); | rtc::getTime(time); | ||||
NOTICE_FORMAT("getAndDisplayRtcTime", "%d/%d/%d %d:%d:%d", tmYearToCalendar(time.Year), time.Month, time.Day, time.Hour, time.Minute, time.Second); | |||||
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(), (uint16_t)(rtc::getTemperature() * 1000)); | |||||
} | } | ||||
void setRtcTime() { | void setRtcTime() { | ||||
@@ -259,4 +265,30 @@ namespace debug { | |||||
for(int i = 0; i < 10; i++) positions::appendLast(metadata); | for(int i = 0; i < 10; i++) positions::appendLast(metadata); | ||||
} | } | ||||
void notifyFailures() { | |||||
PositionEntryMetadata metadata = { | |||||
1, //all battery alerts should goes on with this | |||||
3800, //doesn't matter | |||||
ALERT_SUSPICIOUS_RTC_TEMPERATURE, | |||||
0, | |||||
SIM808_GPS_STATUS::OFF | |||||
}; | |||||
uint8_t alerts = core::notifyFailures(metadata); | |||||
NOTICE_FORMAT("notifyFailures", "result : %B", alerts); | |||||
alerts::add(alerts); | |||||
} | |||||
void clearAlerts() { | |||||
PositionEntryMetadata metadata = { | |||||
100, //all battery alerts should goes off with this | |||||
3800, //doesn't matter | |||||
10, | |||||
0, | |||||
SIM808_GPS_STATUS::OFF | |||||
}; | |||||
alerts::clear(metadata); | |||||
} | |||||
} | } |
@@ -31,7 +31,8 @@ namespace debug { | |||||
EEPROM_GET_ENTRIES, | EEPROM_GET_ENTRIES, | ||||
EEPROM_ADD_ENTRY, | EEPROM_ADD_ENTRY, | ||||
EEPROM_BACKUP_ENTRIES, | EEPROM_BACKUP_ENTRIES, | ||||
SLEEP, | |||||
NOTIFY_FAILURES, | |||||
CLEAR_ALERTS, | |||||
SLEEP_DEEP | SLEEP_DEEP | ||||
}; | }; | ||||
@@ -55,5 +56,6 @@ namespace debug { | |||||
void getAndDisplayEepromLastPosition(); | void getAndDisplayEepromLastPosition(); | ||||
void addLastPositionToEeprom(); | void addLastPositionToEeprom(); | ||||
void notifyFailures(); | |||||
void clearAlerts(); | |||||
} | } |
@@ -80,8 +80,11 @@ void loop() { | |||||
case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_BACKUP_ENTRIES: | case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_BACKUP_ENTRIES: | ||||
positions::doBackup(true); | positions::doBackup(true); | ||||
break; | break; | ||||
case debug::GPSTRACKER_DEBUG_COMMAND::SLEEP: | |||||
mainunit::sleep(period_t::SLEEP_8S); | |||||
case debug::GPSTRACKER_DEBUG_COMMAND::NOTIFY_FAILURES: | |||||
debug::notifyFailures(); | |||||
break; | |||||
case debug::GPSTRACKER_DEBUG_COMMAND::CLEAR_ALERTS: | |||||
debug::clearAlerts(); | |||||
break; | break; | ||||
case debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP: | case debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP: | ||||
mainunit::deepSleep(10); | mainunit::deepSleep(10); |
@@ -1,78 +0,0 @@ | |||||
#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", 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 setup() { | |||||
details::read(); | |||||
//details::write(); | |||||
} | |||||
void save() { | |||||
details::write(); | |||||
} | |||||
void reset() { | |||||
VERBOSE("reset"); | |||||
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 | |||||
}; | |||||
value = config; | |||||
save(); | |||||
} | |||||
} | |||||
} |
@@ -1,77 +0,0 @@ | |||||
#include "Core.h" | |||||
#include "Config.h" | |||||
#include "Flash.h" | |||||
#define LOGGER_NAME "Core" | |||||
using namespace utils; | |||||
namespace core { | |||||
uint16_t sleepTime = SLEEP_DEFAULT_TIME_SECONDS; | |||||
uint8_t stoppedInARow = SLEEP_DEFAULT_STOPPED_THRESHOLD - 1; | |||||
void main() { | |||||
bool forceBackup = false; | |||||
positions::prepareBackup(); | |||||
PositionEntryMetadata metadata; | |||||
if (positions::acquire(metadata)) { | |||||
positions::appendLast(metadata); | |||||
forceBackup = updateSleepTime(); | |||||
gps::preserveCurrentCoordinates(); | |||||
} | |||||
positions::doBackup(forceBackup); | |||||
mainunit::deepSleep(sleepTime); | |||||
} | |||||
bool updateSleepTime() { | |||||
uint8_t velocity = gps::getVelocity(); | |||||
uint16_t result = mapSleepTime(velocity); | |||||
bool goingLongSleep = false; | |||||
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) { | |||||
result = SLEEP_DEFAULT_PAUSING_TIME_SECONDS; | |||||
} | |||||
else if (stoppedInARow == SLEEP_DEFAULT_STOPPED_THRESHOLD) goingLongSleep = true; | |||||
} | |||||
else stoppedInARow = 0; | |||||
sleepTime = result; | |||||
NOTICE_FORMAT("updateSleepTime", "%dkmh => %d seconds", velocity, sleepTime); | |||||
return goingLongSleep; | |||||
} | |||||
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("computeSleepTime", "%d,%d", velocity, result); | |||||
return result; | |||||
} | |||||
} |
@@ -1,13 +0,0 @@ | |||||
#pragma once | |||||
#include "Hardware.h" | |||||
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(); | |||||
} |
@@ -18,6 +18,8 @@ namespace hardware { | |||||
namespace sim808 { | namespace sim808 { | ||||
SoftwareSerial simSerial = SoftwareSerial(SIM_TX, SIM_RX); | SoftwareSerial simSerial = SoftwareSerial(SIM_TX, SIM_RX); | ||||
SIM808 device = SIM808(SIM_RST, SIM_PWR, SIM_STATUS); | SIM808 device = SIM808(SIM_RST, SIM_PWR, SIM_STATUS); | ||||
uint8_t networkPoweredCount = 0; | |||||
uint8_t gpsPoweredCount = 0; | |||||
void powerOn() { | void powerOn() { | ||||
VERBOSE("powerOn"); | VERBOSE("powerOn"); | ||||
@@ -25,14 +27,19 @@ namespace hardware { | |||||
if (!poweredOn) return; | if (!poweredOn) return; | ||||
device.init(); | device.init(); | ||||
networkPoweredCount = gpsPoweredCount = 0; | |||||
} | } | ||||
void powerOff() { | void powerOff() { | ||||
VERBOSE("powerOff"); | VERBOSE("powerOff"); | ||||
device.powerOnOff(false); | device.powerOnOff(false); | ||||
networkPoweredCount = gpsPoweredCount = 0; | |||||
} | } | ||||
void powerOffIfUnused() { | 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; | bool gpsPowered = false; | ||||
if ((!device.getGpsPowerState(&gpsPowered) || !gpsPowered) && | if ((!device.getGpsPowerState(&gpsPowered) || !gpsPowered) && | ||||
@@ -49,13 +56,30 @@ namespace hardware { | |||||
} | } | ||||
void gpsPowerOn() { | void gpsPowerOn() { | ||||
if(gpsPoweredCount) { | |||||
gpsPoweredCount++; | |||||
return; | |||||
} | |||||
VERBOSE("gpsPowerOn"); | VERBOSE("gpsPowerOn"); | ||||
powerOn(); | 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(); | device.enableGps(); | ||||
} | } | ||||
void gpsPowerOff() { | void gpsPowerOff() { | ||||
if (!device.powered()) return; | |||||
if (!device.powered()) { | |||||
networkPoweredCount = gpsPoweredCount = 0; //just to be sure counts == 0 | |||||
return; | |||||
} | |||||
if(gpsPoweredCount > 1) { | |||||
gpsPoweredCount--; | |||||
return; | |||||
} | |||||
VERBOSE("gpsPowerOff"); | VERBOSE("gpsPowerOff"); | ||||
device.disableGps(); | device.disableGps(); | ||||
@@ -63,18 +87,30 @@ namespace hardware { | |||||
} | } | ||||
void networkPowerOn() { | void networkPowerOn() { | ||||
if(networkPoweredCount) { | |||||
networkPoweredCount++; | |||||
return; | |||||
} | |||||
VERBOSE("networkPowerOn"); | VERBOSE("networkPowerOn"); | ||||
powerOn(); | powerOn(); | ||||
device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::FULL); | device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::FULL); | ||||
} | } | ||||
void networkPowerOff() { | void networkPowerOff() { | ||||
if (!device.powered()) return; | |||||
if (!device.powered()) { | |||||
networkPoweredCount = gpsPoweredCount = 0; //just to be sure counts == 0 | |||||
return; | |||||
} | |||||
if(networkPoweredCount > 1) { | |||||
networkPoweredCount--; | |||||
return; | |||||
} | |||||
VERBOSE("networkPowerOff"); | VERBOSE("networkPowerOff"); | ||||
device.disableGprs(); | device.disableGprs(); | ||||
device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::MINIMUM); | device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::MINIMUM); | ||||
powerOffIfUnused(); | powerOffIfUnused(); | ||||
} | } | ||||
} | } | ||||
@@ -87,32 +123,37 @@ namespace hardware { | |||||
uint8_t poweredCount = 0; | uint8_t poweredCount = 0; | ||||
void powerOn() { | void powerOn() { | ||||
if (!poweredCount) { | |||||
VERBOSE("powerOn"); | |||||
digitalWrite(I2C_PWR, HIGH); | |||||
pinMode(I2C_PWR, OUTPUT); | |||||
Wire.begin(); | |||||
if(poweredCount) { | |||||
poweredCount++; | |||||
return; | |||||
} | } | ||||
poweredCount++; | |||||
VERBOSE("powerOn"); | |||||
digitalWrite(I2C_PWR, HIGH); | |||||
pinMode(I2C_PWR, OUTPUT); | |||||
Wire.begin(); | |||||
poweredCount = 1; | |||||
} | } | ||||
void powerOff(bool forced = false) { | void powerOff(bool forced = false) { | ||||
if (poweredCount == 1 || forced) { | |||||
VERBOSE("powerOff"); | |||||
pinMode(I2C_PWR, INPUT); | |||||
digitalWrite(I2C_PWR, LOW); | |||||
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)); | |||||
//turn off i2c | |||||
TWCR &= ~(bit(TWEN) | bit(TWIE) | bit(TWEA)); | |||||
//disable i2c internal pull ups | |||||
digitalWrite(A4, LOW); | |||||
digitalWrite(A5, LOW); | |||||
} | |||||
//disable i2c internal pull ups | |||||
digitalWrite(A4, LOW); | |||||
digitalWrite(A5, LOW); | |||||
poweredCount--; | |||||
poweredCount = 0; | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -11,7 +11,7 @@ namespace mainunit { | |||||
void prepareSleep() { | void prepareSleep() { | ||||
hardware::sim808::simSerial.end(); //avoid woke up by SoftwareSerial interrupt | hardware::sim808::simSerial.end(); //avoid woke up by SoftwareSerial interrupt | ||||
delay(5); //ensure message have been printed out | |||||
delay(5); //ensure log messages have been printed out | |||||
} | } | ||||
void wokeUp() { | void wokeUp() { | ||||
@@ -35,14 +35,6 @@ namespace mainunit { | |||||
attachInterrupt(digitalPinToInterrupt(RTC_WAKE), interrupt, FALLING); | attachInterrupt(digitalPinToInterrupt(RTC_WAKE), interrupt, FALLING); | ||||
} | } | ||||
void sleep(period_t period) { | |||||
NOTICE_FORMAT("sleep", "Period : %d", period); | |||||
details::prepareSleep(); | |||||
LowPower.powerDown(period, ADC_OFF, BOD_OFF); | |||||
details::wokeUp(); | |||||
} | |||||
void deepSleep(uint16_t seconds) { | void deepSleep(uint16_t seconds) { | ||||
NOTICE_FORMAT("deepSleep", "%d seconds", seconds); | NOTICE_FORMAT("deepSleep", "%d seconds", seconds); | ||||
interruptIn(seconds); | interruptIn(seconds); |
@@ -4,6 +4,5 @@ | |||||
#include <LowPower.h> | #include <LowPower.h> | ||||
namespace mainunit { | namespace mainunit { | ||||
void sleep(period_t period); | |||||
void deepSleep(uint16_t seconds); | void deepSleep(uint16_t seconds); | ||||
} | } |
@@ -1,55 +1,76 @@ | |||||
#include "Config.h" | #include "Config.h" | ||||
#if BACKUP_ENABLE_NETWORK | |||||
#include "Debug.h" | #include "Debug.h" | ||||
#include "Network.h" | #include "Network.h" | ||||
#include "Hardware.h" | #include "Hardware.h" | ||||
#include "MainUnit.h" | #include "MainUnit.h" | ||||
#include "Rtc.h" | |||||
#define LOGGER_NAME "Network" | #define LOGGER_NAME "Network" | ||||
namespace network { | namespace network { | ||||
timestamp_t _poweredOnTime; | |||||
void powerOn() { | |||||
hardware::sim808::networkPowerOn(); | |||||
_poweredOnTime = rtc::getTime(); | |||||
} | |||||
void powerOff() { | |||||
hardware::sim808::networkPowerOff(); | |||||
_poweredOnTime = 0; | |||||
} | |||||
__attribute__((__optimize__("O2"))) | __attribute__((__optimize__("O2"))) | ||||
SIM808RegistrationStatus waitForRegistered(uint32_t timeout) { | |||||
SIM808RegistrationStatus waitForRegistered(uint32_t timeout, bool relativeToPowerOnTime = true) { | |||||
SIM808RegistrationStatus currentStatus; | SIM808RegistrationStatus currentStatus; | ||||
SIM808SignalQualityReport report; | SIM808SignalQualityReport report; | ||||
uint8_t noReliableNetwork = 0; | uint8_t noReliableNetwork = 0; | ||||
if (relativeToPowerOnTime) timeout -= (rtc::getTime() - _poweredOnTime) * 1000; | |||||
currentStatus = hardware::sim808::device.getNetworkRegistrationStatus(); | |||||
report = hardware::sim808::device.getSignalQuality(); | |||||
do { | do { | ||||
currentStatus = hardware::sim808::device.getNetworkRegistrationStatus(); | |||||
if (isAvailable(currentStatus.stat)) break; | if (isAvailable(currentStatus.stat)) break; | ||||
report = hardware::sim808::device.getSignalQuality(); | |||||
NOTICE_FORMAT("waitForRegistered", "%d, [%d %ddBm]", currentStatus.stat, report.ssri, report.attenuation); | NOTICE_FORMAT("waitForRegistered", "%d, [%d %ddBm]", currentStatus.stat, report.ssri, report.attenuation); | ||||
if (report.ssri < NETWORK_DEFAULT_NO_NETWORK_QUALITY_THRESHOLD) noReliableNetwork++; | if (report.ssri < NETWORK_DEFAULT_NO_NETWORK_QUALITY_THRESHOLD) noReliableNetwork++; | ||||
else noReliableNetwork = 0; | else noReliableNetwork = 0; | ||||
if (noReliableNetwork > NETWORK_DEFAULT_NO_NETWORK_TRIES) { | if (noReliableNetwork > NETWORK_DEFAULT_NO_NETWORK_TRIES) { | ||||
NOTICE_MSG("waitForRegistered", "No reliable signal"); | NOTICE_MSG("waitForRegistered", "No reliable signal"); | ||||
break; //after a while, not network really means no network. Bailing out | |||||
break; //after a while, no network really means no network. Bailing out | |||||
} | } | ||||
mainunit::deepSleep(NETWORK_DEFAULT_INTERMEDIATE_TIMEOUT_MS / 1000); | mainunit::deepSleep(NETWORK_DEFAULT_INTERMEDIATE_TIMEOUT_MS / 1000); | ||||
timeout -= NETWORK_DEFAULT_INTERMEDIATE_TIMEOUT_MS; | timeout -= NETWORK_DEFAULT_INTERMEDIATE_TIMEOUT_MS; | ||||
currentStatus = hardware::sim808::device.getNetworkRegistrationStatus(); | |||||
report = hardware::sim808::device.getSignalQuality(); | |||||
} while (timeout > 1); | } while (timeout > 1); | ||||
report = hardware::sim808::device.getSignalQuality(); | |||||
NOTICE_FORMAT("waitForRegistered", "%d, [%d %ddBm]", currentStatus.stat, report.ssri, report.attenuation); | NOTICE_FORMAT("waitForRegistered", "%d, [%d %ddBm]", currentStatus.stat, report.ssri, report.attenuation); | ||||
return currentStatus; | return currentStatus; | ||||
} | } | ||||
bool isAvailable(SIM808_NETWORK_REGISTRATION_STATE state) { | bool isAvailable(SIM808_NETWORK_REGISTRATION_STATE state) { | ||||
return state == SIM808_NETWORK_REGISTRATION_STATE::REGISTERED || | |||||
state == SIM808_NETWORK_REGISTRATION_STATE::ROAMING; | |||||
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() { | bool enableGprs() { | ||||
return hardware::sim808::device.enableGprs(config::main::value.network.apn); | return hardware::sim808::device.enableGprs(config::main::value.network.apn); | ||||
} | } | ||||
} | |||||
#endif | |||||
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); | |||||
} | |||||
} |
@@ -0,0 +1,15 @@ | |||||
#pragma once | |||||
#include "Hardware.h" | |||||
namespace network { | |||||
void powerOn(); | |||||
void powerOff(); | |||||
SIM808RegistrationStatus waitForRegistered(uint32_t timeout, bool relativeToPowerOnTime = true); | |||||
bool isAvailable(SIM808_NETWORK_REGISTRATION_STATE state); | |||||
bool enableGprs(); | |||||
bool sendSms(const char * msg); | |||||
} |
@@ -26,16 +26,15 @@ namespace positions { | |||||
bool NetworkPositionsBackup::appendPosition(PositionEntry &entry) { | bool NetworkPositionsBackup::appendPosition(PositionEntry &entry) { | ||||
char buffer[BUFFER_SIZE]; | char buffer[BUFFER_SIZE]; | ||||
snprintf(buffer, BUFFER_SIZE, "%d,%d,%d,%d,%d,%d,%d,", | |||||
snprintf_P(buffer, BUFFER_SIZE, PSTR("%d,%d,%d,%d,%d,%d,%d,%s"), | |||||
debug::freeRam(), | debug::freeRam(), | ||||
hardware::sim808::device.getSignalQuality().attenuation, | hardware::sim808::device.getSignalQuality().attenuation, | ||||
entry.metadata.batteryLevel, | entry.metadata.batteryLevel, | ||||
entry.metadata.batteryVoltage, | entry.metadata.batteryVoltage, | ||||
static_cast<uint16_t>(entry.metadata.temperature * 100), | static_cast<uint16_t>(entry.metadata.temperature * 100), | ||||
static_cast<uint8_t>(entry.metadata.status), | static_cast<uint8_t>(entry.metadata.status), | ||||
entry.metadata.timeToFix); | |||||
strcat(buffer, entry.position); | |||||
entry.metadata.timeToFix, | |||||
entry.position); | |||||
NOTICE_FORMAT("appendPosition", "Sending : %s", buffer); | NOTICE_FORMAT("appendPosition", "Sending : %s", buffer); | ||||
uint16_t responseCode = hardware::sim808::device.httpPost( | uint16_t responseCode = hardware::sim808::device.httpPost( | ||||
@@ -53,15 +52,14 @@ namespace positions { | |||||
//__attribute__((__optimize__("O2"))) | //__attribute__((__optimize__("O2"))) | ||||
void NetworkPositionsBackup::appendPositions() { | void NetworkPositionsBackup::appendPositions() { | ||||
uint16_t currentEntryIndex = config::main::value.network.lastSavedEntry + 1; | uint16_t currentEntryIndex = config::main::value.network.lastSavedEntry + 1; | ||||
uint32_t networkTimeout = 0; | |||||
PositionEntry currentEntry; | PositionEntry currentEntry; | ||||
SIM808RegistrationStatus networkStatus; | SIM808RegistrationStatus networkStatus; | ||||
network::powerOn(); | |||||
networkTimeout = NETWORK_DEFAULT_TOTAL_TIMEOUT_MS; | |||||
if (_prepareTime > 0) networkTimeout -= (rtc::getTime() - _prepareTime) * 1000; | |||||
//avoid edge case where if 0, whole set of positions will be sent again | |||||
if (!positions::count(config::main::value.network.lastSavedEntry)) return; | |||||
networkStatus = network::waitForRegistered(networkTimeout); | |||||
network::powerOn(); | |||||
networkStatus = network::waitForRegistered(NETWORK_DEFAULT_TOTAL_TIMEOUT_MS); | |||||
if (!network::isAvailable(networkStatus.stat) || !network::enableGprs()) { | if (!network::isAvailable(networkStatus.stat) || !network::enableGprs()) { | ||||
networkUnavailableInARow = min(networkUnavailableInARow + 1, POSITIONS_CONFIG_NET_DEFAULT_UNAVAILABLE_NETWORK_POSTPONE_THRESHOLD + 1); //avoid increment overflow | networkUnavailableInARow = min(networkUnavailableInARow + 1, POSITIONS_CONFIG_NET_DEFAULT_UNAVAILABLE_NETWORK_POSTPONE_THRESHOLD + 1); //avoid increment overflow | ||||
@@ -90,20 +88,13 @@ namespace positions { | |||||
network::powerOff(); | network::powerOff(); | ||||
} | } | ||||
void NetworkPositionsBackup::setup() { | |||||
NOTICE("setup"); | |||||
} | |||||
void NetworkPositionsBackup::setup() {} | |||||
void NetworkPositionsBackup::prepare() { | void NetworkPositionsBackup::prepare() { | ||||
NOTICE("prepare"); | NOTICE("prepare"); | ||||
if (!isBackupNeeded(true)) { | |||||
_prepareTime = 0; | |||||
return; | |||||
} | |||||
if (!isBackupNeeded(true)) return; | |||||
network::powerOn(); | network::powerOn(); | ||||
_prepareTime = rtc::getTime(); | |||||
} | } | ||||
void NetworkPositionsBackup::backup(bool force) { | void NetworkPositionsBackup::backup(bool force) { |
@@ -10,8 +10,6 @@ namespace positions { | |||||
class NetworkPositionsBackup : public PositionsBackup { | class NetworkPositionsBackup : public PositionsBackup { | ||||
private: | private: | ||||
timestamp_t _prepareTime; | |||||
bool isBackupNeeded(bool forPrepare); | bool isBackupNeeded(bool forPrepare); | ||||
bool appendPosition(PositionEntry &entry); | bool appendPosition(PositionEntry &entry); | ||||
void appendPositions(); | void appendPositions(); |
@@ -9,8 +9,8 @@ | |||||
struct networkConfig_t { | struct networkConfig_t { | ||||
uint8_t saveThreshold; | |||||
uint16_t lastSavedEntry; | |||||
char apn[20]; | |||||
char url[50]; | |||||
}; | |||||
uint8_t saveThreshold; //sizeof = 1 | |||||
uint16_t lastSavedEntry; //sizeof = 2 | |||||
char apn[20]; //sizeof = 20 | |||||
char url[50]; //sizeof = 50 | |||||
}; //sizeof = 73 |
@@ -4,7 +4,7 @@ | |||||
#include "Gps.h" | #include "Gps.h" | ||||
#if BACKUP_ENABLE_SDCARD || BACKUP_ENABLE_NETWORK | #if BACKUP_ENABLE_SDCARD || BACKUP_ENABLE_NETWORK | ||||
#define BACKUPS_ENABLED BACKUP_ENABLE_SDCARD + BACKUP_ENABLE_NETWORK | |||||
#define BACKUPS_ENABLED (BACKUP_ENABLE_SDCARD + BACKUP_ENABLE_NETWORK) | |||||
#endif | #endif | ||||
#if BACKUP_ENABLE_SDCARD | #if BACKUP_ENABLE_SDCARD | ||||
@@ -21,8 +21,10 @@ | |||||
#define ENTRIES_ADDR CONFIG_RESERVED_SIZE | #define ENTRIES_ADDR CONFIG_RESERVED_SIZE | ||||
namespace positions { | namespace positions { | ||||
#ifdef BACKUPS_ENABLED | |||||
#if BACKUPS_ENABLED > 1 | |||||
backup::PositionsBackup **_backups; | backup::PositionsBackup **_backups; | ||||
#elif BACKUPS_ENABLED == 1 | |||||
backup::PositionsBackup * _backup; | |||||
#endif | #endif | ||||
namespace details { | namespace details { | ||||
@@ -36,21 +38,37 @@ namespace positions { | |||||
void setup() { | void setup() { | ||||
details::maxEntryIndex = (E24_MAX_ADDRESS(hardware::i2c::eeprom.getSize()) - ENTRIES_ADDR) / ENTRY_RESERVED_SIZE; | details::maxEntryIndex = (E24_MAX_ADDRESS(hardware::i2c::eeprom.getSize()) - ENTRIES_ADDR) / ENTRY_RESERVED_SIZE; | ||||
#ifdef BACKUPS_ENABLED | |||||
#if BACKUPS_ENABLED > 0 | |||||
backup::PositionsBackup * backup = NULL; | |||||
#if BACKUPS_ENABLED > 1 | |||||
uint8_t backupIdx = 0; | uint8_t backupIdx = 0; | ||||
_backups = new backup::PositionsBackup*[BACKUPS_ENABLED]; | _backups = new backup::PositionsBackup*[BACKUPS_ENABLED]; | ||||
#endif //BACKUPS_ENABLED > 1 | |||||
#if BACKUP_ENABLE_SDCARD | #if BACKUP_ENABLE_SDCARD | ||||
_backups[backupIdx] = new backup::sd::SdPositionsBackup(); | |||||
_backups[backupIdx]->setup(); | |||||
backup = new backup::sd::SdPositionsBackup(); | |||||
backup->setup(); | |||||
#if BACKUPS_ENABLED > 1 | |||||
_backups[backupIdx] = backup; | |||||
backupIdx++; | backupIdx++; | ||||
#endif | |||||
#endif //BACKUPS_ENABLED > 1 | |||||
#endif //BACKUP_ENABLE_SDCARD | |||||
#if BACKUP_ENABLE_NETWORK | #if BACKUP_ENABLE_NETWORK | ||||
_backups[backupIdx] = new backup::net::NetworkPositionsBackup(); | |||||
_backups[backupIdx]->setup(); | |||||
backup = new backup::net::NetworkPositionsBackup(); | |||||
backup->setup(); | |||||
#if BACKUPS_ENABLED > 1 | |||||
_backups[backupIdx] = backup; | |||||
backupIdx++; | backupIdx++; | ||||
#endif | |||||
#endif | |||||
#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) { | bool acquire(PositionEntryMetadata &metadata) { | ||||
@@ -61,19 +79,13 @@ namespace positions { | |||||
gps::powerOn(); | gps::powerOn(); | ||||
before = rtc::getTime(); | before = rtc::getTime(); | ||||
SIM808_GPS_STATUS gpsStatus = gps::acquireCurrentPosition(GPS_DEFAULT_TOTAL_TIMEOUT_MS); | SIM808_GPS_STATUS gpsStatus = gps::acquireCurrentPosition(GPS_DEFAULT_TOTAL_TIMEOUT_MS); | ||||
uint16_t timeToFix = rtc::getTime() - before; | |||||
SIM808ChargingStatus battery = hardware::sim808::device.getChargingState(); | SIM808ChargingStatus battery = hardware::sim808::device.getChargingState(); | ||||
gps::powerOff(); | 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); | NOTICE_FORMAT("acquire", "Status : %d", gpsStatus); | ||||
if (gpsStatus < SIM808_GPS_STATUS::FIX) return false; | |||||
uint16_t timeToFix = rtc::getTime() - before; | |||||
tmElements_t time; | |||||
gps::getTime(time); | |||||
rtc::setTime(time); | |||||
metadata = { | metadata = { | ||||
battery.level, | battery.level, | ||||
battery.voltage, | battery.voltage, | ||||
@@ -82,7 +94,7 @@ namespace positions { | |||||
gpsStatus | gpsStatus | ||||
}; | }; | ||||
return true; | |||||
return acquired; | |||||
} | } | ||||
void appendLast(const PositionEntryMetadata &metadata) { | void appendLast(const PositionEntryMetadata &metadata) { | ||||
@@ -101,7 +113,7 @@ namespace positions { | |||||
hardware::i2c::powerOn(); | hardware::i2c::powerOn(); | ||||
hardware::i2c::eeprom.writeBlock(entryAddress, entry); | hardware::i2c::eeprom.writeBlock(entryAddress, entry); | ||||
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); | |||||
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->lastEntry++; | config->lastEntry++; | ||||
if (config->lastEntry > details::maxEntryIndex) config->lastEntry = 0; | if (config->lastEntry > details::maxEntryIndex) config->lastEntry = 0; | ||||
@@ -118,19 +130,19 @@ namespace positions { | |||||
uint16_t entryAddress = details::getEntryAddress(index); | uint16_t entryAddress = details::getEntryAddress(index); | ||||
if (entryAddress == -1) return false; | if (entryAddress == -1) return false; | ||||
VERBOSE_FORMAT("get", "Reading entry n°%d @ %X", index, entryAddress); | |||||
VERBOSE_FORMAT("get", "Reading entry n�%d @ %X", index, entryAddress); | |||||
hardware::i2c::powerOn(); | hardware::i2c::powerOn(); | ||||
hardware::i2c::eeprom.readBlock(entryAddress, entry); | hardware::i2c::eeprom.readBlock(entryAddress, entry); | ||||
hardware::i2c::powerOff(); | hardware::i2c::powerOff(); | ||||
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); | |||||
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; | return true; | ||||
} | } | ||||
bool moveNext(uint16_t &index) { | bool moveNext(uint16_t &index) { | ||||
if (index == config::main::value.lastEntry) return false; | if (index == config::main::value.lastEntry) return false; | ||||
if (index == details::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++; | else index++; | ||||
@@ -147,18 +159,22 @@ namespace positions { | |||||
} | } | ||||
void prepareBackup() { | void prepareBackup() { | ||||
#ifdef BACKUPS_ENABLED | |||||
#if BACKUPS_ENABLED > 1 | |||||
for (int i = 0; i < BACKUPS_ENABLED; i++) { | for (int i = 0; i < BACKUPS_ENABLED; i++) { | ||||
_backups[i]->prepare(); | _backups[i]->prepare(); | ||||
} | } | ||||
#elif BACKUPS_ENABLED == 1 | |||||
_backup->prepare(); | |||||
#endif | #endif | ||||
} | } | ||||
void doBackup(bool force) { | void doBackup(bool force) { | ||||
#ifdef BACKUPS_ENABLED | |||||
#if BACKUPS_ENABLED > 1 | |||||
for (int i = 0; i < BACKUPS_ENABLED; i++) { | for (int i = 0; i < BACKUPS_ENABLED; i++) { | ||||
_backups[i]->backup(force); | _backups[i]->backup(force); | ||||
} | } | ||||
#elif BACKUPS_ENABLED == 1 | |||||
_backup->backup(force); | |||||
#endif | #endif | ||||
} | } | ||||
} | } |
@@ -11,7 +11,7 @@ | |||||
using namespace utils; | using namespace utils; | ||||
namespace rtc { | namespace rtc { | ||||
void setup() { | void setup() { | ||||
VERBOSE("setup"); | VERBOSE("setup"); | ||||
hardware::i2c::powerOn(); | hardware::i2c::powerOn(); | ||||
@@ -19,8 +19,6 @@ namespace rtc { | |||||
RTC.control(DS3231_A1_INT_ENABLE, DS3231_OFF); //Alarm 1 OFF | RTC.control(DS3231_A1_INT_ENABLE, DS3231_OFF); //Alarm 1 OFF | ||||
RTC.control(DS3231_INT_ENABLE, DS3231_ON); //INTCN ON | RTC.control(DS3231_INT_ENABLE, DS3231_ON); //INTCN ON | ||||
hardware::i2c::powerOff(); | hardware::i2c::powerOff(); | ||||
//TODO : check wether the osc has been halted (meaning the battery could be dead) | |||||
} | } | ||||
float getTemperature() { | float getTemperature() { |
@@ -0,0 +1,26 @@ | |||||
{ | |||||
"folders": [ | |||||
{ | |||||
"path": "." | |||||
}, | |||||
{ | |||||
"path": "../libraries/SIM808" | |||||
}, | |||||
{ | |||||
"path": "../libraries/uDS3231" | |||||
}, | |||||
{ | |||||
"path": "../libraries/E24" | |||||
}, | |||||
{ | |||||
"path": "../libraries/Low-Power" | |||||
}, | |||||
{ | |||||
"path": "../libraries/ArduinoLog" | |||||
} | |||||
], | |||||
"settings": { | |||||
"C_Cpp.intelliSenseEngineFallback": "Disabled", | |||||
"C_Cpp.intelliSenseEngine": "Tag Parser" | |||||
} | |||||
} |