@@ -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,44 @@ | |||||
#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) { | |||||
if (!mask) return; //save a write to eeprom if there is no change | |||||
config_t* config = &config::main::value; | |||||
config->activeAlerts |= mask; | |||||
config::main::save(); | |||||
} | |||||
void clear(PositionEntryMetadata &metadata) { | |||||
config_t* config = &config::main::value; | |||||
uint8_t clearMask = 0; | |||||
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); | |||||
if (!config->activeAlerts || !clearMask) return; //save a write to eeprom if there is no change | |||||
config->activeAlerts &= ~clearMask; | |||||
config::main::save(); | |||||
} | |||||
} |
@@ -56,6 +56,7 @@ namespace core { | |||||
SIM808RegistrationStatus networkStatus; | SIM808RegistrationStatus networkStatus; | ||||
char buffer[SMS_BUFFER_SIZE]; | char buffer[SMS_BUFFER_SIZE]; | ||||
const __FlashStringHelper * backupFailureString = F(" Backup battery failure ?"); | const __FlashStringHelper * backupFailureString = F(" Backup battery failure ?"); | ||||
bool notified = false; | |||||
uint8_t triggered = alerts::getTriggered(metadata); | uint8_t triggered = alerts::getTriggered(metadata); | ||||
if (!triggered) return NO_ALERTS_NOTIFIED; | if (!triggered) return NO_ALERTS_NOTIFIED; | ||||
@@ -65,24 +66,24 @@ namespace core { | |||||
network::powerOn(); | network::powerOn(); | ||||
networkStatus = network::waitForRegistered(NETWORK_DEFAULT_TOTAL_TIMEOUT_MS); | networkStatus = network::waitForRegistered(NETWORK_DEFAULT_TOTAL_TIMEOUT_MS); | ||||
if (!network::isAvailable(networkStatus.stat)) return NO_ALERTS_NOTIFIED; | |||||
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); | |||||
} | |||||
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_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 (bitRead(triggered, ALERT_RTC_CLOCK_FAILURE)) { | |||||
details::appendToSmsBuffer(buffer, PSTR("\n- RTC was stopped.%S"), backupFailureString); | |||||
notified = network::sendSms(buffer); | |||||
if (!notified) NOTICE_MSG("notifyFailure", "SMS not sent !"); | |||||
} | } | ||||
bool notified = network::sendSms(buffer); | |||||
if (!notified) NOTICE_MSG("notifyFailure", "SMS not sent !"); | |||||
network::powerOff(); | 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) | return notified ? triggered : NO_ALERTS_NOTIFIED; //If not notified, the alerts state should not be persisted (so we can retry to notify them) | ||||
} | } | ||||
@@ -94,39 +95,38 @@ namespace core { | |||||
} | } | ||||
bool updateSleepTime() { | bool updateSleepTime() { | ||||
uint8_t velocity = gps::getVelocity(); | |||||
uint16_t result = mapSleepTime(velocity); | |||||
bool goingLongSleep = false; | bool goingLongSleep = false; | ||||
uint8_t velocity = gps::getVelocity(); | |||||
sleepTime = mapSleepTime(velocity); | |||||
if (velocity < SLEEP_TIMING_MIN_MOVING_VELOCITY) { | if (velocity < SLEEP_TIMING_MIN_MOVING_VELOCITY) { | ||||
float distance = gps::getDistanceFromPrevious(); //did we missed positions because we were sleeping ? | float distance = gps::getDistanceFromPrevious(); //did we missed positions because we were sleeping ? | ||||
if (distance > GPS_DEFAULT_MISSED_POSITION_GAP_KM) stoppedInARow = 0; | 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 | else stoppedInARow = min(stoppedInARow + 1, SLEEP_DEFAULT_STOPPED_THRESHOLD + 1); //avoid overflow on REALLY long stops | ||||
if (stoppedInARow < SLEEP_DEFAULT_STOPPED_THRESHOLD) { | if (stoppedInARow < SLEEP_DEFAULT_STOPPED_THRESHOLD) { | ||||
result = SLEEP_DEFAULT_PAUSING_TIME_SECONDS; | |||||
sleepTime = SLEEP_DEFAULT_PAUSING_TIME_SECONDS; | |||||
} | } | ||||
else if (stoppedInARow == SLEEP_DEFAULT_STOPPED_THRESHOLD) goingLongSleep = true; | else if (stoppedInARow == SLEEP_DEFAULT_STOPPED_THRESHOLD) goingLongSleep = true; | ||||
} | } | ||||
else stoppedInARow = 0; | else stoppedInARow = 0; | ||||
sleepTime = result; | |||||
NOTICE_FORMAT("updateSleepTime", "%dkmh => %d seconds", velocity, sleepTime); | NOTICE_FORMAT("updateSleepTime", "%dkmh => %d seconds", velocity, sleepTime); | ||||
return goingLongSleep; | return goingLongSleep; | ||||
} | } | ||||
uint16_t mapSleepTime(uint8_t velocity) { | uint16_t mapSleepTime(uint8_t velocity) { | ||||
uint16_t result; | uint16_t result; | ||||
uint16_t currentTime = 0xFFFF; | uint16_t currentTime = 0xFFFF; | ||||
if (rtc::isAccurate()) { | if (rtc::isAccurate()) { | ||||
tmElements_t time; | tmElements_t time; | ||||
rtc::getTime(time); | rtc::getTime(time); | ||||
currentTime = SLEEP_TIMING_TIME(time.Hour, time.Minute); | currentTime = SLEEP_TIMING_TIME(time.Hour, time.Minute); | ||||
} | } | ||||
for (uint8_t i = flash::getArraySize(config::defaultSleepTimings); i--;) { | for (uint8_t i = flash::getArraySize(config::defaultSleepTimings); i--;) { | ||||
sleepTimings_t timing; | sleepTimings_t timing; | ||||
flash::read(&config::defaultSleepTimings[i], timing); | flash::read(&config::defaultSleepTimings[i], timing); | ||||
@@ -139,7 +139,7 @@ namespace core { | |||||
} | } | ||||
VERBOSE_FORMAT("computeSleepTime", "%d,%d", velocity, result); | |||||
VERBOSE_FORMAT("mapSleepTime", "%d,%d", velocity, result); | |||||
return result; | return result; | ||||
} | } | ||||
} | } |
@@ -32,7 +32,6 @@ 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(NOTIFY_FAILURES, "[F] Notify failures"); | MENU_ENTRY(NOTIFY_FAILURES, "[F] Notify failures"); | ||||
MENU_ENTRY(CLEAR_ALERTS, "[A] Clear alerts"); | MENU_ENTRY(CLEAR_ALERTS, "[A] Clear alerts"); | ||||
MENU_ENTRY(SLEEP, "[S] Sleep for 8s"); | |||||
MENU_ENTRY(SLEEP_DEEP, "[s] Deep sleep for 10s"); | MENU_ENTRY(SLEEP_DEEP, "[s] Deep sleep for 10s"); | ||||
MENU_ENTRY(QUESTION, "?"); | MENU_ENTRY(QUESTION, "?"); | ||||
@@ -56,7 +55,6 @@ const PROGMEM uint8_t commandIdMapping[] = { | |||||
'B', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_BACKUP_ENTRIES), | 'B', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_BACKUP_ENTRIES), | ||||
'F', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::NOTIFY_FAILURES), | 'F', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::NOTIFY_FAILURES), | ||||
'A', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::CLEAR_ALERTS), | 'A', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::CLEAR_ALERTS), | ||||
'S', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::SLEEP), | |||||
's', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP), | 's', static_cast<uint8_t>(debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP), | ||||
}; | }; | ||||
@@ -97,7 +95,6 @@ const char * const MENU_ENTRIES[] PROGMEM = { | |||||
MENU_CLEAR_ALERTS, | MENU_CLEAR_ALERTS, | ||||
MENU_SEPARATOR, | MENU_SEPARATOR, | ||||
MENU_SLEEP, | |||||
MENU_SLEEP_DEEP, | MENU_SLEEP_DEEP, | ||||
MENU_QUESTION | MENU_QUESTION | ||||
@@ -115,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); | |||||
} | } | ||||
} | } | ||||
@@ -131,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)); | ||||
} | } | ||||
@@ -144,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]))); | ||||
} | } | ||||
@@ -162,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; | ||||
} | } | ||||
@@ -272,7 +269,7 @@ namespace debug { | |||||
void notifyFailures() { | void notifyFailures() { | ||||
PositionEntryMetadata metadata = { | PositionEntryMetadata metadata = { | ||||
1, //all battery alerts should goes on with this | 1, //all battery alerts should goes on with this | ||||
3800, //doesn't matter | |||||
3800, //doesn't matter | |||||
ALERT_SUSPICIOUS_RTC_TEMPERATURE, | ALERT_SUSPICIOUS_RTC_TEMPERATURE, | ||||
0, | 0, | ||||
SIM808_GPS_STATUS::OFF | SIM808_GPS_STATUS::OFF | ||||
@@ -286,7 +283,7 @@ namespace debug { | |||||
void clearAlerts() { | void clearAlerts() { | ||||
PositionEntryMetadata metadata = { | PositionEntryMetadata metadata = { | ||||
100, //all battery alerts should goes off with this | 100, //all battery alerts should goes off with this | ||||
3800, //doesn't matter | |||||
3800, //doesn't matter | |||||
10, | 10, | ||||
0, | 0, | ||||
SIM808_GPS_STATUS::OFF | SIM808_GPS_STATUS::OFF |
@@ -33,7 +33,6 @@ namespace debug { | |||||
EEPROM_BACKUP_ENTRIES, | EEPROM_BACKUP_ENTRIES, | ||||
NOTIFY_FAILURES, | NOTIFY_FAILURES, | ||||
CLEAR_ALERTS, | CLEAR_ALERTS, | ||||
SLEEP, | |||||
SLEEP_DEEP | SLEEP_DEEP | ||||
}; | }; | ||||
@@ -86,9 +86,6 @@ void loop() { | |||||
case debug::GPSTRACKER_DEBUG_COMMAND::CLEAR_ALERTS: | case debug::GPSTRACKER_DEBUG_COMMAND::CLEAR_ALERTS: | ||||
debug::clearAlerts(); | debug::clearAlerts(); | ||||
break; | break; | ||||
case debug::GPSTRACKER_DEBUG_COMMAND::SLEEP: | |||||
mainunit::sleep(period_t::SLEEP_8S); | |||||
break; | |||||
case debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP: | case debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP: | ||||
mainunit::deepSleep(10); | mainunit::deepSleep(10); | ||||
break; | break; |
@@ -1,63 +0,0 @@ | |||||
#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 result = 0; | |||||
if (metadata.batteryLevel <= config->alertBatteryLevel1 && !bitRead(config->activeAlerts, ALERT_BATTERY_LEVEL_1)) { | |||||
bitSet(result, ALERT_BATTERY_LEVEL_1); | |||||
} | |||||
if (metadata.batteryLevel <= config->alertBatteryLevel2 && !bitRead(config->activeAlerts, ALERT_BATTERY_LEVEL_2)) { | |||||
bitSet(result, ALERT_BATTERY_LEVEL_2); | |||||
} | |||||
if (metadata.temperature == ALERT_SUSPICIOUS_RTC_TEMPERATURE && !bitRead(config->activeAlerts, ALERT_RTC_TEMPERATURE_FAILURE)) { | |||||
bitSet(result, ALERT_RTC_TEMPERATURE_FAILURE); | |||||
} | |||||
if (!rtc::isAccurate() && !bitRead(config->activeAlerts, ALERT_RTC_CLOCK_FAILURE)) { | |||||
bitSet(result, ALERT_RTC_CLOCK_FAILURE); | |||||
} | |||||
return result; | |||||
} | |||||
void add(uint8_t mask) { | |||||
if (!mask) return; //save a write to eeprom if there is no change | |||||
config_t* config = &config::main::value; | |||||
config->activeAlerts |= mask; | |||||
config::main::save(); | |||||
} | |||||
void clear(PositionEntryMetadata &metadata) { | |||||
config_t* config = &config::main::value; | |||||
uint8_t clearMask = 0; | |||||
if ((config->activeAlerts & (_BV(ALERT_BATTERY_LEVEL_1) | _BV(ALERT_BATTERY_LEVEL_2))) && metadata.batteryLevel >= config->alertBatteryLevelClear) { | |||||
clearMask |= _BV(ALERT_BATTERY_LEVEL_1) | _BV(ALERT_BATTERY_LEVEL_2); | |||||
} | |||||
if (bitRead(config->activeAlerts, ALERT_RTC_TEMPERATURE_FAILURE) && metadata.temperature != ALERT_SUSPICIOUS_RTC_TEMPERATURE) { | |||||
bitSet(clearMask, ALERT_RTC_TEMPERATURE_FAILURE); | |||||
} | |||||
if (bitRead(config->activeAlerts, ALERT_RTC_CLOCK_FAILURE) && rtc::isAccurate()) { | |||||
bitSet(clearMask, ALERT_RTC_CLOCK_FAILURE); | |||||
} | |||||
if (!clearMask) return; //save a write to eeprom if there is no change | |||||
config->activeAlerts &= ~clearMask; | |||||
config::main::save(); | |||||
} | |||||
} |
@@ -10,8 +10,12 @@ namespace mainunit { | |||||
namespace details { | namespace details { | ||||
void prepareSleep() { | void prepareSleep() { | ||||
//forcing the power off of ALL devices for safety | |||||
hardware::sim808::powerOff(); | |||||
hardware::i2c::powerOff(true); | |||||
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 +39,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); | ||||
} | } |
@@ -37,7 +37,7 @@ namespace network { | |||||
report = hardware::sim808::device.getSignalQuality(); | 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) { | ||||
@@ -50,14 +50,15 @@ namespace network { | |||||
} while (timeout > 1); | } while (timeout > 1); | ||||
report = hardware::sim808::device.getSignalQuality(); | |||||
report = hardware::sim808::device.getSignalQuality(); //FIXME : report does not match currentStatus | |||||
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; //FIXME : on last loop waited for nothing | |||||
} | } | ||||
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() { |
@@ -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,28 +38,44 @@ 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) { | ||||
NOTICE("acquire"); | NOTICE("acquire"); | ||||
timestamp_t before; | timestamp_t before; | ||||
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); | ||||
@@ -95,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; | ||||
@@ -112,13 +130,13 @@ 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; | ||||
} | } | ||||
@@ -141,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" | |||||
} | |||||
} |