kopia lustrzana https://github.com/bristol-seds/pico-tracker
Refactor. System now runs on a "cron" architecture that is aligned to UTC
rodzic
6e584b2ad3
commit
4dde7ed37c
|
@ -34,7 +34,7 @@
|
||||||
| --- | --- | --- | ---
|
| --- | --- | --- | ---
|
||||||
|TC0_IRQn|telemetry tick timer|0|latency critical for symbol timing. rate <= 1200Hz
|
|TC0_IRQn|telemetry tick timer|0|latency critical for symbol timing. rate <= 1200Hz
|
||||||
|[GPS_SERCOM]_IRQn|gps usart rx|1|latency not so critical. rate <= 960Hz
|
|[GPS_SERCOM]_IRQn|gps usart rx|1|latency not so critical. rate <= 960Hz
|
||||||
|EIC_IRQn|timepulse|1|latency not so critical. rate = 2
|
|EIC_IRQn|timepulse|1|latency not so critical. rate = 1
|
||||||
|TC2_IRQn|xosc measurement done|2|latency not critical
|
|TC2_IRQn|xosc measurement done|2|latency not critical
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CRON_H
|
||||||
|
#define CRON_H
|
||||||
|
|
||||||
|
typedef struct tracker_time {
|
||||||
|
uint64_t epoch;
|
||||||
|
uint16_t year;
|
||||||
|
uint8_t month, day, hour, minute, second;
|
||||||
|
uint8_t valid;
|
||||||
|
} tracker_time;
|
||||||
|
|
||||||
|
void do_cron(void);
|
||||||
|
void cron_tick(void);
|
||||||
|
void cron_init(void);
|
||||||
|
|
||||||
|
#endif /* CRON_H */
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Collects data from sensors etc into a struct
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DATA_H
|
||||||
|
#define DATA_H
|
||||||
|
|
||||||
|
#include "samd20.h"
|
||||||
|
#include "cron.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure for all the information in each datapoint.
|
||||||
|
*
|
||||||
|
* Size is approx 40 bytes
|
||||||
|
*/
|
||||||
|
typedef struct tracker_datapoint {
|
||||||
|
/* Time */
|
||||||
|
struct tracker_time time;
|
||||||
|
|
||||||
|
/* Position */
|
||||||
|
uint32_t latitude; /* 100 nanodeg */
|
||||||
|
uint32_t longitude; /* 100 nanodeg */
|
||||||
|
uint32_t altitude; /* mm */
|
||||||
|
uint8_t satillite_count; /* */
|
||||||
|
|
||||||
|
/* Sensors */
|
||||||
|
float battery; /* Volts */
|
||||||
|
float temperature; /* ºC */
|
||||||
|
uint32_t xosc_error; /* Hertz */
|
||||||
|
|
||||||
|
} tracker_datapoint;
|
||||||
|
|
||||||
|
|
||||||
|
void collect_data_async(void);
|
||||||
|
struct tracker_datapoint* collect_data(void);
|
||||||
|
void data_init(void);
|
||||||
|
|
||||||
|
#endif /* DATA_H */
|
|
@ -147,14 +147,12 @@
|
||||||
* Telemetry
|
* Telemetry
|
||||||
*/
|
*/
|
||||||
#define TELEMETRY_FREQUENCY 434600000
|
#define TELEMETRY_FREQUENCY 434600000
|
||||||
#define TELEMETRY_INTERVAL 30
|
|
||||||
#define TELEMETRY_POWER RF_POWER_8dBm
|
#define TELEMETRY_POWER RF_POWER_8dBm
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* APRS
|
* APRS
|
||||||
*/
|
*/
|
||||||
#define APRS_ENABLE 1
|
#define APRS_ENABLE 1
|
||||||
#define APRS_INTERVAL 180
|
|
||||||
#define APRS_POWER RF_POWER_14dBm
|
#define APRS_POWER RF_POWER_14dBm
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -186,4 +184,5 @@
|
||||||
|
|
||||||
#define TC2_INT_PRIO 2 /* XOSC Measure Timer */
|
#define TC2_INT_PRIO 2 /* XOSC Measure Timer */
|
||||||
|
|
||||||
|
|
||||||
#endif /* HW_CONFIG_H */
|
#endif /* HW_CONFIG_H */
|
||||||
|
|
|
@ -26,13 +26,11 @@
|
||||||
#define PIPS_H
|
#define PIPS_H
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 10ms pips, once per second
|
* 50ms pips, once per second
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PIPS_RATE 1
|
#define PIPS_RATE 1
|
||||||
#define PIPS_LENGTH_MS 50
|
#define PIPS_LENGTH_MS 50
|
||||||
|
#define PIPS_FREQUENCY (1000 / PIPS_LENGTH_MS)
|
||||||
#define PIPS_ON_FREQUENCY (1000 / PIPS_LENGTH_MS)
|
|
||||||
#define PIPS_OFF_FREQUENCY PIPS_RATE
|
|
||||||
|
|
||||||
#endif /* PIPS_H */
|
#endif /* PIPS_H */
|
||||||
|
|
|
@ -33,7 +33,7 @@ enum rf_tests {
|
||||||
RF_TEST_TELEMETRY_TONE,
|
RF_TEST_TELEMETRY_TONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RF_TEST RF_TEST_APRS
|
#define RF_TEST RF_TEST_NONE
|
||||||
|
|
||||||
#include "samd20.h"
|
#include "samd20.h"
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,6 @@ int telemetry_active(void);
|
||||||
int telemetry_start(enum telemetry_t type, int32_t length);
|
int telemetry_start(enum telemetry_t type, int32_t length);
|
||||||
int telemetry_start_rsid(rsid_code_t rsid);
|
int telemetry_start_rsid(rsid_code_t rsid);
|
||||||
void telemetry_aprs_set_frequency(int32_t frequency);
|
void telemetry_aprs_set_frequency(int32_t frequency);
|
||||||
void telemetry_request_stop(void);
|
|
||||||
float telemetry_si_temperature(void);
|
float telemetry_si_temperature(void);
|
||||||
|
|
||||||
float timer0_tick_init(float frequency);
|
float timer0_tick_init(float frequency);
|
||||||
|
|
|
@ -285,4 +285,14 @@ __PACKED__ struct ubx_nav_status {
|
||||||
} payload;
|
} payload;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UBX TIMEUTC valid flags
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
UBX_TIMEUTC_VALID_TOW = (1 << 0),
|
||||||
|
UBX_TIMEUTC_VALID_WKN = (1 << 1),
|
||||||
|
UBX_TIMEUTC_VALID_UTC = (1 << 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif /* UBX_MESSAGES_H */
|
#endif /* UBX_MESSAGES_H */
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
/* Internal time representation */
|
||||||
|
struct tracker_time time;
|
||||||
|
|
||||||
|
/* Pointer to latest datapoint */
|
||||||
|
struct tracker_datapoint* dp;
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads current time from the GPS
|
||||||
|
*/
|
||||||
|
void read_gps_time(void)
|
||||||
|
{
|
||||||
|
/* GPS Time */
|
||||||
|
gps_update_time();
|
||||||
|
|
||||||
|
/* Sleep Wait */
|
||||||
|
while (gps_update_time_pending()) {
|
||||||
|
system_sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 ---- */
|
||||||
|
struct tracker_time t;
|
||||||
|
memcpy(&t, &time, sizeof(struct tracker_time));
|
||||||
|
|
||||||
|
/* ---- Data every 30 seconds ---- */
|
||||||
|
if ((time.second % 30) == 0) {
|
||||||
|
dp = collect_data();
|
||||||
|
memcpy(&dp->time, &t, sizeof(struct tracker_time));
|
||||||
|
} else if ((time.second % 30) == 20) {
|
||||||
|
collect_data_async();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ---- Telemetry output ---- */
|
||||||
|
/* RTTY */
|
||||||
|
if (time.second == 0) {
|
||||||
|
rtty_telemetry(dp);
|
||||||
|
|
||||||
|
/* Contestia */
|
||||||
|
} else if (time.second == 30) {
|
||||||
|
contestia_telemetry(dp);
|
||||||
|
|
||||||
|
/* APRS */ /* LIMIT CONTESTIA PACKET LENGTH */
|
||||||
|
#ifdef APRS_ENABLE
|
||||||
|
} else if ((time.minute % 2) == 0 && time.second == 55) {
|
||||||
|
aprs_telemetry(dp);
|
||||||
|
#endif
|
||||||
|
/* Pips */
|
||||||
|
} else if ((time.second % 1) == 0) {
|
||||||
|
pips_telemetry();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called in an interrupt, increments internal time representation
|
||||||
|
*/
|
||||||
|
void cron_tick(void) {
|
||||||
|
|
||||||
|
/* Update time internally */
|
||||||
|
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 > 23) {
|
||||||
|
time.hour = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 == 5)) ||
|
||||||
|
((time.second == 5) && !(time.valid & UBX_TIMEUTC_VALID_UTC))) {
|
||||||
|
|
||||||
|
/* Be careful not a call this while the collect_data function is running */
|
||||||
|
read_gps_time();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cron_init(void)
|
||||||
|
{
|
||||||
|
memset(&time, 0, sizeof(struct tracker_time));
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Collects data from sensors etc into a struct
|
||||||
|
* 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 "data.h"
|
||||||
|
#include "xosc.h"
|
||||||
|
#include "hw_config.h"
|
||||||
|
#include "analogue.h"
|
||||||
|
#include "gps.h"
|
||||||
|
#include "ubx_messages.h"
|
||||||
|
#include "telemetry.h"
|
||||||
|
|
||||||
|
struct tracker_datapoint datapoint;
|
||||||
|
|
||||||
|
void xosc_measure_callback(uint32_t result)
|
||||||
|
{
|
||||||
|
datapoint.xosc_error = result - XOSC_FREQUENCY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect data asynchronously
|
||||||
|
*/
|
||||||
|
void collect_data_async(void)
|
||||||
|
{
|
||||||
|
/* Measure XOSC against gps timepulse */
|
||||||
|
measure_xosc(XOSC_MEASURE_TIMEPULSE, xosc_measure_callback);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Collect Data synchronously and return datapoint
|
||||||
|
*/
|
||||||
|
struct tracker_datapoint* collect_data(void)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* ---- Analogue ----
|
||||||
|
*/
|
||||||
|
datapoint.battery = get_battery();
|
||||||
|
datapoint.temperature = telemetry_si_temperature();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ---- GPS ----
|
||||||
|
*/
|
||||||
|
gps_update_position();
|
||||||
|
|
||||||
|
/* Wait for the gps update */
|
||||||
|
while (gps_update_position_pending()) {
|
||||||
|
system_sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GPS Status */
|
||||||
|
struct ubx_nav_sol sol = gps_get_nav_sol();
|
||||||
|
datapoint.satillite_count = sol.payload.numSV;
|
||||||
|
|
||||||
|
/* GPS Position */
|
||||||
|
if (gps_is_locked()) {
|
||||||
|
struct ubx_nav_posllh pos = gps_get_nav_posllh();
|
||||||
|
|
||||||
|
datapoint.latitude = pos.payload.lat;
|
||||||
|
datapoint.longitude = pos.payload.lon;
|
||||||
|
datapoint.altitude = pos.payload.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GPS Powersave */
|
||||||
|
gps_set_powersave_auto();
|
||||||
|
|
||||||
|
return &datapoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void data_init(void)
|
||||||
|
{
|
||||||
|
memset(&datapoint, 0, sizeof(struct tracker_datapoint));
|
||||||
|
}
|
|
@ -33,6 +33,8 @@
|
||||||
#include "watchdog.h"
|
#include "watchdog.h"
|
||||||
#include "xosc.h"
|
#include "xosc.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
#include "cron.h"
|
||||||
|
#include "data.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises the status LED. SHOULD TURN ON THE LED
|
* Initialises the status LED. SHOULD TURN ON THE LED
|
||||||
|
@ -53,7 +55,7 @@ void powermananger_init(void)
|
||||||
{
|
{
|
||||||
system_apb_clock_clear_mask(SYSTEM_CLOCK_APB_APBA,
|
system_apb_clock_clear_mask(SYSTEM_CLOCK_APB_APBA,
|
||||||
// PM_APBAMASK_EIC | /* EIC is used now */
|
// PM_APBAMASK_EIC | /* EIC is used now */
|
||||||
// PM_APBAMASK_RTC | /* RTC is used now */
|
PM_APBAMASK_RTC |
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +106,7 @@ void init(timepulse_callback_t callback)
|
||||||
system_set_sleepmode(SYSTEM_SLEEPMODE_IDLE_2); /* Disable CPU, AHB and APB */
|
system_set_sleepmode(SYSTEM_SLEEPMODE_IDLE_2); /* Disable CPU, AHB and APB */
|
||||||
|
|
||||||
/* Configure the Power Manager */
|
/* Configure the Power Manager */
|
||||||
//powermananger_init();
|
powermananger_init();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* System initialisation
|
* System initialisation
|
||||||
|
@ -123,4 +125,8 @@ void init(timepulse_callback_t callback)
|
||||||
|
|
||||||
/* Initialise Si4060 interface */
|
/* Initialise Si4060 interface */
|
||||||
si_trx_init();
|
si_trx_init();
|
||||||
|
|
||||||
|
/* Data and Cron structures */
|
||||||
|
data_init();
|
||||||
|
cron_init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,145 +27,110 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "samd20.h"
|
#include "samd20.h"
|
||||||
#include "semihosting.h"
|
|
||||||
#include "hw_config.h"
|
#include "hw_config.h"
|
||||||
#include "system/system.h"
|
|
||||||
#include "sercom/usart.h"
|
|
||||||
#include "system/port.h"
|
|
||||||
#include "system/extint.h"
|
|
||||||
#include "tc/tc_driver.h"
|
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "gps.h"
|
#include "gps.h"
|
||||||
#include "mfsk.h"
|
#include "mfsk.h"
|
||||||
#include "ubx_messages.h"
|
|
||||||
#include "watchdog.h"
|
#include "watchdog.h"
|
||||||
#include "xosc.h"
|
|
||||||
#include "telemetry.h"
|
#include "telemetry.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "contestia.h"
|
#include "contestia.h"
|
||||||
#include "rsid.h"
|
|
||||||
#include "aprs.h"
|
#include "aprs.h"
|
||||||
#include "location.h"
|
#include "location.h"
|
||||||
#include "si_trx.h"
|
|
||||||
#include "si_trx_defs.h"
|
|
||||||
#include "analogue.h"
|
|
||||||
#include "spi_bitbang.h"
|
|
||||||
#include "system/interrupt.h"
|
|
||||||
#include "rf_tests.h"
|
#include "rf_tests.h"
|
||||||
|
#include "data.h"
|
||||||
|
|
||||||
#define CALLSIGN "UBSEDSx"
|
#define CALLSIGN "UBSEDSx"
|
||||||
|
|
||||||
void xosc_measure_callback(uint32_t result);
|
|
||||||
void timepulse_callback(uint32_t sequence);
|
|
||||||
|
|
||||||
int32_t _xosc_error = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Telemetry String
|
* Formats a UKHAS telemetry string for the given datapoint
|
||||||
* =============================================================================
|
*
|
||||||
|
* The telemetry string starts with the specified number of dollar signs
|
||||||
*/
|
*/
|
||||||
void output_telemetry_string(enum telemetry_t type)
|
uint16_t format_telemetry_string(char* string, struct tracker_datapoint* dp,
|
||||||
|
uint8_t dollars)
|
||||||
{
|
{
|
||||||
double lat_fmt = 0.0;
|
double lat_fmt = 0.0;
|
||||||
double lon_fmt = 0.0;
|
double lon_fmt = 0.0;
|
||||||
uint32_t altitude = 0;
|
uint32_t altitude = 0;
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
uint8_t dollars = 2;
|
|
||||||
|
|
||||||
/**
|
lat_fmt = (double)dp->latitude / 10000000.0; /* degrees */
|
||||||
* Collect Data
|
lon_fmt = (double)dp->longitude / 10000000.0; /* degrees */
|
||||||
* ---------------------------------------------------------------------------
|
altitude = dp->altitude / 1000; /* meters */
|
||||||
*/
|
|
||||||
|
|
||||||
/* Analogue */
|
|
||||||
float battery = get_battery();
|
|
||||||
float temperature = telemetry_si_temperature();
|
|
||||||
|
|
||||||
/* GPS Time */
|
|
||||||
gps_update_time();
|
|
||||||
|
|
||||||
/* Sleep Wait */
|
|
||||||
while (gps_update_time_pending()) {
|
|
||||||
system_sleep();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Time */
|
|
||||||
struct ubx_nav_timeutc time = gps_get_nav_timeutc();
|
|
||||||
uint8_t hours = time.payload.hour;
|
|
||||||
uint8_t minutes = time.payload.min;
|
|
||||||
uint8_t seconds = time.payload.sec;
|
|
||||||
|
|
||||||
/* Request updates from the gps */
|
|
||||||
gps_update_position();
|
|
||||||
if (gps_is_locked()) {
|
|
||||||
led_on();
|
|
||||||
} else {
|
|
||||||
led_off();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for the gps update */
|
|
||||||
while (gps_update_position_pending()) {
|
|
||||||
system_sleep();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gps_is_locked()) {
|
|
||||||
led_off();
|
|
||||||
} else {
|
|
||||||
led_on();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* GPS Status */
|
|
||||||
struct ubx_nav_sol sol = gps_get_nav_sol();
|
|
||||||
uint8_t satillite_count = sol.payload.numSV;
|
|
||||||
|
|
||||||
/* GPS Position */
|
|
||||||
if (gps_is_locked()) {
|
|
||||||
struct ubx_nav_posllh pos = gps_get_nav_posllh();
|
|
||||||
lat_fmt = (double)pos.payload.lat / 10000000.0;
|
|
||||||
lon_fmt = (double)pos.payload.lon / 10000000.0;
|
|
||||||
altitude = pos.payload.height / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* GPS Powersave */
|
|
||||||
gps_set_powersave_auto();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (type == TELEMETRY_RTTY) {
|
|
||||||
dollars = 5; // Extra dollars for RTTY
|
|
||||||
}
|
|
||||||
|
|
||||||
/* sprintf - preamble */
|
/* sprintf - preamble */
|
||||||
memset(telemetry_string, '$', dollars);
|
memset(string, '$', dollars);
|
||||||
len = dollars;
|
len = dollars;
|
||||||
|
|
||||||
/* sprintf - full string */
|
/* sprintf - full string */
|
||||||
len += sprintf(telemetry_string + len,
|
len += sprintf(telemetry_string + len,
|
||||||
"%s,%02u:%02u:%02u,%02.5f,%03.5f,%ld,%u,%.2f,%.1f,%ld",
|
"%s,%02u:%02u:%02u,%02.5f,%03.5f,%ld,%u,%.2f,%.1f,%ld",
|
||||||
CALLSIGN, hours, minutes, seconds, lat_fmt, lon_fmt,
|
CALLSIGN,
|
||||||
altitude, satillite_count, battery, temperature, _xosc_error);
|
dp->time.hour, dp->time.minute, dp->time.second,
|
||||||
|
lat_fmt, lon_fmt, altitude, dp->satillite_count,
|
||||||
if (type == TELEMETRY_CONTESTIA) { contestiaize(telemetry_string + dollars); }
|
dp->battery, dp->temperature, dp->xosc_error);
|
||||||
|
|
||||||
/* sprintf - checksum. don't include dollars */
|
/* sprintf - checksum. don't include dollars */
|
||||||
len += sprintf(telemetry_string + len,
|
len += sprintf(telemetry_string + len,
|
||||||
"*%04X\r",
|
"*%04X\r",
|
||||||
crc_checksum(telemetry_string + dollars));
|
crc_checksum(telemetry_string + dollars));
|
||||||
|
|
||||||
|
/* Length should be no more than 100 characters!! */
|
||||||
|
if (len <= 100) {
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Okay, let's use a shorter backup format */
|
||||||
|
len = dollars;
|
||||||
|
|
||||||
|
/* sprintf - short format */
|
||||||
|
len += sprintf(telemetry_string + len,
|
||||||
|
"%s,%02u:%02u:%02u,%02.5f,%03.5f,%ld",
|
||||||
|
CALLSIGN,
|
||||||
|
dp->time.hour, dp->time.minute, dp->time.second,
|
||||||
|
lat_fmt, lon_fmt, altitude);
|
||||||
|
|
||||||
|
/* sprintf - checksum. don't include dollars */
|
||||||
|
len += sprintf(telemetry_string + len,
|
||||||
|
"*%04X\r",
|
||||||
|
crc_checksum(telemetry_string + dollars));
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starting up the radio blocks on high-prio interrupt for ~100ms: todo fixme
|
* RTTY telemetry. Uses 5 dollar symbols
|
||||||
*/
|
*/
|
||||||
|
#define RTTY_DOLLARS 5
|
||||||
|
void rtty_telemetry(struct tracker_datapoint* dp) {
|
||||||
|
uint16_t len;
|
||||||
|
|
||||||
|
len = format_telemetry_string(telemetry_string, dp, RTTY_DOLLARS);
|
||||||
|
|
||||||
|
/* Main telemetry */
|
||||||
|
telemetry_start(TELEMETRY_RTTY, len);
|
||||||
|
|
||||||
|
/* Sleep Wait for main telemetry */
|
||||||
|
while (telemetry_active()) {
|
||||||
|
system_sleep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Contestia telemetry. Uses 2 dollar symbols
|
||||||
|
*/
|
||||||
|
#define CONTESTIA_DOLLARS 2
|
||||||
|
void contestia_telemetry(struct tracker_datapoint* dp) {
|
||||||
|
uint16_t len;
|
||||||
|
|
||||||
|
len = format_telemetry_string(telemetry_string, dp, CONTESTIA_DOLLARS);
|
||||||
|
|
||||||
|
/* Reduce character set */
|
||||||
|
contestiaize(telemetry_string + CONTESTIA_DOLLARS);
|
||||||
|
|
||||||
/* RSID */
|
/* RSID */
|
||||||
/* start - SI NOW BELONGS TO TELEMETRY, WE CANNOT ACCESS */
|
|
||||||
if (type == TELEMETRY_CONTESTIA) {
|
|
||||||
telemetry_start_rsid(RSID_CONTESTIA_32_1000);
|
telemetry_start_rsid(RSID_CONTESTIA_32_1000);
|
||||||
}
|
|
||||||
|
|
||||||
/* Sleep Wait for RSID */
|
/* Sleep Wait for RSID */
|
||||||
while (telemetry_active()) {
|
while (telemetry_active()) {
|
||||||
|
@ -173,22 +138,23 @@ void output_telemetry_string(enum telemetry_t type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Main telemetry */
|
/* Main telemetry */
|
||||||
telemetry_start(type, len);
|
telemetry_start(TELEMETRY_CONTESTIA, len);
|
||||||
|
|
||||||
/* Sleep Wait for main telemetry */
|
/* Sleep Wait for main telemetry */
|
||||||
while (telemetry_active()) {
|
while (telemetry_active()) {
|
||||||
system_sleep();
|
system_sleep();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
void aprs_telemetry(void) {
|
* APRS telemetry if required
|
||||||
|
*/
|
||||||
|
void aprs_telemetry(struct tracker_datapoint* dp) {
|
||||||
|
|
||||||
if (!gps_is_locked()) return; /* Don't bother with no GPS */
|
if (!gps_is_locked()) return; /* Don't bother with no GPS */
|
||||||
|
|
||||||
struct ubx_nav_posllh pos = gps_get_nav_posllh();
|
float lat = (float)dp->latitude / 10000000.0; /* degrees */
|
||||||
float lat = (float)pos.payload.lat / 10000000.0; // This division is from the gps reciver, not for geofence
|
float lon = (float)dp->longitude / 10000000.0; /* degrees */
|
||||||
float lon = (float)pos.payload.lon / 10000000.0;
|
uint32_t altitude = dp->altitude / 1000; /* meters */
|
||||||
uint32_t altitude = pos.payload.height / 1000;
|
|
||||||
|
|
||||||
/* Update location */
|
/* Update location */
|
||||||
aprs_location_update(lon, lat, altitude);
|
aprs_location_update(lon, lat, altitude);
|
||||||
|
@ -209,37 +175,34 @@ void aprs_telemetry(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Pips telemetry
|
||||||
void xosc_measure_callback(uint32_t result)
|
*/
|
||||||
|
void pips_telemetry(void)
|
||||||
{
|
{
|
||||||
_xosc_error = result - XOSC_FREQUENCY;
|
/* Pips */
|
||||||
|
telemetry_start(TELEMETRY_PIPS, 0xFFFF);
|
||||||
|
|
||||||
|
while (telemetry_active()) {
|
||||||
|
system_sleep();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t telemetry_interval_count = TELEMETRY_INTERVAL;
|
uint8_t tick_flag = 0;
|
||||||
uint32_t aprs_interval_count = APRS_INTERVAL;
|
|
||||||
uint8_t telemetry_trigger_flag = 0;
|
|
||||||
uint8_t aprs_trigger_flag = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the timer at 1Hz
|
* Called at 1Hz by the GPS
|
||||||
*/
|
*/
|
||||||
void timepulse_callback(uint32_t sequence)
|
void gps_tick(uint32_t sequence)
|
||||||
{
|
{
|
||||||
telemetry_interval_count++;
|
/* Sequence not used */
|
||||||
aprs_interval_count++;
|
(void)sequence;
|
||||||
|
|
||||||
/* Runs at the rate of telemetry packets */
|
/* Update internal time representation */
|
||||||
if (telemetry_interval_count >= TELEMETRY_INTERVAL) {
|
cron_tick();
|
||||||
telemetry_interval_count = 0;
|
|
||||||
telemetry_trigger_flag = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Runs at the rate of aprs packets */
|
/* Raise the tick flag */
|
||||||
if (aprs_interval_count >= APRS_INTERVAL) {
|
tick_flag = 1;
|
||||||
aprs_interval_count = 0;
|
|
||||||
aprs_trigger_flag = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -248,9 +211,8 @@ void timepulse_callback(uint32_t sequence)
|
||||||
*/
|
*/
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
uint32_t telemetry_alternate = 0;
|
/* Init */
|
||||||
|
init(gps_tick);
|
||||||
init(timepulse_callback);
|
|
||||||
|
|
||||||
/* Maybe do some rf tests */
|
/* Maybe do some rf tests */
|
||||||
rf_tests();
|
rf_tests();
|
||||||
|
@ -259,35 +221,12 @@ int main(void)
|
||||||
led_off();
|
led_off();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
/* Send a packet */
|
/* Run cron job */
|
||||||
output_telemetry_string((telemetry_alternate++ & 1) ?
|
if (tick_flag) {
|
||||||
TELEMETRY_CONTESTIA :
|
tick_flag = 0; do_cron();
|
||||||
TELEMETRY_RTTY);
|
|
||||||
|
|
||||||
/* Maybe aprs? */
|
|
||||||
#if APRS_ENABLE
|
|
||||||
if (aprs_trigger_flag) {
|
|
||||||
aprs_telemetry();
|
|
||||||
}
|
}
|
||||||
aprs_trigger_flag = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Pips */
|
/* Idle */
|
||||||
telemetry_start(TELEMETRY_PIPS, 0xFFFF);
|
|
||||||
|
|
||||||
/* Measure XOSC against gps timepulse */
|
|
||||||
measure_xosc(XOSC_MEASURE_TIMEPULSE, xosc_measure_callback);
|
|
||||||
|
|
||||||
/* Sleep wait for next telemetry */
|
|
||||||
while (telemetry_trigger_flag == 0) {
|
|
||||||
system_sleep();
|
|
||||||
}
|
|
||||||
telemetry_trigger_flag = 0;
|
|
||||||
|
|
||||||
/* End pips */
|
|
||||||
telemetry_request_stop();
|
|
||||||
while (telemetry_active()) {
|
|
||||||
system_sleep();
|
system_sleep();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -106,10 +106,6 @@ int32_t telemetry_string_length = 0;
|
||||||
* Where we are in the current output
|
* Where we are in the current output
|
||||||
*/
|
*/
|
||||||
int32_t telemetry_index;
|
int32_t telemetry_index;
|
||||||
/**
|
|
||||||
* Should we stop?
|
|
||||||
*/
|
|
||||||
uint8_t telemetry_stop_flag = 0;
|
|
||||||
/**
|
/**
|
||||||
* Is the radio currently on?
|
* Is the radio currently on?
|
||||||
*/
|
*/
|
||||||
|
@ -142,7 +138,6 @@ int telemetry_start(enum telemetry_t type, int32_t length) {
|
||||||
telemetry_type = type;
|
telemetry_type = type;
|
||||||
telemetry_index = 0;
|
telemetry_index = 0;
|
||||||
telemetry_string_length = length;
|
telemetry_string_length = length;
|
||||||
telemetry_stop_flag = 0;
|
|
||||||
|
|
||||||
/* Setup timer tick */
|
/* Setup timer tick */
|
||||||
switch(telemetry_type) {
|
switch(telemetry_type) {
|
||||||
|
@ -153,7 +148,7 @@ int telemetry_start(enum telemetry_t type, int32_t length) {
|
||||||
timer0_tick_init(RTTY_BITRATE);
|
timer0_tick_init(RTTY_BITRATE);
|
||||||
break;
|
break;
|
||||||
case TELEMETRY_PIPS:
|
case TELEMETRY_PIPS:
|
||||||
timer0_tick_init(PIPS_OFF_FREQUENCY);
|
timer0_tick_init(PIPS_FREQUENCY);
|
||||||
break;
|
break;
|
||||||
case TELEMETRY_APRS:
|
case TELEMETRY_APRS:
|
||||||
timer0_tick_init(AX25_TICK_RATE);
|
timer0_tick_init(AX25_TICK_RATE);
|
||||||
|
@ -207,7 +202,6 @@ float telemetry_si_temperature(void) {
|
||||||
void telemetry_stop(void) {
|
void telemetry_stop(void) {
|
||||||
/* All done, deactivate */
|
/* All done, deactivate */
|
||||||
telemetry_string_length = 0;
|
telemetry_string_length = 0;
|
||||||
telemetry_stop_flag = 0;
|
|
||||||
|
|
||||||
/* Turn radio off */
|
/* Turn radio off */
|
||||||
if (radio_on) {
|
if (radio_on) {
|
||||||
|
@ -222,7 +216,7 @@ void telemetry_stop(void) {
|
||||||
timer0_tick_deinit();
|
timer0_tick_deinit();
|
||||||
}
|
}
|
||||||
uint8_t is_telemetry_finished(void) {
|
uint8_t is_telemetry_finished(void) {
|
||||||
if (telemetry_index >= telemetry_string_length || telemetry_stop_flag) {
|
if (telemetry_index >= telemetry_string_length) {
|
||||||
|
|
||||||
/* Finish telemetry */
|
/* Finish telemetry */
|
||||||
telemetry_stop();
|
telemetry_stop();
|
||||||
|
@ -230,16 +224,6 @@ uint8_t is_telemetry_finished(void) {
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Stops the ongoing telemetry at the earliest possible moment (end of
|
|
||||||
* symbol / block).
|
|
||||||
*/
|
|
||||||
void telemetry_request_stop(void) {
|
|
||||||
if (telemetry_active()) {
|
|
||||||
telemetry_stop_flag = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -338,8 +322,7 @@ void telemetry_tick(void) {
|
||||||
|
|
||||||
if (!aprs_tick()) {
|
if (!aprs_tick()) {
|
||||||
/* Transmission Finished */
|
/* Transmission Finished */
|
||||||
telemetry_request_stop();
|
telemetry_stop();
|
||||||
if (is_telemetry_finished()) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -350,14 +333,11 @@ void telemetry_tick(void) {
|
||||||
/* Pips: Cw */
|
/* Pips: Cw */
|
||||||
si_trx_on(SI_MODEM_MOD_TYPE_CW, TELEMETRY_FREQUENCY, 1, TELEMETRY_POWER);
|
si_trx_on(SI_MODEM_MOD_TYPE_CW, TELEMETRY_FREQUENCY, 1, TELEMETRY_POWER);
|
||||||
radio_on = 1;
|
radio_on = 1;
|
||||||
timer0_tick_frequency(PIPS_ON_FREQUENCY);
|
|
||||||
|
|
||||||
} else { /* Turn off */
|
} else { /* Turn off */
|
||||||
si_trx_off(); radio_on = 0;
|
si_trx_off(); radio_on = 0;
|
||||||
timer0_tick_frequency(PIPS_OFF_FREQUENCY);
|
|
||||||
|
|
||||||
telemetry_index++;
|
telemetry_stop();
|
||||||
if (is_telemetry_finished()) return;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue