kopia lustrzana https://github.com/bristol-seds/pico-tracker
253 wiersze
6.8 KiB
C
253 wiersze
6.8 KiB
C
/*
|
|
* Cron job for the system
|
|
* Copyright (C) 2015 Richard Meadows <richardeoin>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "samd20.h"
|
|
#include "cron.h"
|
|
#include "gps.h"
|
|
#include "ubx_messages.h"
|
|
#include "data.h"
|
|
#include "hw_config.h"
|
|
#include "watchdog.h"
|
|
#include "backlog.h"
|
|
#include "location.h"
|
|
|
|
/* Internal time representation */
|
|
struct tracker_time time = {0};
|
|
|
|
volatile uint32_t ticks = 0;
|
|
|
|
/* Indicates telemetry wakeup hysteresis. We wake up immediately */
|
|
uint8_t has_telemetry_woken_up = 0;
|
|
#define TELEMETRY_WAKEUP_TEST(d) (1)
|
|
|
|
/* Pointer to latest datapoint */
|
|
struct tracker_datapoint* dp;
|
|
|
|
/* Low Power Mode */
|
|
#define LOW_POWER(d) (d->solar < 0.2)
|
|
|
|
void rtty_telemetry(struct tracker_datapoint* dp);
|
|
void contestia_telemetry(struct tracker_datapoint* dp);
|
|
void aprs_telemetry(struct tracker_datapoint* dp);
|
|
void pips_telemetry(void);
|
|
|
|
/**
|
|
* For GPS time timeout
|
|
*/
|
|
uint32_t ticks_delta_start;
|
|
|
|
/**
|
|
* Number of days in month. This won't be used much but I guess I have
|
|
* to implement it. Sigh
|
|
*
|
|
* Assumes days and months start at 1 (ubx does do this, I checked)
|
|
*/
|
|
uint8_t days_in_month(struct tracker_time* t)
|
|
{
|
|
switch (t->month) {
|
|
case 1: return 31; /* Janua */
|
|
case 2:
|
|
return (t->year % 4) ?
|
|
((t->year % 100) ?
|
|
((t->year % 400) ? 29 /* div 400, leap */
|
|
: 28) /* div 100, not 400, common */
|
|
: 29) /* div 4, not 100, leap */
|
|
: 28; /* Not div 4, common */
|
|
case 3: return 31; /* March */
|
|
case 4: return 30; /* April */
|
|
case 5: return 31; /* May */
|
|
case 6: return 30; /* June */
|
|
case 7: return 31; /* July */
|
|
case 8: return 31; /* Augus */
|
|
case 9: return 30; /* Septe */
|
|
case 10: return 31; /* Octob */
|
|
case 11: return 30; /* Novem */
|
|
case 12: return 31; /* Decem */
|
|
default: return 31; /* It's probably 31 */
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the number of ticks the current cron job has been running for
|
|
*
|
|
* ticks = seconds. Can be used for timeouts etc.
|
|
*/
|
|
uint32_t cron_current_job_ticks(void)
|
|
{
|
|
return ticks;
|
|
}
|
|
|
|
/**
|
|
* Reads current time from the GPS
|
|
*/
|
|
void read_gps_time(void)
|
|
{
|
|
/* Record current ticks */
|
|
ticks_delta_start = cron_current_job_ticks();
|
|
|
|
/* GPS Time */
|
|
gps_update_time();
|
|
|
|
/* Sleep Wait. Timeout after 3 ticks */
|
|
while (gps_update_time_pending() &&
|
|
(cron_current_job_ticks() - ticks_delta_start) <= 3) {
|
|
|
|
idle(IDLE_WAIT_FOR_NEXT_TELEMETRY);
|
|
}
|
|
|
|
/* If no error and no timeout */
|
|
if ((gps_get_error_state() == GPS_NOERROR) &&
|
|
(cron_current_job_ticks() - ticks_delta_start) <= 3) {
|
|
|
|
/* Time */
|
|
struct ubx_nav_timeutc gt = gps_get_nav_timeutc();
|
|
time.year = gt.payload.year;
|
|
time.month = gt.payload.month;
|
|
time.day = gt.payload.day;
|
|
time.hour = gt.payload.hour;
|
|
time.minute = gt.payload.min;
|
|
time.second = gt.payload.sec;
|
|
time.valid = gt.payload.valid;
|
|
|
|
/* TODO calculate epoch time here */
|
|
|
|
/* Zero out ticks as we have just set the correct time */
|
|
ticks = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Pars of cron job that handles telemetry
|
|
*/
|
|
#define TELEM_TOM 30 /* Telemetry on the 30th second */
|
|
|
|
void cron_telemetry(struct tracker_time* t, struct tracker_datapoint* dp)
|
|
{
|
|
#ifdef TELEMETRY_USE_GEOFENCE
|
|
/* ---- Telemetry output ---- */
|
|
if (telemetry_location_tx_allow()) {
|
|
#endif
|
|
|
|
/* Contestia */
|
|
if (t->second == TELEM_TOM) {
|
|
contestia_telemetry(dp);
|
|
|
|
/* Pip */
|
|
} else if ((t->second % 1) == 0) {
|
|
pips_telemetry();
|
|
}
|
|
|
|
#ifdef TELEMETRY_USE_GEOFENCE
|
|
}
|
|
#endif
|
|
|
|
/* APRS */
|
|
#ifdef APRS_ENABLE
|
|
if ((t->minute % 2) == 0 && t->second == TELEM_TOM) {
|
|
aprs_telemetry(dp);
|
|
}
|
|
#endif
|
|
|
|
/* ---- Update telemetry geofence ---- */
|
|
if ((t->minute % 5 == 0) && (t->second == 0)) { /* Every 5 minutes */
|
|
|
|
if (gps_is_locked()) { /* Don't bother with no GPS */
|
|
|
|
telemetry_location_update(dp->longitude, dp->latitude);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Cron job for the system.
|
|
*
|
|
* Run at the top of the second but may take longer than a second
|
|
*/
|
|
void do_cron(void)
|
|
{
|
|
/* ---- Local representation of the time ---- */
|
|
while (ticks) {
|
|
/* Update time internally */
|
|
ticks--; time.epoch++; time.second++;
|
|
if (time.second >= 60) {
|
|
time.second = 0; time.minute++;
|
|
if (time.minute >= 60) {
|
|
time.minute = 0; time.hour++;
|
|
if (time.hour >= 24) {
|
|
time.hour = 0; time.day++;
|
|
if (time.day > days_in_month(&time)) {
|
|
time.day = 1; time.month++;
|
|
if (time.month > 12) {
|
|
time.month = 0; time.year++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ---- Data every 30 seconds ---- */
|
|
if (time.second == TELEM_TOM) {
|
|
dp = collect_data();
|
|
memcpy(&dp->time, &time, sizeof(struct tracker_time));
|
|
} else if (time.second == ((TELEM_TOM + 55)%60)) { /* 5 seconds for async things */
|
|
collect_data_async();
|
|
}
|
|
|
|
/* ---- Telemetry output ---- */
|
|
if (has_telemetry_woken_up > 0) {
|
|
cron_telemetry(&time, dp);
|
|
} else {
|
|
has_telemetry_woken_up = TELEMETRY_WAKEUP_TEST(dp) ? 0xF : 0;
|
|
}
|
|
|
|
/* ---- Record for backlog ---- */
|
|
if ((time.minute == 0) && (time.second == 0)) { /* Once per hour */
|
|
|
|
kick_the_watchdog();
|
|
|
|
if (gps_is_locked()) { /* Don't bother with no GPS */
|
|
record_backlog(dp);
|
|
}
|
|
}
|
|
|
|
/* Update internal time from GPS */
|
|
/* We do this just after midnight or if time is yet to set UTC exactly */
|
|
if (((time.hour == 0) && (time.minute == 0) && (time.second == 0)) ||
|
|
((time.second == 0) && !(time.valid & UBX_TIMEUTC_VALID_UTC))) {
|
|
|
|
kick_the_watchdog();
|
|
|
|
read_gps_time();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Called in an interrupt, increments internal time representation
|
|
*/
|
|
void cron_tick(void) {
|
|
ticks++;
|
|
}
|