112 lines
3.1 KiB
C++
112 lines
3.1 KiB
C++
#include <TinyGPS.h>
|
|
|
|
#include "gps.h"
|
|
#include "settings.h"
|
|
#include "power.h"
|
|
#include "storage.h"
|
|
|
|
|
|
SoftwareSerial gps_begin() {
|
|
// FUTURE: If this doesn't work as expected, we may want to find a more reliable SoftwareSerial library
|
|
SoftwareSerial serial_gps(PIN_GPS_RX, PIN_GPS_TX);
|
|
// Initialise the software-based serial connection to the GPS device
|
|
serial_gps.begin(BAUD_GPS);
|
|
return serial_gps;
|
|
}
|
|
|
|
GPSLocation gps_fetch() {
|
|
// The serial connection to the GPS module
|
|
SoftwareSerial serial_gps = gps_begin();
|
|
// The GPS message decoder
|
|
TinyGPS gps;
|
|
// The struct that will hold the result
|
|
GPSLocation result;
|
|
|
|
Serial.print(F("[gps] Working "));
|
|
uint32_t start = millis(), ms_last_update = millis();
|
|
uint8_t ticks = 0;
|
|
unsigned long fix_age = TinyGPS::GPS_INVALID_AGE;
|
|
unsigned long chars;
|
|
unsigned short sentences, failed_checksum;
|
|
|
|
|
|
|
|
// We WILL discover our location - if it's the last thing we do!
|
|
while(true) {
|
|
gps.stats(&chars, &sentences, &failed_checksum);
|
|
|
|
if(millis() - start > 5000 && chars < 10) {
|
|
Serial.println(F("\n[error/gps] Init failed"));
|
|
while(true) { delay(1); }
|
|
}
|
|
|
|
// Make sure there's something to read
|
|
if(serial_gps.available() <= 0)
|
|
continue;
|
|
|
|
// If it failed, go around again
|
|
if(!gps.encode(serial_gps.read()))
|
|
continue;
|
|
|
|
gps.f_get_position(&(result.lat), &(result.lng), &fix_age);
|
|
|
|
// If we haven't acquired a lock yet, go around again
|
|
if(fix_age == TinyGPS::GPS_INVALID_AGE) {
|
|
// NOTE: It can take a rather long time to get a lock. Just wait patiently :-)
|
|
if(millis() - ms_last_update > 500) {
|
|
ticks++;
|
|
Serial.print('.');
|
|
if(ticks > 80) {
|
|
Serial.println();
|
|
ticks = 0;
|
|
}
|
|
ms_last_update = millis();
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Hooray!
|
|
Serial.println(F("ok"));
|
|
|
|
// gps.f_get_position pushes the values into result directly
|
|
|
|
#ifdef GPS_DELTA_CHECK
|
|
float last_reading_lat = store_eeprom_float_retrieve(sizeof(uint32_t) * 2);
|
|
float last_reading_lng = store_eeprom_float_retrieve(sizeof(uint32_t) * 2 + sizeof(float));
|
|
// Serial.println(last_reading_lat);
|
|
// Serial.println(last_reading_lng);
|
|
// Serial.println(result.lat);
|
|
// Serial.println(result.lng);
|
|
if(abs(last_reading_lat - result.lat) < GPS_DELTA_MIN_LAT &&
|
|
abs(last_reading_lng - result.lng) < GPS_DELTA_MIN_LNG &&
|
|
last_reading_lat == last_reading_lat && // Ensure that the last readings aren't NaN
|
|
last_reading_lng == last_reading_lng) {
|
|
Serial.println(F("[gps] No movement detected"));
|
|
power_off();
|
|
}
|
|
|
|
// Save this location to EEPROM
|
|
store_eeprom_float_save(sizeof(uint32_t) * 2, result.lat);
|
|
store_eeprom_float_save(sizeof(uint32_t) * 2 + sizeof(float), result.lng);
|
|
#endif
|
|
|
|
// TODO: Don't send a message at night
|
|
#ifdef SD_DEBUG_ENABLED
|
|
int year;
|
|
byte month, day, hour, minute, second, _hundredths;
|
|
gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &_hundredths, &fix_age);
|
|
|
|
snprintf(result.time, 19, "%04d-%02d-%02d %02d:%02d:%02d",
|
|
year, month, day,
|
|
hour, minute, second
|
|
);
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
gps_end(serial_gps);
|
|
}
|
|
|
|
void gps_end(SoftwareSerial serial_gps) {
|
|
serial_gps.end();
|
|
}
|