From 11cd5a4849b057c98a229ebad66dbaa1eba34af4 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 28 Jun 2018 21:50:43 +1000 Subject: [PATCH] Improve handling of low battery and init error condition for GPS. --- tracker/software/source/drivers/ublox.c | 10 +- tracker/software/source/drivers/ublox.h | 8 +- .../software/source/protocols/packet/aprs.c | 7 +- tracker/software/source/threads/collector.c | 94 ++++++++++++------- tracker/software/source/threads/collector.h | 43 +++++++-- tracker/software/source/threads/rxtx/beacon.c | 24 +++-- 6 files changed, 130 insertions(+), 56 deletions(-) diff --git a/tracker/software/source/drivers/ublox.c b/tracker/software/source/drivers/ublox.c index 26653a10..b8e25c6a 100644 --- a/tracker/software/source/drivers/ublox.c +++ b/tracker/software/source/drivers/ublox.c @@ -14,7 +14,7 @@ bool gps_enabled = false; int8_t gps_model = GPS_MODEL_UNSET; -#if defined(UBLOX_USE_UART) +#if defined(UBLOX_UART_CONNECTED) // Serial driver configuration for GPS const SerialConfig gps_config = { @@ -49,10 +49,12 @@ bool gps_receive_byte(uint8_t *data) { I2C_read8(UBLOX_MAX_ADDRESS, 0xFF, data); return true; } - return false; -#else +#elif defined(UBLOX_USE_UART) return sdReadTimeout(&SD5, data, 1, TIME_IMMEDIATE); +#else + (void) data; #endif + return false; } /** @@ -580,7 +582,7 @@ bool GPS_Init() { palSetLineMode(LINE_GPS_EN, PAL_MODE_OUTPUT_PUSHPULL); // GPS off // Init UART - #if defined(UBLOX_USE_UART) + #if defined(UBLOX_UART_CONNECTED) palSetLineMode(LINE_GPS_RXD, PAL_MODE_ALTERNATE(11)); // UART RXD palSetLineMode(LINE_GPS_TXD, PAL_MODE_ALTERNATE(11)); // UART TXD TRACE_INFO("GPS > Init GPS UART"); diff --git a/tracker/software/source/drivers/ublox.h b/tracker/software/source/drivers/ublox.h index bc697ee1..77d53150 100644 --- a/tracker/software/source/drivers/ublox.h +++ b/tracker/software/source/drivers/ublox.h @@ -37,9 +37,13 @@ typedef enum { #define UBLOX_MAX_ADDRESS 0x42 -// You can either use I2C (TRUE) or UART (FALSE) +// You can either use I2C (TRUE) or UART if available (FALSE) #define UBLOX_USE_I2C FALSE -#define UBLOX_USE_UART TRUE +#define UBLOX_UART_CONNECTED + +#if UBLOX_USE_I2C == FALSE && !defined(UBLOX_UART_CONNECTED) +#warning "UBLOX has no I2C or UART communications enabled" +#endif #define isGPSLocked(pos) ((pos)->type == 3 && (pos)->num_svs >= 4 && (pos)->fixOK == true) diff --git a/tracker/software/source/protocols/packet/aprs.c b/tracker/software/source/protocols/packet/aprs.c index 28e0e7f3..0aa41b94 100644 --- a/tracker/software/source/protocols/packet/aprs.c +++ b/tracker/software/source/protocols/packet/aprs.c @@ -865,10 +865,13 @@ msg_t aprs_send_telemetry_response(aprs_identity_t *id, aprsd = *id->beacon; aprsd.run_once = true; aprsd.beacon.init_delay = 0; - thread_t * th = start_beacon_thread(&aprsd, "APRSD"); + thread_t *th = start_beacon_thread(&aprsd, "APRSD"); if(th == NULL) return MSG_ERROR; - return chThdWait(th); + if(chThdWait(th) == MSG_TIMEOUT) + /* GPS acquisition timeout in beacon (no fix or battery insufficient). */ + return MSG_ERROR; + return MSG_OK; /* //======================================================== // Encode and transmit telemetry config first diff --git a/tracker/software/source/threads/collector.c b/tracker/software/source/threads/collector.c index b3be0bca..27a5f001 100644 --- a/tracker/software/source/threads/collector.c +++ b/tracker/software/source/threads/collector.c @@ -72,7 +72,7 @@ static void getPositionFallback(dataPoint_t* tp, tp->gps_lat = 0; tp->gps_lon = 0; tp->gps_alt = 0; - if(isPositionValid(ltp)) { + if(isPositionFromSV(ltp)) { tp->gps_lat = ltp->gps_lat; tp->gps_lon = ltp->gps_lon; tp->gps_alt = ltp->gps_alt; @@ -388,7 +388,7 @@ void setSystemStatus(dataPoint_t* tp) { * */ THD_FUNCTION(collectorThread, arg) { - (void)arg; + thread_t *caller = (thread_t *)arg; uint32_t id = 0; @@ -437,42 +437,38 @@ THD_FUNCTION(collectorThread, arg) { } else { TRACE_INFO("COLL > No data point found in flash memory"); /* State indicates that no valid stored position is available. */ + lastDataPoint->gps_lat = 0; + lastDataPoint->gps_lon = 0; + lastDataPoint->gps_alt = 0; + lastDataPoint->gps_ttff = 0; + lastDataPoint->gps_pdop = 0; + lastDataPoint->gps_sats = 0; lastDataPoint->gps_state = GPS_OFF; + + // Measure telemetry + measureVoltage(lastDataPoint); + getSensors(lastDataPoint); + getGPIO(lastDataPoint); + setSystemStatus(lastDataPoint); + + // Write data point to Flash memory + flash_writeLogDataPoint(lastDataPoint); } - - // Measure telemetry - measureVoltage(lastDataPoint); - getSensors(lastDataPoint); - getGPIO(lastDataPoint); - setSystemStatus(lastDataPoint); - - // Write data point to Flash memory - flash_writeLogDataPoint(lastDataPoint); - - sysinterval_t gps_wait_time; - + /* Now check if the controller has been reset (RTC not set). */ getTime(&time); - if(time.year == RTC_BASE_YEAR) { - /* - * The RTC is not set. - * Enable the GPS and attempt a lock which results in setting the RTC. - */ - TRACE_INFO("COLL > Acquire time using GPS"); - if(aquirePosition(newDataPoint, lastDataPoint, gps_wait_time - TIME_S2I(3))) { - /* Acquisition succeeded. */ - TRACE_INFO("COLL > Time update acquired from GPS"); - /* Update with freshly acquired data. */ - lastDataPoint = newDataPoint; - GPS_Deinit(); - } else { - /* Time is stale record. */ - TRACE_INFO("COLL > Time update not acquired from GPS"); - } - } + if(time.year == RTC_BASE_YEAR) + /* Let initializer know this is a cold start (power loss). */ + (void)chMsgSend(caller, MSG_RESET); + else + (void)chMsgSend(caller, MSG_OK); + /* + * Done with initialization now. + * lastDataPoint becomes the first history entry for the loop. + */ while(true) { /* Primary loop. */ /* Wait for a request from a client. */ - thread_t *caller = chMsgWait(); + caller = chMsgWait(); /* Fetch the message. */ bcn_app_conf_t *config; config = (bcn_app_conf_t *)chMsgGet(caller); @@ -488,6 +484,25 @@ THD_FUNCTION(collectorThread, arg) { getGPIO(tp); setSystemStatus(tp); + getTime(&time); + if(time.year == RTC_BASE_YEAR) { + /* + * The RTC is not set. + * Enable the GPS and attempt a lock which results in setting the RTC. + */ + TRACE_INFO("COLL > Acquire time using GPS"); + if(aquirePosition(newDataPoint, lastDataPoint, TIME_S2I(600))) { + /* Acquisition succeeded. */ + TRACE_INFO("COLL > Time update acquired from GPS"); + /* Update with freshly acquired data. */ + lastDataPoint = newDataPoint; + GPS_Deinit(); + } else { + /* Time is stale record. */ + TRACE_INFO("COLL > Time update not acquired from GPS"); + } + } + if(config->beacon.fixed) { /* * Use fixed position data. @@ -505,12 +520,14 @@ THD_FUNCTION(collectorThread, arg) { getTime(&time); tp->gps_time = date2UnixTimestamp(&time); } else { + /* * Try GPS lock to get data. * If lock not attained fallback data is set. */ TRACE_INFO("COLL > Acquire position using GPS"); // Determine timeout waiting for lock. + sysinterval_t gps_wait_time; if(config->beacon.gps_wait > TIME_S2I(63)) // Minimum 1M + 3S gps_wait_time = config->beacon.gps_wait; else @@ -566,14 +583,23 @@ void init_data_collector() { thread_t *th = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(10*1024), "COL", LOWPRIO, - collectorThread, NULL); + collectorThread, chThdGetSelfX()); collector_thd = th; if(!th) { // Print startup error, do not start watchdog for this thread TRACE_ERROR("COLL > Could not start" " thread (not enough memory available)"); } else { - chThdSleep(TIME_MS2I(300)); // Wait a little bit until data collector has initialized first dataset + /* Wait for collector to start. */ + thread_t *tp = chMsgWait(); + msg_t msg = chMsgGet(tp); + if(msg == MSG_RESET) { + TRACE_INFO("COLL > Executed cold start"); + } + else { + TRACE_INFO("COLL > Executed warm start"); + } + chMsgRelease(tp, MSG_OK); } } } diff --git a/tracker/software/source/threads/collector.h b/tracker/software/source/threads/collector.h index fd3f8396..8b815c07 100644 --- a/tracker/software/source/threads/collector.h +++ b/tracker/software/source/threads/collector.h @@ -135,15 +135,46 @@ void init_data_collector(void); * @param[in] pointer to data point * * @returns result of check - * @retval true if position data is valid - * @retval false if position not valid + * @retval true if position data is from satellite or fixed. + * @retval false if position not valid. * * @api */ -#define isPositionValid(dp) (dp->gps_state == GPS_LOCKED1 \ - || dp->gps_state == GPS_LOCKED2 \ - || dp->gps_state == GPS_FIXED \ - || dp->gps_state == GPS_LOG) +#define isPositionValid(dp) (dp->gps_state == GPS_LOCKED1 \ + || dp->gps_state == GPS_LOCKED2 \ + || dp->gps_state == GPS_FIXED \ + || dp->gps_state == GPS_LOG) + +/** + * @brief Is position from a satellite. + * @notes This is an alias for hasGPSacquiredLock + * + * @param[in] pointer to data point + * + * @returns result of check + * @retval true if position data is from satellite + * @retval false if position not satellite + * + * @api + */ +#define isPositionFromSV(dp) hasGPSacquiredLock(dp) + +/** + * @brief Is GPS able to operate on battery. + * + * @param[in] pointer to data point + * + * @returns result of check + * @retval true if battery operable + * @retval false if not battery operable + * + * @api + */ +#define isGPSbatteryOperable(dp) (!(dp->gps_state == GPS_LOWBATT1 \ + || dp->gps_state == GPS_LOWBATT2 \ + || dp->gps_state == GPS_FIXED \ + || dp->gps_state == GPS_ERROR \ + || dp->gps_state == GPS_OFF)) #endif /* __COLLECTOR_H__ */ diff --git a/tracker/software/source/threads/rxtx/beacon.c b/tracker/software/source/threads/rxtx/beacon.c index df20b808..c23bf3c0 100644 --- a/tracker/software/source/threads/rxtx/beacon.c +++ b/tracker/software/source/threads/rxtx/beacon.c @@ -38,21 +38,29 @@ THD_FUNCTION(bcnThread, arg) { char code_s[100]; pktDisplayFrequencyCode(conf->radio_conf.freq, code_s, sizeof(code_s)); - TRACE_INFO("POS > Do module BEACON cycle for %s on %s", - conf->call, code_s); + TRACE_INFO("POS > Do module BEACON cycle for %s on %s%s", + conf->call, code_s, conf->run_once ? " (?aprsp response)" : ""); extern thread_t *collector_thd; /* * Pass pointer to beacon config to the collector thread. */ dataPoint_t *dataPoint = (dataPoint_t *)chMsgSend(collector_thd, (msg_t)conf); + /* Continue here when collector responds. */ if(!p_sleep(&conf->beacon.sleep_conf)) { - if(!isPositionValid(dataPoint) || dataPoint == NULL) { - TRACE_INFO("BCN > Waiting for position data for" - " %s (GPS state=%d)", conf->call, dataPoint->gps_state); - chThdSleep(TIME_S2I(60)); - continue; + TRACE_INFO("BCN > Waiting for position data for" + " %s (GPS state=%d)", conf->call, dataPoint->gps_state); + if(conf->run_once) + /* If this is run once don't retry. */ + chThdExit(MSG_TIMEOUT); + if(isGPSbatteryOperable(dataPoint)) { + /* If the battery is good retry quickly. + * TODO: Rework and involve the p_sleep setting? */ + chThdSleep(TIME_S2I(60)); + continue; + } + /* Else battery weak so beacon fallback data (TX may fail). */ } // Telemetry encoding parameter transmissions @@ -150,7 +158,7 @@ THD_FUNCTION(bcnThread, arg) { } } -/* +/** * */ thread_t * start_beacon_thread(bcn_app_conf_t *conf, const char *name) {