diff --git a/.gitignore b/.gitignore index 85b7e92..371c8d7 100644 --- a/.gitignore +++ b/.gitignore @@ -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 -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ [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 \ No newline at end of file +#Visual Studio code +.vscode/ \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..62faa60 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -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 +} \ No newline at end of file diff --git a/Alerts.cpp b/Alerts.cpp new file mode 100644 index 0000000..d9c8e9a --- /dev/null +++ b/Alerts.cpp @@ -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(); + } +} diff --git a/Alerts.h b/Alerts.h new file mode 100644 index 0000000..a0edc99 --- /dev/null +++ b/Alerts.h @@ -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); +} diff --git a/Config.cpp b/Config.cpp new file mode 100644 index 0000000..2328035 --- /dev/null +++ b/Config.cpp @@ -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(); + } + + } +} \ No newline at end of file diff --git a/GpsTracker/Config.h b/Config.h similarity index 67% rename from GpsTracker/Config.h rename to Config.h index 54e776e..d509e69 100644 --- a/GpsTracker/Config.h +++ b/Config.h @@ -14,7 +14,7 @@ #define CONFIG_ADDR 0 #define CONFIG_RESERVED_SIZE 128 #define CONFIG_SEED 13 -#define VERSION "1.00" +#define VERSION "1.10" #define SLEEP_TIMING_TIME(hours, minutes) hours * 60 + minutes @@ -26,8 +26,15 @@ 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_STOPPED_THRESHOLD 5 #define SLEEP_DEFAULT_PAUSING_TIME_SECONDS 270 #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_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 { @@ -53,14 +68,21 @@ struct sleepTimings_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 - networkConfig_t 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 { diff --git a/Core.cpp b/Core.cpp new file mode 100644 index 0000000..afbe9fa --- /dev/null +++ b/Core.cpp @@ -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(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; + } +} \ No newline at end of file diff --git a/GpsTracker/Core.h b/Core.h similarity index 78% rename from GpsTracker/Core.h rename to Core.h index 8e4e5b2..16ba5c7 100644 --- a/GpsTracker/Core.h +++ b/Core.h @@ -14,6 +14,9 @@ namespace core { extern uint16_t sleepTime; void main(); + void updateRtcTime(); bool updateSleepTime(); uint16_t mapSleepTime(uint8_t velocity); + + uint8_t notifyFailures(PositionEntryMetadata &metadata); } \ No newline at end of file diff --git a/GpsTracker/Debug.cpp b/Debug.cpp similarity index 84% rename from GpsTracker/Debug.cpp rename to Debug.cpp index f88d1f2..e9263ca 100644 --- a/GpsTracker/Debug.cpp +++ b/Debug.cpp @@ -2,6 +2,7 @@ #include "Flash.h" #include "Positions.h" #include "Core.h" +#include "Alerts.h" #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_ADD_ENTRY, "[a] Add last entry to EEPROM"); MENU_ENTRY(EEPROM_BACKUP_ENTRIES, "[B] Backup EEPROM entries"); -MENU_ENTRY(SLEEP, "[S] Sleep for 8s"); +MENU_ENTRY(NOTIFY_FAILURES, "[F] Notify failures"); +MENU_ENTRY(CLEAR_ALERTS, "[A] Clear alerts"); MENU_ENTRY(SLEEP_DEEP, "[s] Deep sleep for 10s"); MENU_ENTRY(QUESTION, "?"); @@ -51,7 +53,8 @@ const PROGMEM uint8_t commandIdMapping[] = { 'p', static_cast(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_GET_LAST_ENTRY), 'a', static_cast(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_ADD_ENTRY), 'B', static_cast(debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_BACKUP_ENTRIES), - 'S', static_cast(debug::GPSTRACKER_DEBUG_COMMAND::SLEEP), + 'F', static_cast(debug::GPSTRACKER_DEBUG_COMMAND::NOTIFY_FAILURES), + 'A', static_cast(debug::GPSTRACKER_DEBUG_COMMAND::CLEAR_ALERTS), 's', static_cast(debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP), }; @@ -88,7 +91,10 @@ const char * const MENU_ENTRIES[] PROGMEM = { MENU_EEPROM_BACKUP_ENTRIES, MENU_SEPARATOR, - MENU_SLEEP, + MENU_NOTIFY_FAILURES, + MENU_CLEAR_ALERTS, + MENU_SEPARATOR, + MENU_SLEEP_DEEP, MENU_QUESTION @@ -106,7 +112,7 @@ namespace debug { namespace details { inline void displayPosition(PositionEntry entry) { - Log.notice(F("%d%%, %dmV, %f°C, %ds, %d, %s\n"), entry.metadata.batteryLevel, entry.metadata.batteryVoltage, entry.metadata.temperature, entry.metadata.timeToFix, entry.metadata.status, entry.position); + Log.notice(F("%d%%, %dmV, %f�C, %ds, %d, %s\n"), entry.metadata.batteryLevel, entry.metadata.batteryVoltage, entry.metadata.temperature, entry.metadata.timeToFix, entry.metadata.status, entry.position); } } @@ -122,7 +128,7 @@ namespace debug { size_t mappingArraySize = flash::getArraySize(commandIdMapping); 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); if (commandId == id) return static_cast(pgm_read_byte_near(commandIdMapping + i + 1)); } @@ -135,7 +141,7 @@ namespace debug { size_t menuSize = flash::getArraySize(MENU_ENTRIES); uint8_t intermediate_timeout = 50; - do { + do { for (uint8_t i = 0; i < menuSize; i++) { Serial.println(reinterpret_cast(pgm_read_word_near(&MENU_ENTRIES[i]))); } @@ -153,7 +159,7 @@ namespace debug { command = parseCommand(Serial.read()); while (Serial.available()) Serial.read(); //flushing input } while (command == GPSTRACKER_DEBUG_COMMAND::NONE); - + return command; } @@ -183,7 +189,7 @@ namespace debug { tmElements_t 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() { @@ -259,4 +265,30 @@ namespace debug { 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); + } } \ No newline at end of file diff --git a/GpsTracker/Debug.h b/Debug.h similarity index 92% rename from GpsTracker/Debug.h rename to Debug.h index ee3f48f..b02fea7 100644 --- a/GpsTracker/Debug.h +++ b/Debug.h @@ -31,7 +31,8 @@ namespace debug { EEPROM_GET_ENTRIES, EEPROM_ADD_ENTRY, EEPROM_BACKUP_ENTRIES, - SLEEP, + NOTIFY_FAILURES, + CLEAR_ALERTS, SLEEP_DEEP }; @@ -55,5 +56,6 @@ namespace debug { void getAndDisplayEepromLastPosition(); void addLastPositionToEeprom(); - + void notifyFailures(); + void clearAlerts(); } diff --git a/GpsTracker/Flash.cpp b/Flash.cpp similarity index 100% rename from GpsTracker/Flash.cpp rename to Flash.cpp diff --git a/GpsTracker/Flash.h b/Flash.h similarity index 100% rename from GpsTracker/Flash.h rename to Flash.h diff --git a/GpsTracker/Gps.cpp b/Gps.cpp similarity index 100% rename from GpsTracker/Gps.cpp rename to Gps.cpp diff --git a/GpsTracker/Gps.h b/Gps.h similarity index 100% rename from GpsTracker/Gps.h rename to Gps.h diff --git a/GpsTracker/GpsTracker.h b/GpsTracker.h similarity index 100% rename from GpsTracker/GpsTracker.h rename to GpsTracker.h diff --git a/GpsTracker/GpsTracker.ino b/GpsTracker.ino similarity index 93% rename from GpsTracker/GpsTracker.ino rename to GpsTracker.ino index 806f815..984c9bb 100644 --- a/GpsTracker/GpsTracker.ino +++ b/GpsTracker.ino @@ -80,8 +80,11 @@ void loop() { case debug::GPSTRACKER_DEBUG_COMMAND::EEPROM_BACKUP_ENTRIES: positions::doBackup(true); 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; case debug::GPSTRACKER_DEBUG_COMMAND::SLEEP_DEEP: mainunit::deepSleep(10); diff --git a/GpsTracker/Config.cpp b/GpsTracker/Config.cpp deleted file mode 100644 index 4948580..0000000 --- a/GpsTracker/Config.cpp +++ /dev/null @@ -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(); - } - - } -} \ No newline at end of file diff --git a/GpsTracker/Core.cpp b/GpsTracker/Core.cpp deleted file mode 100644 index 386e33d..0000000 --- a/GpsTracker/Core.cpp +++ /dev/null @@ -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; - } -} \ No newline at end of file diff --git a/GpsTracker/Network.h b/GpsTracker/Network.h deleted file mode 100644 index 33ee41e..0000000 --- a/GpsTracker/Network.h +++ /dev/null @@ -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(); -} \ No newline at end of file diff --git a/GpsTracker/~AutoRecover.GpsTracker.vcxproj0 b/GpsTracker/~AutoRecover.GpsTracker.vcxproj0 deleted file mode 100644 index 1555d93..0000000 --- a/GpsTracker/~AutoRecover.GpsTracker.vcxproj0 +++ /dev/null @@ -1,143 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {C5F80730-F44F-4478-BDAE-6634EFC2CA88} - GpsTracker - GpsTracker - - - - Application - true - - - MultiByte - - - Application - false - - - true - MultiByte - - - - - - - - - - - - - - - - - - - - Level3 - Disabled - true - $(ProjectDir)..\GpsTracker;$(ProjectDir)..\..\libraries\E24;$(ProjectDir)..\..\libraries\SIM808;$(ProjectDir)..\..\libraries\uDS3231;$(ProjectDir)..\..\libraries\ArduinoLog;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src;$(ProjectDir)..\..\libraries\Low-Power;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\SoftwareSerial\src;$(ProjectDir)..\..\libraries\SdFat\src;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\SPI\src;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\libraries;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries;$(ProjectDir)..\..\libraries;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\avr\include\;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\avr\include\avr\;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\lib\gcc\avr\4.8.1\include;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\lib\gcc\avr\4.9.2\include;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\lib\gcc\avr\4.9.3\include;%(AdditionalIncludeDirectories) - $(ProjectDir)__vm\.GpsTracker.vsarduino.h;%(ForcedIncludeFiles) - false - __AVR_ATmega328p__;__AVR_ATmega328P__;_DEBUG=1;_VMDEBUG=1;F_CPU=8000000L;ARDUINO=10805;ARDUINO_AVR_PRO;ARDUINO_ARCH_AVR;__cplusplus=201103L;_VMICRO_INTELLISENSE;%(PreprocessorDefinitions) - - - true - - - - - Level3 - Disabled - true - true - true - $(ProjectDir)..\GpsTracker;$(ProjectDir)..\..\libraries\E24;$(ProjectDir)..\..\libraries\SIM808;$(ProjectDir)..\..\libraries\uDS3231;$(ProjectDir)..\..\libraries\ArduinoLog;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\SoftwareSerial\src;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src;$(ProjectDir)..\..\libraries\Low-Power;$(ProjectDir)..\..\libraries\SdFat\src;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\SPI\src;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src\utility;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\libraries;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\libraries;$(ProjectDir)..\..\libraries;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\arduino\avr\variants\eightanaloginputs;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\avr\include\;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\avr\include\avr\;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\lib\gcc\avr\4.8.1\include;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\lib\gcc\avr\4.9.2\include;$(ProjectDir)..\..\..\..\..\..\..\..\Program Files (x86)\Arduino\hardware\tools\avr\lib\gcc\avr\4.9.3\include;%(AdditionalIncludeDirectories) - $(ProjectDir)__vm\.GpsTracker.vsarduino.h;%(ForcedIncludeFiles) - false - __AVR_ATmega328p__;__AVR_ATmega328P__;F_CPU=8000000L;ARDUINO=10805;ARDUINO_AVR_PRO;ARDUINO_ARCH_AVR;__cplusplus=201103L;_VMICRO_INTELLISENSE;%(PreprocessorDefinitions) - - - true - true - true - - - - - - - VisualMicroDebugger - - - - CppCode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/GpsTracker/Hardware.cpp b/Hardware.cpp similarity index 52% rename from GpsTracker/Hardware.cpp rename to Hardware.cpp index 640ed9d..35ffc48 100644 --- a/GpsTracker/Hardware.cpp +++ b/Hardware.cpp @@ -18,6 +18,8 @@ namespace hardware { 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"); @@ -25,14 +27,19 @@ namespace hardware { 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) && @@ -49,13 +56,30 @@ namespace hardware { } 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()) return; + if (!device.powered()) { + networkPoweredCount = gpsPoweredCount = 0; //just to be sure counts == 0 + return; + } + + if(gpsPoweredCount > 1) { + gpsPoweredCount--; + return; + } VERBOSE("gpsPowerOff"); device.disableGps(); @@ -63,18 +87,30 @@ namespace hardware { } void networkPowerOn() { + if(networkPoweredCount) { + networkPoweredCount++; + return; + } + VERBOSE("networkPowerOn"); powerOn(); device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::FULL); } 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"); device.disableGprs(); device.setPhoneFunctionality(SIM808_PHONE_FUNCTIONALITY::MINIMUM); - powerOffIfUnused(); } } @@ -87,32 +123,37 @@ namespace hardware { uint8_t poweredCount = 0; 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) { - 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; } } } diff --git a/GpsTracker/Hardware.h b/Hardware.h similarity index 100% rename from GpsTracker/Hardware.h rename to Hardware.h diff --git a/GpsTracker/Logging.cpp b/Logging.cpp similarity index 100% rename from GpsTracker/Logging.cpp rename to Logging.cpp diff --git a/GpsTracker/Logging.h b/Logging.h similarity index 100% rename from GpsTracker/Logging.h rename to Logging.h diff --git a/GpsTracker/MainUnit.cpp b/MainUnit.cpp similarity index 80% rename from GpsTracker/MainUnit.cpp rename to MainUnit.cpp index e72e2aa..1d02dff 100644 --- a/GpsTracker/MainUnit.cpp +++ b/MainUnit.cpp @@ -11,7 +11,7 @@ namespace mainunit { void prepareSleep() { 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() { @@ -35,14 +35,6 @@ namespace mainunit { 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) { NOTICE_FORMAT("deepSleep", "%d seconds", seconds); interruptIn(seconds); diff --git a/GpsTracker/MainUnit.h b/MainUnit.h similarity index 78% rename from GpsTracker/MainUnit.h rename to MainUnit.h index 8a7b633..791894a 100644 --- a/GpsTracker/MainUnit.h +++ b/MainUnit.h @@ -4,6 +4,5 @@ #include namespace mainunit { - void sleep(period_t period); void deepSleep(uint16_t seconds); } \ No newline at end of file diff --git a/GpsTracker/Network.cpp b/Network.cpp similarity index 58% rename from GpsTracker/Network.cpp rename to Network.cpp index 030435d..79033f3 100644 --- a/GpsTracker/Network.cpp +++ b/Network.cpp @@ -1,55 +1,76 @@ #include "Config.h" -#if BACKUP_ENABLE_NETWORK #include "Debug.h" #include "Network.h" #include "Hardware.h" #include "MainUnit.h" +#include "Rtc.h" #define LOGGER_NAME "Network" namespace network { + timestamp_t _poweredOnTime; + + void powerOn() { + hardware::sim808::networkPowerOn(); + _poweredOnTime = rtc::getTime(); + } + + void powerOff() { + hardware::sim808::networkPowerOff(); + _poweredOnTime = 0; + } + __attribute__((__optimize__("O2"))) - SIM808RegistrationStatus waitForRegistered(uint32_t timeout) { + SIM808RegistrationStatus waitForRegistered(uint32_t timeout, bool relativeToPowerOnTime = true) { SIM808RegistrationStatus currentStatus; SIM808SignalQualityReport report; uint8_t noReliableNetwork = 0; + if (relativeToPowerOnTime) timeout -= (rtc::getTime() - _poweredOnTime) * 1000; + + currentStatus = hardware::sim808::device.getNetworkRegistrationStatus(); + report = hardware::sim808::device.getSignalQuality(); + do { - currentStatus = hardware::sim808::device.getNetworkRegistrationStatus(); if (isAvailable(currentStatus.stat)) break; - report = hardware::sim808::device.getSignalQuality(); NOTICE_FORMAT("waitForRegistered", "%d, [%d %ddBm]", currentStatus.stat, report.ssri, report.attenuation); - + if (report.ssri < NETWORK_DEFAULT_NO_NETWORK_QUALITY_THRESHOLD) noReliableNetwork++; else noReliableNetwork = 0; if (noReliableNetwork > NETWORK_DEFAULT_NO_NETWORK_TRIES) { NOTICE_MSG("waitForRegistered", "No reliable signal"); - break; //after a while, 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); timeout -= NETWORK_DEFAULT_INTERMEDIATE_TIMEOUT_MS; + currentStatus = hardware::sim808::device.getNetworkRegistrationStatus(); + report = hardware::sim808::device.getSignalQuality(); } while (timeout > 1); - report = hardware::sim808::device.getSignalQuality(); NOTICE_FORMAT("waitForRegistered", "%d, [%d %ddBm]", currentStatus.stat, report.ssri, report.attenuation); return currentStatus; } bool isAvailable(SIM808_NETWORK_REGISTRATION_STATE state) { - return state == SIM808_NETWORK_REGISTRATION_STATE::REGISTERED || - state == SIM808_NETWORK_REGISTRATION_STATE::ROAMING; + return static_cast(state) & + (static_cast(SIM808_NETWORK_REGISTRATION_STATE::REGISTERED) | static_cast(SIM808_NETWORK_REGISTRATION_STATE::ROAMING)) + != 0; } bool enableGprs() { return hardware::sim808::device.enableGprs(config::main::value.network.apn); } - - -} -#endif \ No newline at end of file + + 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); + } +} \ No newline at end of file diff --git a/Network.h b/Network.h new file mode 100644 index 0000000..80334e8 --- /dev/null +++ b/Network.h @@ -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); +} \ No newline at end of file diff --git a/GpsTracker/NetworkPositionsBackup.cpp b/NetworkPositionsBackup.cpp similarity index 84% rename from GpsTracker/NetworkPositionsBackup.cpp rename to NetworkPositionsBackup.cpp index 77d44e7..1e387c9 100644 --- a/GpsTracker/NetworkPositionsBackup.cpp +++ b/NetworkPositionsBackup.cpp @@ -26,16 +26,15 @@ namespace positions { bool NetworkPositionsBackup::appendPosition(PositionEntry &entry) { 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(), hardware::sim808::device.getSignalQuality().attenuation, entry.metadata.batteryLevel, entry.metadata.batteryVoltage, static_cast(entry.metadata.temperature * 100), static_cast(entry.metadata.status), - entry.metadata.timeToFix); - - strcat(buffer, entry.position); + entry.metadata.timeToFix, + entry.position); NOTICE_FORMAT("appendPosition", "Sending : %s", buffer); uint16_t responseCode = hardware::sim808::device.httpPost( @@ -53,15 +52,14 @@ namespace positions { //__attribute__((__optimize__("O2"))) void NetworkPositionsBackup::appendPositions() { uint16_t currentEntryIndex = config::main::value.network.lastSavedEntry + 1; - uint32_t networkTimeout = 0; PositionEntry currentEntry; 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()) { networkUnavailableInARow = min(networkUnavailableInARow + 1, POSITIONS_CONFIG_NET_DEFAULT_UNAVAILABLE_NETWORK_POSTPONE_THRESHOLD + 1); //avoid increment overflow @@ -90,20 +88,13 @@ namespace positions { network::powerOff(); } - void NetworkPositionsBackup::setup() { - NOTICE("setup"); - } + void NetworkPositionsBackup::setup() {} void NetworkPositionsBackup::prepare() { NOTICE("prepare"); - if (!isBackupNeeded(true)) { - _prepareTime = 0; - return; - } - + if (!isBackupNeeded(true)) return; network::powerOn(); - _prepareTime = rtc::getTime(); } void NetworkPositionsBackup::backup(bool force) { diff --git a/GpsTracker/NetworkPositionsBackup.h b/NetworkPositionsBackup.h similarity index 93% rename from GpsTracker/NetworkPositionsBackup.h rename to NetworkPositionsBackup.h index 4986093..751a911 100644 --- a/GpsTracker/NetworkPositionsBackup.h +++ b/NetworkPositionsBackup.h @@ -10,8 +10,6 @@ namespace positions { class NetworkPositionsBackup : public PositionsBackup { private: - timestamp_t _prepareTime; - bool isBackupNeeded(bool forPrepare); bool appendPosition(PositionEntry &entry); void appendPositions(); diff --git a/GpsTracker/NetworkPositionsConfig.h b/NetworkPositionsConfig.h similarity index 70% rename from GpsTracker/NetworkPositionsConfig.h rename to NetworkPositionsConfig.h index 3313b16..a363b7f 100644 --- a/GpsTracker/NetworkPositionsConfig.h +++ b/NetworkPositionsConfig.h @@ -9,8 +9,8 @@ struct networkConfig_t { - uint8_t saveThreshold; - uint16_t lastSavedEntry; - char apn[20]; - char url[50]; -}; \ No newline at end of file + uint8_t saveThreshold; //sizeof = 1 + uint16_t lastSavedEntry; //sizeof = 2 + char apn[20]; //sizeof = 20 + char url[50]; //sizeof = 50 +}; //sizeof = 73 \ No newline at end of file diff --git a/GpsTracker/Pins.h b/Pins.h similarity index 100% rename from GpsTracker/Pins.h rename to Pins.h diff --git a/GpsTracker/Positions.cpp b/Positions.cpp similarity index 67% rename from GpsTracker/Positions.cpp rename to Positions.cpp index 14e0253..5feea1e 100644 --- a/GpsTracker/Positions.cpp +++ b/Positions.cpp @@ -4,7 +4,7 @@ #include "Gps.h" #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 #if BACKUP_ENABLE_SDCARD @@ -21,8 +21,10 @@ #define ENTRIES_ADDR CONFIG_RESERVED_SIZE namespace positions { -#ifdef BACKUPS_ENABLED +#if BACKUPS_ENABLED > 1 backup::PositionsBackup **_backups; +#elif BACKUPS_ENABLED == 1 + backup::PositionsBackup * _backup; #endif namespace details { @@ -36,21 +38,37 @@ namespace positions { void setup() { 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; _backups = new backup::PositionsBackup*[BACKUPS_ENABLED]; +#endif //BACKUPS_ENABLED > 1 #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++; -#endif +#endif //BACKUPS_ENABLED > 1 +#endif //BACKUP_ENABLE_SDCARD + #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++; -#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) { @@ -61,19 +79,13 @@ namespace positions { gps::powerOn(); before = rtc::getTime(); SIM808_GPS_STATUS gpsStatus = gps::acquireCurrentPosition(GPS_DEFAULT_TOTAL_TIMEOUT_MS); + uint16_t timeToFix = rtc::getTime() - before; SIM808ChargingStatus battery = hardware::sim808::device.getChargingState(); gps::powerOff(); + bool acquired = gpsStatus >= SIM808_GPS_STATUS::FIX; //prety useless wins 14 bytes on the hex size rather than return gpStatus >= ... NOTICE_FORMAT("acquire", "Status : %d", gpsStatus); - if (gpsStatus < SIM808_GPS_STATUS::FIX) return false; - - uint16_t timeToFix = rtc::getTime() - before; - - tmElements_t time; - gps::getTime(time); - rtc::setTime(time); - metadata = { battery.level, battery.voltage, @@ -82,7 +94,7 @@ namespace positions { gpsStatus }; - return true; + return acquired; } void appendLast(const PositionEntryMetadata &metadata) { @@ -101,7 +113,7 @@ namespace positions { hardware::i2c::powerOn(); 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++; if (config->lastEntry > details::maxEntryIndex) config->lastEntry = 0; @@ -118,19 +130,19 @@ namespace positions { uint16_t entryAddress = details::getEntryAddress(index); 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::eeprom.readBlock(entryAddress, entry); 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; } bool moveNext(uint16_t &index) { if (index == config::main::value.lastEntry) return false; - + if (index == details::maxEntryIndex) index = 0; //could use a modulo but easier to understand that way else index++; @@ -147,18 +159,22 @@ namespace positions { } void prepareBackup() { -#ifdef BACKUPS_ENABLED +#if BACKUPS_ENABLED > 1 for (int i = 0; i < BACKUPS_ENABLED; i++) { _backups[i]->prepare(); } +#elif BACKUPS_ENABLED == 1 + _backup->prepare(); #endif } void doBackup(bool force) { -#ifdef BACKUPS_ENABLED +#if BACKUPS_ENABLED > 1 for (int i = 0; i < BACKUPS_ENABLED; i++) { _backups[i]->backup(force); } +#elif BACKUPS_ENABLED == 1 + _backup->backup(force); #endif } } \ No newline at end of file diff --git a/GpsTracker/Positions.h b/Positions.h similarity index 100% rename from GpsTracker/Positions.h rename to Positions.h diff --git a/GpsTracker/PositionsBackup.cpp b/PositionsBackup.cpp similarity index 100% rename from GpsTracker/PositionsBackup.cpp rename to PositionsBackup.cpp diff --git a/GpsTracker/PositionsBackup.h b/PositionsBackup.h similarity index 100% rename from GpsTracker/PositionsBackup.h rename to PositionsBackup.h diff --git a/GpsTracker/Rtc.cpp b/Rtc.cpp similarity index 95% rename from GpsTracker/Rtc.cpp rename to Rtc.cpp index 26d8b45..861e3a2 100644 --- a/GpsTracker/Rtc.cpp +++ b/Rtc.cpp @@ -11,7 +11,7 @@ using namespace utils; namespace rtc { - + void setup() { VERBOSE("setup"); hardware::i2c::powerOn(); @@ -19,8 +19,6 @@ namespace rtc { RTC.control(DS3231_A1_INT_ENABLE, DS3231_OFF); //Alarm 1 OFF RTC.control(DS3231_INT_ENABLE, DS3231_ON); //INTCN ON hardware::i2c::powerOff(); - - //TODO : check wether the osc has been halted (meaning the battery could be dead) } float getTemperature() { diff --git a/GpsTracker/Rtc.h b/Rtc.h similarity index 100% rename from GpsTracker/Rtc.h rename to Rtc.h diff --git a/GpsTracker/SdCard.cpp b/SdCard.cpp similarity index 100% rename from GpsTracker/SdCard.cpp rename to SdCard.cpp diff --git a/GpsTracker/SdCard.h b/SdCard.h similarity index 100% rename from GpsTracker/SdCard.h rename to SdCard.h diff --git a/GpsTracker/SdPositionsBackup.cpp b/SdPositionsBackup.cpp similarity index 100% rename from GpsTracker/SdPositionsBackup.cpp rename to SdPositionsBackup.cpp diff --git a/GpsTracker/SdPositionsBackup.h b/SdPositionsBackup.h similarity index 100% rename from GpsTracker/SdPositionsBackup.h rename to SdPositionsBackup.h diff --git a/GpsTracker/SdPositionsConfig.cpp b/SdPositionsConfig.cpp similarity index 100% rename from GpsTracker/SdPositionsConfig.cpp rename to SdPositionsConfig.cpp diff --git a/GpsTracker/SdPositionsConfig.h b/SdPositionsConfig.h similarity index 100% rename from GpsTracker/SdPositionsConfig.h rename to SdPositionsConfig.h diff --git a/GpsTracker/Time2.cpp b/Time2.cpp similarity index 100% rename from GpsTracker/Time2.cpp rename to Time2.cpp diff --git a/GpsTracker/Time2.h b/Time2.h similarity index 100% rename from GpsTracker/Time2.h rename to Time2.h diff --git a/gpstracker.code-workspace b/gpstracker.code-workspace new file mode 100644 index 0000000..1f9a02e --- /dev/null +++ b/gpstracker.code-workspace @@ -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" + } +} \ No newline at end of file