kopia lustrzana https://github.com/bristol-seds/pico-tracker
commit
afabff5734
|
@ -33,12 +33,17 @@ enum gps_error_t {
|
|||
GPS_ERROR_INVALID_FRAME,
|
||||
};
|
||||
|
||||
void gps_update();
|
||||
void gps_update_time(void);
|
||||
void gps_update_position(void);
|
||||
int gps_update_time_pending(void);
|
||||
int gps_update_position_pending(void);
|
||||
|
||||
struct ubx_nav_posllh gps_get_nav_posllh();
|
||||
struct ubx_nav_sol gps_get_nav_sol();
|
||||
struct ubx_nav_timeutc gps_get_nav_timeutc();
|
||||
|
||||
uint8_t gps_is_locked(void);
|
||||
|
||||
void gps_init(void);
|
||||
void usart_loopback_test(void);
|
||||
|
||||
|
|
|
@ -120,6 +120,11 @@
|
|||
#define SI406X_TCXO_GCLK GCLK_GENERATOR_3
|
||||
#define SI406X_TCXO_FREQUENCY 16369000
|
||||
|
||||
/**
|
||||
* Watchdog Timer
|
||||
*/
|
||||
#define WDT_GCLK GCLK_GENERATOR_4
|
||||
|
||||
/**
|
||||
* External Watchdog Timer
|
||||
*/
|
||||
|
|
|
@ -25,8 +25,21 @@
|
|||
#ifndef RTTY_H
|
||||
#define RTTY_H
|
||||
|
||||
#include "util/dbuffer.h"
|
||||
|
||||
/**
|
||||
* Output String
|
||||
*/
|
||||
#define RTTY_STRING_MAX 0x200
|
||||
/**
|
||||
* It's actually a double buffer which we swap for mid-string updates
|
||||
*/
|
||||
ARRAY_DBUFFER_T(char, RTTY_STRING_MAX) rtty_dbuffer_string;
|
||||
|
||||
int rtty_active(void);
|
||||
int rtty_set_string(char* string, uint32_t length);
|
||||
int rtty_start(void);
|
||||
int32_t rtty_get_index(void);
|
||||
void rtty_set_length(int32_t length);
|
||||
void rtty_tick(void);
|
||||
|
||||
#endif /* RTTY_H */
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#ifndef TELEMETRY_H
|
||||
#define TELEMETRY_H
|
||||
|
||||
void set_telemetry_string(void);
|
||||
uint16_t crc_checksum(char *string);
|
||||
void timer0_tick_init(uint32_t frequency);
|
||||
|
||||
#endif /* TELEMETRY_H */
|
||||
|
|
|
@ -36,6 +36,7 @@ enum ubx_packet_state {
|
|||
UBX_PACKET_WAITING,
|
||||
UBX_PACKET_ACK,
|
||||
UBX_PACKET_NACK,
|
||||
UBX_PACKET_UPDATED,
|
||||
};
|
||||
/** Generic UBX Message Type. Each message type extended is from this */
|
||||
typedef struct {
|
||||
|
@ -73,6 +74,26 @@ __PACKED__ struct ubx_cfg_ant {
|
|||
uint16_t pins;
|
||||
} payload;
|
||||
};
|
||||
/**
|
||||
* UBX CFG GNSS
|
||||
*/
|
||||
__PACKED__ struct ubx_cfg_gnss {
|
||||
ubx_message_id_t id;
|
||||
enum ubx_packet_state state;
|
||||
struct {
|
||||
uint8_t msgVer;
|
||||
uint8_t numTrkChHw;
|
||||
uint8_t numTrkChUse;
|
||||
uint8_t numConfigBlocks;
|
||||
struct {
|
||||
uint8_t gnssID;
|
||||
uint8_t resTrkCh;
|
||||
uint8_t maxTrkCh;
|
||||
uint8_t reserved1;
|
||||
int32_t flags;
|
||||
} block[8];
|
||||
} payload;
|
||||
};
|
||||
/**
|
||||
* UBX CFG NAV5 Navigation Engine Settings
|
||||
*/
|
||||
|
@ -150,6 +171,17 @@ enum {
|
|||
UBX_PLATFORM_MODEL_AIRBORNE_2G = 7,
|
||||
UBX_PLATFORM_MODEL_AIRBORNE_4G = 8,
|
||||
};
|
||||
/**
|
||||
* UBX GNSS Systems
|
||||
*/
|
||||
enum {
|
||||
UBX_GNSS_GPS = 0,
|
||||
UBX_GNSS_SBAS = 1,
|
||||
UBX_GNSS_GALILEO = 2,
|
||||
UBX_GNSS_BEIDOU = 3,
|
||||
UBX_GNSS_QZSS = 5,
|
||||
UBX_GNSS_GLONASS = 6,
|
||||
};
|
||||
|
||||
/**
|
||||
* =============================================================================
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Functions for the UBLOX 6 GPS
|
||||
* Functions for the UBLOX 8 GPS
|
||||
* Copyright (C) 2014 Richard Meadows <richardeoin>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
@ -69,6 +69,7 @@ uint8_t ubx_irq_buffer[UBX_BUFFER_LEN];
|
|||
* UBX Messages
|
||||
*/
|
||||
volatile struct ubx_cfg_ant ubx_cfg_ant = { .id = (UBX_CFG | (0x13 << 8)) };
|
||||
volatile struct ubx_cfg_gnss ubx_cfg_gnss = { .id = (UBX_CFG | (0x3E << 8)) };
|
||||
volatile struct ubx_cfg_nav5 ubx_cfg_nav5 = { .id = (UBX_CFG | (0x24 << 8)) };
|
||||
volatile struct ubx_cfg_tp5 ubx_cfg_tp5 = { .id = (UBX_CFG | (0x31 << 8)) };
|
||||
volatile struct ubx_cfg_prt ubx_cfg_prt = { .id = (UBX_CFG | (0x00 << 8)) };
|
||||
|
@ -81,6 +82,7 @@ volatile struct ubx_nav_status ubx_nav_status = { .id = (UBX_NAV | (0x03 << 8))
|
|||
*/
|
||||
volatile ubx_message_t* const ubx_messages[] = {
|
||||
(ubx_message_t*)&ubx_cfg_ant,
|
||||
(ubx_message_t*)&ubx_cfg_gnss,
|
||||
(ubx_message_t*)&ubx_cfg_nav5,
|
||||
(ubx_message_t*)&ubx_cfg_tp5,
|
||||
(ubx_message_t*)&ubx_cfg_prt,
|
||||
|
@ -163,6 +165,9 @@ void ubx_process_frame(uint8_t* frame)
|
|||
/* Populate struct */
|
||||
memcpy((void*)(ubx_messages[i]+1), frame + 4, payload_length);
|
||||
|
||||
/* Set the message state */
|
||||
ubx_messages[i]->state = UBX_PACKET_UPDATED;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -230,6 +235,9 @@ void _ubx_send_message(ubx_message_t* message, uint8_t* payload, uint16_t length
|
|||
uint8_t ubx[UBX_BUFFER_LEN];
|
||||
uint8_t* ubx_buffer = ubx;
|
||||
|
||||
/* Clear the message state */
|
||||
message->state = UBX_PACKET_WAITING;
|
||||
|
||||
/* Copy little endian */
|
||||
memcpy(ubx_buffer, &ubx_header, 2); ubx_buffer += 2; /* Header */
|
||||
memcpy(ubx_buffer, &message->id, 2); ubx_buffer += 2; /* Message Type */
|
||||
|
@ -244,9 +252,7 @@ void _ubx_send_message(ubx_message_t* message, uint8_t* payload, uint16_t length
|
|||
* Polls the GPS for packets
|
||||
*/
|
||||
void _ubx_poll(ubx_message_t* message) {
|
||||
/* Clear the packet state */
|
||||
message->state = UBX_PACKET_WAITING;
|
||||
|
||||
/* Send the message */
|
||||
_ubx_send_message(message, NULL, 0);
|
||||
|
||||
/* Wait for acknoledge */
|
||||
|
@ -275,14 +281,37 @@ void gps_disable_nmea(void)
|
|||
}
|
||||
|
||||
/**
|
||||
* Sends messages to the GPS to update the messages we want
|
||||
* Sends messages to the GPS to update the time
|
||||
*/
|
||||
void gps_update()
|
||||
void gps_update_time(void)
|
||||
{
|
||||
_ubx_send_message((ubx_message_t*)&ubx_nav_timeutc, NULL, 0);
|
||||
};
|
||||
/**
|
||||
* Sends messages to the GPS to update the position
|
||||
*/
|
||||
void gps_update_position(void)
|
||||
{
|
||||
_ubx_send_message((ubx_message_t*)&ubx_nav_posllh, NULL, 0);
|
||||
_ubx_send_message((ubx_message_t*)&ubx_nav_sol, NULL, 0);
|
||||
_ubx_send_message((ubx_message_t*)&ubx_nav_timeutc, NULL, 0);
|
||||
_ubx_send_message((ubx_message_t*)&ubx_nav_status, NULL, 0);
|
||||
|
||||
// _ubx_send_message((ubx_message_t*)&ubx_nav_status, NULL, 0);
|
||||
}
|
||||
/**
|
||||
* Indicates a pending time update from the GPS
|
||||
*/
|
||||
int gps_update_time_pending(void)
|
||||
{
|
||||
return (ubx_nav_timeutc.state == UBX_PACKET_WAITING);
|
||||
}
|
||||
/**
|
||||
* Indicates a pending position update from the GPS
|
||||
*/
|
||||
int gps_update_position_pending(void)
|
||||
{
|
||||
return (ubx_nav_posllh.state == UBX_PACKET_WAITING) ||
|
||||
(ubx_nav_sol.state == UBX_PACKET_WAITING);
|
||||
//(ubx_nav_status.state == UBX_PACKET_WAITING);
|
||||
}
|
||||
/**
|
||||
* Return the latest received messages
|
||||
|
@ -299,6 +328,15 @@ struct ubx_nav_timeutc gps_get_nav_timeutc()
|
|||
{
|
||||
return ubx_nav_timeutc;
|
||||
}
|
||||
/**
|
||||
* Returns if the GPS has a position lock
|
||||
*/
|
||||
uint8_t gps_is_locked(void)
|
||||
{
|
||||
return (ubx_nav_sol.payload.gpsFix == 0x2) ||
|
||||
(ubx_nav_sol.payload.gpsFix == 0x3) ||
|
||||
(ubx_nav_sol.payload.gpsFix == 0x4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the uBlox 6 GPS receiver is set to the <1g airborne
|
||||
|
@ -341,6 +379,36 @@ void gps_set_timepulse_five(uint32_t frequency)
|
|||
(uint8_t*)&ubx_cfg_tp5.payload,
|
||||
sizeof(ubx_cfg_tp5.payload));
|
||||
}
|
||||
/**
|
||||
* Set which GNSS constellations to use
|
||||
*/
|
||||
void gps_set_gnss(void)
|
||||
{
|
||||
/* Read the current settings */
|
||||
_ubx_poll((ubx_message_t*)&ubx_cfg_gnss);
|
||||
|
||||
switch (ubx_cfg_gnss.payload.msgVer) {
|
||||
case 0:
|
||||
/* For each configuration block */
|
||||
for (uint8_t i = 0; i < ubx_cfg_gnss.payload.numConfigBlocks; i++) {
|
||||
|
||||
/* If it's the configuration for something other than GPS */
|
||||
if (ubx_cfg_gnss.payload.block[i].gnssID != UBX_GNSS_GPS) {
|
||||
|
||||
/* Disable this GNSS system */
|
||||
ubx_cfg_gnss.payload.block[i].flags &= ~0x1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Write the new settings */
|
||||
_ubx_send_message((ubx_message_t*)&ubx_cfg_gnss,
|
||||
(uint8_t*)&ubx_cfg_gnss.payload,
|
||||
4 + (8 * ubx_cfg_gnss.payload.numConfigBlocks));
|
||||
}
|
||||
|
||||
/**
|
||||
* Init
|
||||
|
@ -386,6 +454,9 @@ void gps_init(void)
|
|||
/* Set the platform model */
|
||||
gps_set_platform_model();
|
||||
|
||||
/* Set which GNSS constellation we'd like to use */
|
||||
gps_set_gnss();
|
||||
|
||||
/* Set the timepulse */
|
||||
gps_set_timepulse_five(GPS_TIMEPULSE_FREQ);
|
||||
}
|
||||
|
|
|
@ -34,15 +34,21 @@
|
|||
#include "system/port.h"
|
||||
#include "tc/tc_driver.h"
|
||||
#include "gps.h"
|
||||
#include "ubx_messages.h"
|
||||
#include "system/wdt.h"
|
||||
#include "timepulse.h"
|
||||
#include "telemetry.h"
|
||||
|
||||
#include "si_trx.h"
|
||||
|
||||
#include "analogue.h"
|
||||
#include "si4060.h"
|
||||
#include "spi_bitbang.h"
|
||||
#include "rtty.h"
|
||||
#include "system/interrupt.h"
|
||||
|
||||
#define CALLSIGN "UBSEDSx"
|
||||
|
||||
void si4060_hw_init(void)
|
||||
{
|
||||
/* Configure the SDN pin */
|
||||
|
@ -148,25 +154,158 @@ void set_timer(uint32_t time)
|
|||
tc_start_counter(TC2);
|
||||
}
|
||||
|
||||
/* 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); */
|
||||
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 *\/ */
|
||||
/* } */
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Power Management
|
||||
*/
|
||||
void powermananger_init(void)
|
||||
{
|
||||
system_apb_clock_clear_mask(SYSTEM_CLOCK_APB_APBA,
|
||||
PM_APBAMASK_EIC | /* EIC is unused */
|
||||
PM_APBAMASK_RTC); /* RTC is unused */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Telemetry String
|
||||
* =============================================================================
|
||||
*/
|
||||
void output_telemetry_string(void)
|
||||
{
|
||||
double lat_fmt = 0.0;
|
||||
double lon_fmt = 0.0;
|
||||
uint32_t altitude = 0;
|
||||
|
||||
/**
|
||||
* Callsign, Time
|
||||
* ---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* GPS Time */
|
||||
gps_update_time();
|
||||
|
||||
/* Sleep Wait */
|
||||
while (gps_update_time_pending()) {
|
||||
system_sleep();
|
||||
}
|
||||
for (int i = 0; i < 100*1000; i++);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* init double buffers */
|
||||
ARRAY_DBUFFER_INIT(&rtty_dbuffer_string);
|
||||
|
||||
/* sprintf - initial string */
|
||||
uint16_t len = sprintf(ARRAY_DBUFFER_WRITE_PTR(&rtty_dbuffer_string),
|
||||
"$$%s,%02u:%02u:%02u,",
|
||||
CALLSIGN, hours, minutes, seconds);
|
||||
|
||||
/* swap buffers */
|
||||
ARRAY_DBUFFER_SWAP(&rtty_dbuffer_string);
|
||||
|
||||
/* start */
|
||||
rtty_start();
|
||||
|
||||
/**
|
||||
* Position, Status, Analogue, Checksum
|
||||
* ---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Analogue */
|
||||
float battery = get_battery();
|
||||
float temperature = si4060_get_temperature();
|
||||
|
||||
/* Sleep Wait */
|
||||
while (rtty_get_index() < (len - 4)) {
|
||||
system_sleep();
|
||||
}
|
||||
|
||||
/* Request updates from the gps */
|
||||
gps_update_position();
|
||||
if (gps_is_locked()) {
|
||||
led_on();
|
||||
} else {
|
||||
led_off();
|
||||
}
|
||||
|
||||
/* Wait for the gps update. Move on if it's urgent */
|
||||
while (gps_update_position_pending() && rtty_get_index() < (len - 1)) {
|
||||
system_sleep();
|
||||
}
|
||||
|
||||
if (gps_is_locked()) {
|
||||
led_off();
|
||||
} else {
|
||||
led_on();
|
||||
}
|
||||
|
||||
/* GPS Status */
|
||||
struct ubx_nav_sol sol = gps_get_nav_sol();
|
||||
uint8_t lock = sol.payload.gpsFix;
|
||||
uint8_t satillite_count = sol.payload.numSV;
|
||||
|
||||
/* GPS Position */
|
||||
if (lock == 0x2 || lock == 0x3 || lock == 0x4) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* sprintf - full string */
|
||||
len = sprintf(ARRAY_DBUFFER_WRITE_PTR(&rtty_dbuffer_string),
|
||||
"$$%s,%02u:%02u:%02u,%02.6f,%03.6f,%ld,%u,%.2f,%.1f",
|
||||
CALLSIGN, hours, minutes, seconds, lat_fmt, lon_fmt,
|
||||
altitude, satillite_count, battery, temperature);
|
||||
|
||||
/* sprintf - checksum */
|
||||
len += sprintf(ARRAY_DBUFFER_WRITE_PTR(&rtty_dbuffer_string) + len,
|
||||
"*%04X\n",
|
||||
crc_checksum(ARRAY_DBUFFER_WRITE_PTR(&rtty_dbuffer_string)));
|
||||
|
||||
/* swap buffers */
|
||||
ARRAY_DBUFFER_SWAP(&rtty_dbuffer_string);
|
||||
|
||||
/**
|
||||
* End
|
||||
* ---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Set the final length */
|
||||
rtty_set_length(len);
|
||||
|
||||
/* Sleep Wait */
|
||||
while (rtty_active()) {
|
||||
system_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MAIN
|
||||
* =============================================================================
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
/**
|
||||
|
@ -189,18 +328,24 @@ int main(void)
|
|||
SystemCoreClock = system_cpu_clock_get_hz();
|
||||
|
||||
/* Configure Sleep Mode */
|
||||
system_set_sleepmode(SYSTEM_SLEEPMODE_IDLE_0);
|
||||
//TODO: system_set_sleepmode(SYSTEM_SLEEPMODE_STANDBY);
|
||||
//system_set_sleepmode(SYSTEM_SLEEPMODE_STANDBY);
|
||||
system_set_sleepmode(SYSTEM_SLEEPMODE_IDLE_2); /* Disable CPU, AHB and APB */
|
||||
|
||||
/* Configure the SysTick for 50Hz triggering */
|
||||
SysTick_Config(SystemCoreClock / 50);
|
||||
/* Configure the Power Manager */
|
||||
powermananger_init();
|
||||
|
||||
/* Timer 0 for 50Hz triggering */
|
||||
timer0_tick_init(50);
|
||||
|
||||
/**
|
||||
* System initialisation
|
||||
* ---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Set the wdt here. We should get to the first reset in one min */
|
||||
wdt_init();
|
||||
wdt_reset_count();
|
||||
|
||||
led_init();
|
||||
gps_init();
|
||||
|
||||
|
@ -227,31 +372,25 @@ int main(void)
|
|||
|
||||
//si_trx_state_tx();
|
||||
|
||||
led_on();
|
||||
|
||||
while (1) {
|
||||
/* Send the last packet */
|
||||
while (rtty_active());
|
||||
/* Watchdog */
|
||||
wdt_reset_count();
|
||||
|
||||
/* Send requests to the gps */
|
||||
gps_update();
|
||||
|
||||
/* Wait between frames */
|
||||
led_on();
|
||||
for (int i = 0; i < 100*1000; i++);
|
||||
led_off();
|
||||
for (int i = 0; i < 100*1000; i++);
|
||||
|
||||
/* Set the next packet */
|
||||
set_telemetry_string();
|
||||
|
||||
//system_sleep();
|
||||
/* Send the next packet */
|
||||
output_telemetry_string();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called at 50Hz
|
||||
*/
|
||||
void SysTick_Handler(void)
|
||||
void TC0_Handler(void)
|
||||
{
|
||||
/* Output RTTY */
|
||||
rtty_tick();
|
||||
if (tc_get_status(TC0) & TC_STATUS_CHANNEL_0_MATCH) {
|
||||
tc_clear_status(TC0, TC_STATUS_CHANNEL_0_MATCH);
|
||||
|
||||
rtty_tick();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "samd20.h"
|
||||
#include "rtty.h"
|
||||
#include "hw_config.h"
|
||||
#include "system/port.h"
|
||||
|
||||
|
@ -33,7 +34,7 @@
|
|||
*/
|
||||
#define RTTY_ACTIVATE()
|
||||
#define RTTY_DEACTIVATE()
|
||||
#define RTTY_SET(b) port_pin_set_output_level(SI406X_GPIO1_PIN, b);
|
||||
#define RTTY_SET(b) port_pin_set_output_level(SI406X_GPIO1_PIN, !b);
|
||||
#define RTTY_NEXT()
|
||||
|
||||
/**
|
||||
|
@ -42,11 +43,6 @@
|
|||
#define ASCII_BITS 8
|
||||
#define BITS_PER_CHAR 11
|
||||
|
||||
/**
|
||||
* Output String
|
||||
*/
|
||||
#define RTTY_STRING_MAX 0x200
|
||||
|
||||
/**
|
||||
* Where we currently are in the rtty output byte
|
||||
*
|
||||
|
@ -59,13 +55,12 @@ uint8_t rtty_phase;
|
|||
/**
|
||||
* Where we are in the current output string
|
||||
*/
|
||||
uint32_t rtty_index;
|
||||
int32_t rtty_index;
|
||||
|
||||
/**
|
||||
* Details of the string that is currently being output
|
||||
*/
|
||||
char rtty_string[RTTY_STRING_MAX];
|
||||
uint32_t rtty_string_length = 0;
|
||||
int32_t rtty_string_length = 0;
|
||||
|
||||
/**
|
||||
* Returns 1 if we're currently outputting.
|
||||
|
@ -75,25 +70,35 @@ int rtty_active(void) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets an output string.
|
||||
* Starts RTTY output
|
||||
*
|
||||
* Returns 0 on success, 1 if a string is already active or 2 if the
|
||||
* specified string was too long.
|
||||
* Returns 0 on success, 1 if already active
|
||||
*/
|
||||
int rtty_set_string(char* string, uint32_t length) {
|
||||
if (length > RTTY_STRING_MAX) return 2; // To long
|
||||
|
||||
int rtty_start(void) {
|
||||
if (!rtty_active()) {
|
||||
// Copy
|
||||
memcpy(rtty_string, string, length);
|
||||
rtty_string_length = length;
|
||||
// Initialise
|
||||
|
||||
/* Initialise */
|
||||
rtty_string_length = RTTY_STRING_MAX;
|
||||
rtty_index = 0;
|
||||
rtty_phase = 0;
|
||||
|
||||
return 0; // Success
|
||||
return 0; /* Success */
|
||||
} else {
|
||||
return 1; // Already active
|
||||
return 1; /* Already active */
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns the index of the current byte being outputted from the buffer
|
||||
*/
|
||||
int32_t rtty_get_index(void) {
|
||||
return rtty_index;
|
||||
}
|
||||
/**
|
||||
* Sets the final length of the RTTY string
|
||||
*/
|
||||
void rtty_set_length(int32_t length) {
|
||||
if (length <= RTTY_STRING_MAX) {
|
||||
rtty_string_length = length;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,21 +111,17 @@ void rtty_tick(void) {
|
|||
|
||||
if (rtty_phase == 0) { // Start
|
||||
// Low
|
||||
//RTTY_SET(0);
|
||||
port_pin_set_output_level(SI406X_GPIO1_PIN, 0);
|
||||
RTTY_SET(0);
|
||||
} else if (rtty_phase < ASCII_BITS + 1) {
|
||||
// Data
|
||||
if ((rtty_string[rtty_index] >> (rtty_phase - 1)) & 1) {
|
||||
//RTTY_SET(1);
|
||||
port_pin_set_output_level(SI406X_GPIO1_PIN, 1);
|
||||
if ((ARRAY_DBUFFER_READ_PTR(&rtty_dbuffer_string)[rtty_index] >> (rtty_phase - 1)) & 1) {
|
||||
RTTY_SET(1);
|
||||
} else {
|
||||
//RTTY_SET(0);
|
||||
port_pin_set_output_level(SI406X_GPIO1_PIN, 0);
|
||||
RTTY_SET(0);
|
||||
}
|
||||
} else if (rtty_phase < BITS_PER_CHAR) { // Stop
|
||||
// High
|
||||
//RTTY_SET(1);
|
||||
port_pin_set_output_level(SI406X_GPIO1_PIN, 1);
|
||||
RTTY_SET(1);
|
||||
}
|
||||
|
||||
rtty_phase++;
|
||||
|
@ -133,7 +134,7 @@ void rtty_tick(void) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// RTTY_DEACTIVATE();
|
||||
RTTY_DEACTIVATE();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -362,7 +362,7 @@ float si4060_get_temperature(void)
|
|||
spi_select();
|
||||
spi_write(CMD_GET_ADC_READING);
|
||||
spi_write(0x10); /* Temperature */
|
||||
spi_write((0xC << 4) | 0); /* UDTIME = 0xC, Att = 0 */
|
||||
spi_write(0); /* ADC_CFG = 0 */
|
||||
spi_deselect();
|
||||
|
||||
/* do not deselect after reading CTS */
|
||||
|
@ -377,12 +377,15 @@ float si4060_get_temperature(void)
|
|||
spi_read(); spi_read();
|
||||
|
||||
/* Battery */
|
||||
result = (spi_read() & 0x7) << 8;
|
||||
result |= spi_read() & 0xFF;
|
||||
spi_read(); spi_read();
|
||||
|
||||
/* Temperature */
|
||||
result = (spi_read() & 0xFF) << 8;
|
||||
result |= (spi_read() & 0xFF);
|
||||
|
||||
spi_deselect();
|
||||
|
||||
return ((((float)result) * 568.0) / 2560.0) - 297.0;
|
||||
return (((float)result * 568.0) / 2560.0) - 297.0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -165,6 +165,6 @@ void wdt_reset_count(void)
|
|||
|
||||
WDT_WAIT_FOR_SYNC(hw);
|
||||
|
||||
/* Disable the Watchdog module */
|
||||
/* Reset the Watchdog module */
|
||||
hw->CLEAR.reg = WDT_CLEAR_CLEAR_KEY;
|
||||
}
|
||||
|
|
|
@ -26,16 +26,10 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "samd20.h"
|
||||
#include "semihosting.h"
|
||||
#include "analogue.h"
|
||||
#include "gps.h"
|
||||
#include "rtty.h"
|
||||
#include "ubx_messages.h"
|
||||
#include "si4060.h"
|
||||
#include "system/gclk.h"
|
||||
#include "system/interrupt.h"
|
||||
#include "tc/tc_driver.h"
|
||||
|
||||
//#define SEMIHOST_LOG
|
||||
|
||||
char telemetry_string[0x200];
|
||||
|
||||
/**
|
||||
* CRC Function for the XMODEM protocol.
|
||||
|
@ -77,52 +71,46 @@ uint16_t crc_checksum(char *string)
|
|||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets output telemetry
|
||||
* Initialises a timer interupt at the given frequency
|
||||
*/
|
||||
void set_telemetry_string(void)
|
||||
void timer0_tick_init(uint32_t frequency)
|
||||
{
|
||||
double lat_fmt = 0.0;
|
||||
double lon_fmt = 0.0;
|
||||
uint32_t altitude = 0;
|
||||
/* Calculate the wrap value for the given frequency */
|
||||
uint32_t gclk0_frequency = system_gclk_chan_get_hz(0);
|
||||
uint32_t count = gclk0_frequency / frequency;
|
||||
|
||||
/* Analogue */
|
||||
float battery = get_battery();
|
||||
/* Configure Timer 0 */
|
||||
bool t0_capture_channel_enables[] = {false, false};
|
||||
uint32_t t0_compare_channel_values[] = {count, 0x0000};
|
||||
tc_init(TC0,
|
||||
GCLK_GENERATOR_0,
|
||||
TC_COUNTER_SIZE_32BIT,
|
||||
TC_CLOCK_PRESCALER_DIV1,
|
||||
TC_WAVE_GENERATION_MATCH_FREQ,
|
||||
TC_RELOAD_ACTION_GCLK,
|
||||
TC_COUNT_DIRECTION_UP,
|
||||
TC_WAVEFORM_INVERT_OUTPUT_NONE,
|
||||
false, /* Oneshot */
|
||||
true, /* Run in standby */
|
||||
0x0000, /* Initial value */
|
||||
count, /* Top value */
|
||||
t0_capture_channel_enables, /* Capture Channel Enables */
|
||||
t0_compare_channel_values); /* Compare Channels Values */
|
||||
|
||||
/* 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;
|
||||
/* Enable Events */
|
||||
struct tc_events event;
|
||||
memset(&event, 0, sizeof(struct tc_events));
|
||||
event.generate_event_on_compare_channel[0] = true;
|
||||
event.event_action = TC_EVENT_ACTION_RETRIGGER;
|
||||
tc_enable_events(TC0, &event);
|
||||
|
||||
/* GPS Status */
|
||||
struct ubx_nav_sol sol = gps_get_nav_sol();
|
||||
uint8_t lock = sol.payload.gpsFix;
|
||||
uint8_t satillite_count = sol.payload.numSV;
|
||||
/* Enable Interrupt */
|
||||
TC0->COUNT32.INTENSET.reg = (1 << 4);
|
||||
irq_register_handler(TC0_IRQn, 0); /* Highest Priority */
|
||||
|
||||
/* GPS Position */
|
||||
if (lock == 0x2 || lock == 0x3 || lock == 0x4) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//#ifdef SEMIHOST_LOG
|
||||
// semihost_printf("Batt %f, Temp %f\n", battery, temperature);
|
||||
// semihost_printf("%02.7f,%03.7f,%ld\n", lat_fmt, lon_fmt, altitude);
|
||||
// semihost_printf("Lock: %d Sats: %d\n", lock, satillite_count);
|
||||
// semihost_printf("%02u:%02u:%02u\n", hours, minutes, seconds);
|
||||
//#endif
|
||||
|
||||
/* sprintf */
|
||||
uint16_t len = sprintf(telemetry_string,
|
||||
"$$UBSEDS2,%02u:%02u:%02u,%02.6f,%03.6f,%ld,%u,%.2f",
|
||||
hours, minutes, seconds, lat_fmt, lon_fmt, altitude,
|
||||
satillite_count, battery);
|
||||
|
||||
sprintf(telemetry_string + len, "*%04X\n", crc_checksum(telemetry_string));
|
||||
|
||||
rtty_set_string(telemetry_string, strlen(telemetry_string));
|
||||
/* Enable Timer */
|
||||
tc_enable(TC0);
|
||||
tc_start_counter(TC0);
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue