2014-07-13 13:33:10 +00:00
|
|
|
/*
|
2014-10-06 18:05:11 +00:00
|
|
|
* Bristol SEDS pico-tracker
|
2014-07-13 13:33:10 +00:00
|
|
|
* Copyright (C) 2014 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 <stdio.h>
|
|
|
|
#include <math.h>
|
2014-08-31 10:54:20 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "samd20.h"
|
2014-07-13 13:33:10 +00:00
|
|
|
#include "semihosting.h"
|
2014-08-23 21:18:49 +00:00
|
|
|
#include "hw_config.h"
|
|
|
|
#include "system/system.h"
|
|
|
|
#include "sercom/usart.h"
|
2014-08-27 18:57:03 +00:00
|
|
|
#include "system/port.h"
|
2015-03-13 09:58:22 +00:00
|
|
|
#include "system/events.h"
|
|
|
|
#include "system/extint.h"
|
2014-08-30 20:11:35 +00:00
|
|
|
#include "tc/tc_driver.h"
|
2014-08-23 21:18:49 +00:00
|
|
|
#include "gps.h"
|
2014-11-26 11:56:21 +00:00
|
|
|
#include "mfsk.h"
|
2014-10-25 17:26:47 +00:00
|
|
|
#include "ubx_messages.h"
|
2014-08-31 10:02:22 +00:00
|
|
|
#include "system/wdt.h"
|
2015-03-13 09:58:22 +00:00
|
|
|
#include "xosc.h"
|
2014-08-31 10:02:22 +00:00
|
|
|
#include "telemetry.h"
|
2015-03-15 21:18:33 +00:00
|
|
|
#include "timer.h"
|
2015-03-07 16:00:31 +00:00
|
|
|
#include "contestia.h"
|
2015-03-06 19:30:33 +00:00
|
|
|
#include "rsid.h"
|
2014-10-10 09:32:13 +00:00
|
|
|
#include "si_trx.h"
|
2014-11-18 14:37:36 +00:00
|
|
|
#include "si_trx_defs.h"
|
2014-10-25 17:26:47 +00:00
|
|
|
#include "analogue.h"
|
2014-08-27 18:57:03 +00:00
|
|
|
#include "spi_bitbang.h"
|
2014-08-30 20:11:35 +00:00
|
|
|
#include "system/interrupt.h"
|
2014-08-27 18:57:03 +00:00
|
|
|
|
2015-03-07 16:00:31 +00:00
|
|
|
#define CALLSIGN "UBSEDSx"
|
2014-10-25 17:26:47 +00:00
|
|
|
|
2015-03-15 21:18:33 +00:00
|
|
|
void xosc_measure_callback(uint32_t result);
|
|
|
|
void timepulse_callback(uint32_t sequence);
|
|
|
|
|
2015-03-16 15:30:36 +00:00
|
|
|
int32_t _xosc_error = 0;
|
|
|
|
|
2014-10-06 18:05:11 +00:00
|
|
|
/**
|
|
|
|
* Initialises the status LED
|
|
|
|
*/
|
|
|
|
static inline void led_init(void)
|
|
|
|
{
|
2015-03-15 18:43:07 +00:00
|
|
|
/**
|
|
|
|
* This pin is shared with the XOSC line on the current hardware bodge
|
|
|
|
*/
|
2014-10-06 18:05:11 +00:00
|
|
|
port_pin_set_config(LED0_PIN,
|
2015-03-13 09:58:22 +00:00
|
|
|
PORT_PIN_DIR_INPUT, /* Direction */
|
2014-10-06 18:05:11 +00:00
|
|
|
PORT_PIN_PULL_NONE, /* Pull */
|
|
|
|
false); /* Powersave */
|
2015-03-13 09:58:22 +00:00
|
|
|
// port_pin_set_output_level(LED0_PIN, 1); /* LED is active low */
|
2014-10-06 18:05:11 +00:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Turns the status LED on
|
|
|
|
*/
|
|
|
|
static inline void led_on(void)
|
|
|
|
{
|
2015-03-15 18:43:07 +00:00
|
|
|
//port_pin_set_output_level(LED0_PIN, 0); /* LED is active low */
|
2014-10-06 18:05:11 +00:00
|
|
|
}
|
|
|
|
/**
|
2015-03-07 16:02:22 +00:00
|
|
|
* Turns the status LED off
|
2014-10-06 18:05:11 +00:00
|
|
|
*/
|
|
|
|
static inline void led_off(void)
|
|
|
|
{
|
2015-03-15 18:43:07 +00:00
|
|
|
//port_pin_set_output_level(LED0_PIN, 1); /* LED is active low */
|
2014-08-30 20:11:35 +00:00
|
|
|
}
|
|
|
|
|
2014-10-24 11:13:29 +00:00
|
|
|
void wdt_init() {
|
|
|
|
/* 64 seconds timeout. So 2^(15+6) cycles of the wdt clock */
|
|
|
|
system_gclk_gen_set_config(WDT_GCLK,
|
|
|
|
GCLK_SOURCE_OSCULP32K, /* Source */
|
|
|
|
false, /* High When Disabled */
|
|
|
|
128, /* Division Factor */
|
|
|
|
false, /* Run in standby */
|
|
|
|
true); /* Output Pin Enable */
|
|
|
|
system_gclk_gen_enable(WDT_GCLK);
|
|
|
|
|
|
|
|
/* Set the watchdog timer. On 256Hz gclk 4 */
|
|
|
|
wdt_set_config(true, /* Lock WDT */
|
|
|
|
true, /* Enable WDT */
|
|
|
|
GCLK_GENERATOR_4, /* Clock Source */
|
|
|
|
WDT_PERIOD_16384CLK, /* Timeout Period */
|
|
|
|
WDT_PERIOD_NONE, /* Window Period */
|
|
|
|
WDT_PERIOD_NONE); /* Early Warning Period */
|
|
|
|
}
|
2014-07-13 13:33:10 +00:00
|
|
|
|
2014-10-25 14:42:25 +00:00
|
|
|
/**
|
|
|
|
* Power Management
|
|
|
|
*/
|
|
|
|
void powermananger_init(void)
|
|
|
|
{
|
|
|
|
system_apb_clock_clear_mask(SYSTEM_CLOCK_APB_APBA,
|
2015-03-15 19:29:16 +00:00
|
|
|
// PM_APBAMASK_EIC | /* EIC is used now */
|
|
|
|
// PM_APBAMASK_RTC | /* RTC is used now */
|
|
|
|
0);
|
2014-10-25 14:42:25 +00:00
|
|
|
}
|
|
|
|
|
2014-10-25 17:26:47 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Telemetry String
|
|
|
|
* =============================================================================
|
|
|
|
*/
|
2015-03-06 23:39:54 +00:00
|
|
|
void output_telemetry_string(enum telemetry_t type)
|
2014-10-25 17:26:47 +00:00
|
|
|
{
|
|
|
|
double lat_fmt = 0.0;
|
|
|
|
double lon_fmt = 0.0;
|
|
|
|
uint32_t altitude = 0;
|
2015-03-07 15:29:10 +00:00
|
|
|
uint16_t len;
|
2015-03-07 16:00:31 +00:00
|
|
|
uint8_t dollars = 2;
|
2014-10-25 17:26:47 +00:00
|
|
|
|
|
|
|
/**
|
2015-03-07 16:00:31 +00:00
|
|
|
* Collect Data
|
2014-10-25 17:26:47 +00:00
|
|
|
* ---------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
2015-02-27 10:55:05 +00:00
|
|
|
/* Analogue */
|
|
|
|
float battery = get_battery();
|
2015-03-16 13:55:26 +00:00
|
|
|
float temperature = telemetry_si_temperature();
|
2015-02-27 10:55:05 +00:00
|
|
|
|
2014-10-25 17:26:47 +00:00
|
|
|
/* 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()) {
|
2015-03-07 15:29:10 +00:00
|
|
|
led_on();
|
2014-10-25 17:26:47 +00:00
|
|
|
} else {
|
2015-03-07 15:29:10 +00:00
|
|
|
led_off();
|
2014-10-25 17:26:47 +00:00
|
|
|
}
|
|
|
|
|
2015-03-07 15:29:10 +00:00
|
|
|
/* Wait for the gps update */
|
|
|
|
while (gps_update_position_pending()) {
|
2014-10-25 17:26:47 +00:00
|
|
|
system_sleep();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gps_is_locked()) {
|
2015-03-07 15:29:10 +00:00
|
|
|
led_off();
|
2014-10-25 17:26:47 +00:00
|
|
|
} else {
|
2015-03-07 15:29:10 +00:00
|
|
|
led_on();
|
2014-10-25 17:26:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* GPS Status */
|
|
|
|
struct ubx_nav_sol sol = gps_get_nav_sol();
|
|
|
|
uint8_t satillite_count = sol.payload.numSV;
|
|
|
|
|
|
|
|
/* GPS Position */
|
2015-03-16 15:30:36 +00:00
|
|
|
if (gps_is_locked()) {
|
2014-10-25 17:26:47 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-03-16 15:30:36 +00:00
|
|
|
/* GPS Powersave */
|
|
|
|
gps_set_powersave_auto();
|
2015-03-07 16:00:31 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Format
|
|
|
|
* ---------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (type == TELEMETRY_RTTY) {
|
|
|
|
dollars = 5; // Extra dollars for RTTY
|
|
|
|
}
|
|
|
|
|
2015-03-07 15:29:10 +00:00
|
|
|
/* sprintf - preamble */
|
|
|
|
memset(telemetry_string, '$', dollars);
|
|
|
|
len = dollars;
|
|
|
|
|
2014-10-25 17:26:47 +00:00
|
|
|
/* sprintf - full string */
|
2015-03-07 15:29:10 +00:00
|
|
|
len += sprintf(telemetry_string + len,
|
2015-03-16 15:30:36 +00:00
|
|
|
"%s,%02u:%02u:%02u,%02.5f,%03.5f,%ld,%u,%.2f,%.1f,%ld",
|
2014-10-25 22:36:44 +00:00
|
|
|
CALLSIGN, hours, minutes, seconds, lat_fmt, lon_fmt,
|
2015-03-16 15:30:36 +00:00
|
|
|
altitude, satillite_count, battery, temperature, _xosc_error);
|
2014-10-25 17:26:47 +00:00
|
|
|
|
2015-03-07 16:00:31 +00:00
|
|
|
if (type == TELEMETRY_CONTESTIA) { contestiaize(telemetry_string + dollars); }
|
|
|
|
|
2015-03-07 15:29:10 +00:00
|
|
|
/* sprintf - checksum. don't include dollars */
|
|
|
|
len += sprintf(telemetry_string + len,
|
2015-02-27 10:55:05 +00:00
|
|
|
"*%04X\r",
|
2015-03-07 16:00:31 +00:00
|
|
|
crc_checksum(telemetry_string + dollars));
|
2014-10-25 17:26:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2015-03-07 15:29:10 +00:00
|
|
|
/**
|
|
|
|
* Starting up the radio blocks on high-prio interrupt for ~100ms: todo fixme
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* RSID */
|
|
|
|
/* start - SI NOW BELONGS TO TELEMETRY, WE CANNOT ACCESS */
|
|
|
|
if (type == TELEMETRY_CONTESTIA) {
|
|
|
|
telemetry_start_rsid(RSID_CONTESTIA_32_1000);
|
|
|
|
}
|
|
|
|
|
2015-03-16 01:09:25 +00:00
|
|
|
/* Sleep Wait for RSID */
|
2015-03-07 15:29:10 +00:00
|
|
|
while (telemetry_active()) {
|
|
|
|
system_sleep();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Main telemetry */
|
|
|
|
telemetry_start(type, len);
|
2015-03-16 01:09:25 +00:00
|
|
|
|
|
|
|
/* Sleep Wait for main telemetry */
|
|
|
|
while (telemetry_active()) {
|
|
|
|
system_sleep();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pips */
|
|
|
|
telemetry_start(TELEMETRY_PIPS, 0xFFFF);
|
2014-10-25 17:26:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-03-13 19:42:01 +00:00
|
|
|
* Internal initialisation
|
2014-10-25 17:26:47 +00:00
|
|
|
* =============================================================================
|
|
|
|
*/
|
2015-03-13 19:42:01 +00:00
|
|
|
void init(void)
|
2014-07-13 13:33:10 +00:00
|
|
|
{
|
2014-10-06 18:05:11 +00:00
|
|
|
/**
|
|
|
|
* Internal initialisation
|
|
|
|
* ---------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
2014-08-30 20:11:35 +00:00
|
|
|
/* Clock up to 14MHz with 0 wait states */
|
|
|
|
system_flash_set_waitstates(SYSTEM_WAIT_STATE_1_8V_14MHZ);
|
2014-07-13 13:33:10 +00:00
|
|
|
|
2015-04-02 10:38:48 +00:00
|
|
|
/* Up the clock rate to 8MHz */
|
|
|
|
system_clock_source_osc8m_set_config(SYSTEM_OSC8M_DIV_1, /* Prescaler */
|
2014-08-23 21:18:49 +00:00
|
|
|
false, /* Run in Standby */
|
|
|
|
false); /* Run on Demand */
|
|
|
|
|
2014-08-27 18:57:03 +00:00
|
|
|
/* Restart the GCLK Module */
|
|
|
|
system_gclk_init();
|
2015-03-13 09:58:22 +00:00
|
|
|
system_events_init();
|
|
|
|
system_extint_init();
|
2014-07-13 13:33:10 +00:00
|
|
|
|
2014-08-27 18:57:03 +00:00
|
|
|
/* Get the current CPU Clock */
|
|
|
|
SystemCoreClock = system_cpu_clock_get_hz();
|
2014-08-23 21:18:49 +00:00
|
|
|
|
|
|
|
/* Configure Sleep Mode */
|
2014-10-25 18:38:28 +00:00
|
|
|
//system_set_sleepmode(SYSTEM_SLEEPMODE_STANDBY);
|
|
|
|
system_set_sleepmode(SYSTEM_SLEEPMODE_IDLE_2); /* Disable CPU, AHB and APB */
|
2014-08-23 21:18:49 +00:00
|
|
|
|
2014-10-25 14:42:25 +00:00
|
|
|
/* Configure the Power Manager */
|
2014-11-18 14:37:36 +00:00
|
|
|
//powermananger_init();
|
2014-10-06 18:05:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* System initialisation
|
|
|
|
* ---------------------------------------------------------------------------
|
|
|
|
*/
|
2014-08-31 10:54:20 +00:00
|
|
|
|
2014-10-24 11:13:29 +00:00
|
|
|
/* Set the wdt here. We should get to the first reset in one min */
|
2014-11-18 14:37:36 +00:00
|
|
|
//wdt_init();
|
|
|
|
//wdt_reset_count();
|
2014-10-24 11:13:29 +00:00
|
|
|
|
2015-03-15 21:18:33 +00:00
|
|
|
/* Enables the xosc on gclk1 */
|
2015-03-13 19:42:01 +00:00
|
|
|
xosc_init();
|
|
|
|
|
2014-10-06 18:05:11 +00:00
|
|
|
led_init();
|
2014-08-23 21:18:49 +00:00
|
|
|
gps_init();
|
2014-08-27 18:57:03 +00:00
|
|
|
|
2015-03-15 21:18:33 +00:00
|
|
|
/* Enable timer interrupt and event channel */
|
|
|
|
timepulse_extint_init();
|
|
|
|
timepulse_set_callback(timepulse_callback);
|
|
|
|
|
2014-11-26 11:56:21 +00:00
|
|
|
/* Initialise Si4060 interface */
|
2014-11-18 14:37:36 +00:00
|
|
|
si_trx_init();
|
2015-03-13 19:42:01 +00:00
|
|
|
}
|
2014-08-30 20:11:35 +00:00
|
|
|
|
2015-03-13 09:58:22 +00:00
|
|
|
|
2015-03-15 17:34:46 +00:00
|
|
|
void xosc_measure_callback(uint32_t result)
|
|
|
|
{
|
2015-03-16 15:30:36 +00:00
|
|
|
_xosc_error = result - XOSC_FREQUENCY;
|
2015-03-15 21:18:33 +00:00
|
|
|
}
|
2015-03-15 17:34:46 +00:00
|
|
|
|
2015-03-15 21:18:33 +00:00
|
|
|
uint8_t telemetry_trigger_flag = 0;
|
|
|
|
void timepulse_callback(uint32_t sequence)
|
|
|
|
{
|
|
|
|
telemetry_trigger_flag = 1;
|
2015-03-15 17:34:46 +00:00
|
|
|
}
|
|
|
|
|
2015-03-13 19:42:01 +00:00
|
|
|
/**
|
|
|
|
* MAIN
|
|
|
|
* =============================================================================
|
|
|
|
*/
|
|
|
|
int main(void)
|
|
|
|
{
|
2015-03-16 01:09:25 +00:00
|
|
|
uint32_t telemetry_alternate = 0;
|
|
|
|
|
2015-03-13 19:42:01 +00:00
|
|
|
init();
|
2015-03-13 09:58:22 +00:00
|
|
|
|
2015-03-07 15:29:10 +00:00
|
|
|
led_on();
|
2015-03-06 19:30:33 +00:00
|
|
|
|
2015-04-01 14:13:01 +00:00
|
|
|
|
2015-04-14 15:17:38 +00:00
|
|
|
/* while (1) { */
|
|
|
|
/* telemetry_start(TELEMETRY_APRS, 0xFFFF); */
|
2015-04-01 14:13:01 +00:00
|
|
|
|
2015-04-14 15:17:38 +00:00
|
|
|
/* while (telemetry_active()) { */
|
|
|
|
/* system_sleep(); */
|
|
|
|
/* } */
|
2015-04-01 14:13:01 +00:00
|
|
|
|
2015-04-14 15:17:38 +00:00
|
|
|
/* for (int i = 0; i < 1000*1000; i++); */
|
|
|
|
/* } */
|
2015-04-01 14:13:01 +00:00
|
|
|
|
|
|
|
|
2014-08-23 21:18:49 +00:00
|
|
|
while (1) {
|
2015-03-15 21:18:33 +00:00
|
|
|
/* Sleep wait for next telemetry */
|
2015-03-16 01:09:25 +00:00
|
|
|
while (telemetry_trigger_flag == 0) {
|
2015-03-07 15:29:10 +00:00
|
|
|
system_sleep();
|
|
|
|
}
|
2015-03-15 21:18:33 +00:00
|
|
|
telemetry_trigger_flag = 0;
|
|
|
|
|
2015-03-16 01:09:25 +00:00
|
|
|
/* End pips */
|
|
|
|
telemetry_stop();
|
|
|
|
while (telemetry_active()) {
|
|
|
|
system_sleep();
|
|
|
|
}
|
|
|
|
|
2015-03-15 21:18:33 +00:00
|
|
|
/* Watchdog */
|
|
|
|
//wdt_reset_count();
|
2015-03-07 15:29:10 +00:00
|
|
|
|
|
|
|
/* Send the next packet */
|
2015-03-16 01:09:25 +00:00
|
|
|
output_telemetry_string((telemetry_alternate++ & 1) ?
|
|
|
|
TELEMETRY_CONTESTIA :
|
|
|
|
TELEMETRY_RTTY);
|
2015-03-16 15:30:36 +00:00
|
|
|
|
|
|
|
/* Measure XOSC against gps timepulse */
|
|
|
|
measure_xosc(XOSC_MEASURE_TIMEPULSE, xosc_measure_callback);
|
2014-08-23 21:18:49 +00:00
|
|
|
}
|
2014-07-13 13:33:10 +00:00
|
|
|
}
|