diff --git a/TelnetPrint.h b/TelnetPrint.h index a6f1779..80e3028 100644 --- a/TelnetPrint.h +++ b/TelnetPrint.h @@ -57,7 +57,7 @@ class TelnetPrint : public Print { return 1; } - // Is only called for Strings, not char arrays + // Is only called for Strings, not char arrays? /*virtual size_t write(const char *buffer, size_t size) { for(uint8_t i = 0; i < MAX_TELNET_CLIENTS; i++){ if (clients[i] && clients[i].connected()){ diff --git a/config.h b/config.h index bab67fc..548a5c5 100644 --- a/config.h +++ b/config.h @@ -1,12 +1,16 @@ #pragma once /* GENERAL */ -// interval of the measurements in ms. 0 for "as fast as possible" -#define MEASUREMENT_INTERVAL 10000 +// interval of the measurements in millisec / meters +#define MEASUREMENT_INTERVAL 10000 // 0 for "as fast as possible" +#define MEASUREMENT_DISTANCE_ENABLED true +#define MEASUREMENT_DISTANCE 25 + // pull this pin down to disable measurements (eg for quickly bulk uploading stored measurements) #define PIN_MEASURE_MODE D14 // pull this pin down to disable uploads (eg for higher measurement rates when no realtime data is required) #define PIN_UPLOAD_MODE D15 + // should be higher than the number of sensors to avoid storage overflowing. tradeoff with the measurement interval #define MAX_UPLOADS_PER_CYCLE 4 diff --git a/gps.h b/gps.h index e57070f..c38ae3a 100644 --- a/gps.h +++ b/gps.h @@ -3,24 +3,22 @@ #include #include "config.h" -// TODO: refactor updateXXX members to be protected and called by getXXX ? - class Gps { protected: TinyGPSPlus gps; - + public: void begin() { Serial.begin(GPS_BAUD); } - - /** + + /** * parse all available bytes from the Serial input * should be called frequently to avoid buffer overflows */ void pollGPS() { while (Serial.available() > 0) - gps.encode(Serial.read()); + gps.encode(Serial.read()); } /** @@ -31,14 +29,14 @@ class Gps { // abort if the GPS device does not push valid data within one update cycle static const unsigned int timeout = 2 * GPS_INTERVAL; unsigned long start = millis(); - + do { pollGPS(); if (millis() - start > timeout) return false; - } while (!gps.location.isUpdated()); // TODO: check if is valid? + } while (!gps.location.isUpdated() && !gps.location.isValid()); return true; } - + /** * poll until we have a valid date & time. * retries at most once, returns success state @@ -48,23 +46,22 @@ class Gps { static const unsigned int timeout = 2 * GPS_INTERVAL; unsigned long start = millis(); - // TODO: check if is valid? do { pollGPS(); if (millis() - start > timeout) return false; - } while ( !(gps.date.isUpdated() && gps.time.isUpdated()) ); - + } while ( !(gps.date.isUpdated() && gps.time.isUpdated() && gps.time.isValid() && gps.time.isValid()) ); + // in case we didnt timeout, resync the local clock (Time.h) setTime(gps.time.hour(), gps.time.minute(), gps.time.second(), gps.date.day(), gps.date.month(), gps.date.year()); - + return true; } TinyGPSLocation& getLocation() { return gps.location; } - + /** * fill a char[20] with an iso8601 formatted date from now */ diff --git a/mobile-sensebox.ino b/mobile-sensebox.ino index 4b0daa0..3a152e7 100644 --- a/mobile-sensebox.ino +++ b/mobile-sensebox.ino @@ -1,3 +1,4 @@ +#include #include "config.h" #include "gps.h" #include "wifi.h" @@ -14,6 +15,10 @@ TelnetPrint telnet = TelnetPrint(); OsemApi api = OsemApi(); Gps gps = Gps(); +unsigned long cycleStart; +WifiState wifiState; // global, as both measure and upload need the state +TinyGPSLocation location; + bool storeMeasurement(float lat, float lng, float value, const char* timeStamp, const char* sensorID) { Measurement m; m.lat = lat; @@ -24,22 +29,21 @@ bool storeMeasurement(float lat, float lng, float value, const char* timeStamp, return storage.add(m); } -void measure(WifiState& wifiState) { +void measure(WifiState& wifiState, TinyGPSLocation& loc) { char dateString[20]; // measure WiFi wifiState = wifi.scan(WIFI_SSID); - // update gps position - // TODO: how to handle lost GPS fix? - // TODO: check if is data is valid? + // update gps position if we can't get a fix, skip the measurements if(!gps.updateLocation() || !gps.updateTime()) { - DEBUG_OUT << "GPS timed out" << EOL; - digitalWrite(BUILTIN_LED, LOW); - } else { - digitalWrite(BUILTIN_LED, HIGH); + DEBUG_OUT << "GPS timed out, skipping measurements" << EOL; + digitalWrite(BUILTIN_LED, LOW); // turn status LED on + return; } - TinyGPSLocation loc = gps.getLocation(); + + digitalWrite(BUILTIN_LED, HIGH); + loc = gps.getLocation(); gps.getISODate(dateString); // print state @@ -100,13 +104,22 @@ void upload(WifiState& wifiState) { // delay for a given duration (ms), rollover-safe implementation // offset may be a duration which has been "used up" before, so the delay is adaptive, // meaning that the interval of a adaptiveDelay() call is constant -void adaptiveDelay(unsigned long ms, unsigned long offset = 0) { +// returns earlier, if we moved more than MEASUREMENT_DISTANCE meters from our last fix +void adaptiveDelay(unsigned long ms, TinyGPSLocation& lastLoc, unsigned long offset = 0) { unsigned long start = millis(); for (;;) { // for some reason, operations have to be performed in this loop for // proper operation, so we just do the polling to be done anyway gps.pollGPS(); telnet.pollClients(); + + // update our location. if we moved MEASUREMENT_DISTANCE meters or more, return + TinyGPSLocation newLoc = gps.getLocation(); + double distanceToPrevLoc = TinyGPSPlus::distanceBetween(lastLoc.lat(), lastLoc.lng(), newLoc.lat(), newLoc.lng()); + if (MEASUREMENT_DISTANCE_ENABLED && distanceToPrevLoc >= MEASUREMENT_DISTANCE) { + DEBUG_OUT << "moved " << distanceToPrevLoc << "m, delay stopped." << EOL; + return; + } unsigned long now = millis(); unsigned long elapsed = now - start + offset; @@ -135,6 +148,7 @@ void setup() { // wait until we got a first fix from GPS, and thus an initial time DEBUG_OUT << "Getting GPS fix.."; while (!gps.updateLocation()) { DEBUG_OUT << "."; } + location = gps.getLocation(); DEBUG_OUT << " done!" << EOL; digitalWrite(BUILTIN_LED, HIGH); @@ -144,26 +158,22 @@ void setup() { DEBUG_OUT << "SPIFF bytes free: " << bytesFree << EOL << EOL; } -unsigned long cycleStart; -WifiState wifiState; // global, as both measure and upload need the state - void loop() { cycleStart = millis(); if (digitalRead(PIN_MEASURE_MODE) == HIGH) - measure(wifiState); + measure(wifiState, location); if (digitalRead(PIN_UPLOAD_MODE) == HIGH) upload(wifiState); if (digitalRead(PIN_MEASURE_MODE) == HIGH) { // run the measurements in a fixed interval, using an adaptive delay - // IDEA: dont use time but distance interval? -> TinyGPSPlus::distanceBetween() - adaptiveDelay(MEASUREMENT_INTERVAL, millis() - cycleStart); - } else { - // run as fast as possible when not measuring. - // adaptiveDelay has to be called anyway, as some polling functions are run within - adaptiveDelay(0); + // the interval is defined by a duration and/or distance from our last fix + return adaptiveDelay(MEASUREMENT_INTERVAL, location, millis() - cycleStart); } + // run as fast as possible when not measuring. + // smartDelay has to be called anyway, as some polling functions are run within + adaptiveDelay(0, location); }