2010-06-07 11:45:35 +00:00
|
|
|
/* hadie - High Altitude Balloon flight software */
|
|
|
|
/*============================================================*/
|
|
|
|
/* Copyright (C)2010 Philip Heron <phil@sanslogic.co.uk> */
|
|
|
|
/* */
|
|
|
|
/* This program is distributed under the terms of the GNU */
|
|
|
|
/* General Public License, version 2. You may use, modify, */
|
|
|
|
/* and redistribute it under the terms of this license. A */
|
|
|
|
/* copy should be included with this source. */
|
|
|
|
|
2010-06-07 12:10:32 +00:00
|
|
|
#include "config.h"
|
2010-07-06 11:16:42 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2010-06-08 10:45:12 +00:00
|
|
|
#include <util/delay.h>
|
2010-06-09 15:32:22 +00:00
|
|
|
#include <util/crc16.h>
|
2010-06-07 11:45:35 +00:00
|
|
|
#include <avr/interrupt.h>
|
2010-06-08 10:19:37 +00:00
|
|
|
#include "rtty.h"
|
2010-08-03 22:42:15 +00:00
|
|
|
#include "gps.h"
|
2010-07-06 11:16:42 +00:00
|
|
|
#include "c328.h"
|
2010-06-07 11:45:35 +00:00
|
|
|
#include "rs8.h"
|
2010-09-30 22:28:13 +00:00
|
|
|
#include "ssdv.h"
|
2010-06-07 11:45:35 +00:00
|
|
|
|
2010-07-06 11:16:42 +00:00
|
|
|
/* Message buffer */
|
|
|
|
#define MSG_SIZE (100)
|
|
|
|
char msg[MSG_SIZE];
|
|
|
|
|
2010-10-12 10:43:18 +00:00
|
|
|
#define PREFIX "$$"
|
2010-08-03 22:42:15 +00:00
|
|
|
|
2010-07-06 11:16:42 +00:00
|
|
|
/* Image TX data */
|
2010-09-30 22:28:13 +00:00
|
|
|
uint8_t pkt[SSDV_PKT_SIZE], img[64];
|
2010-07-06 11:16:42 +00:00
|
|
|
|
2010-10-12 12:14:05 +00:00
|
|
|
/* State of the flight */
|
|
|
|
#define ALT_STEP (200)
|
|
|
|
static int32_t r_altitude = 0; /* Reference altitude */
|
|
|
|
static char ascent = 1; /* Direction of travel. 0 = Down, 1 = Up */
|
|
|
|
|
2010-07-06 11:16:42 +00:00
|
|
|
char tx_image(void)
|
2010-06-09 15:32:22 +00:00
|
|
|
{
|
2010-07-06 11:16:42 +00:00
|
|
|
static char setup = 0;
|
|
|
|
static uint8_t img_id = 0;
|
2010-09-30 22:28:13 +00:00
|
|
|
static ssdv_t ssdv;
|
|
|
|
int r;
|
2010-06-09 15:32:22 +00:00
|
|
|
|
2010-07-06 11:16:42 +00:00
|
|
|
if(!setup)
|
|
|
|
{
|
2010-10-12 12:14:05 +00:00
|
|
|
/* Don't begin transmitting a new image if the payload is falling */
|
|
|
|
if(ascent == 0) return(setup);
|
|
|
|
|
2010-08-07 17:38:09 +00:00
|
|
|
if(c3_open(SR_320x240) != 0)
|
|
|
|
{
|
|
|
|
rtx_string_P(PSTR(PREFIX CALLSIGN ":Camera error\n"));
|
|
|
|
return(setup);
|
|
|
|
}
|
|
|
|
|
2010-08-07 15:58:06 +00:00
|
|
|
setup = -1;
|
|
|
|
|
2012-03-04 23:36:37 +00:00
|
|
|
ssdv_enc_init(&ssdv, CALLSIGN, img_id++);
|
2010-09-30 22:28:13 +00:00
|
|
|
ssdv_enc_set_buffer(&ssdv, pkt);
|
2010-07-06 11:16:42 +00:00
|
|
|
}
|
|
|
|
|
2010-09-30 22:28:13 +00:00
|
|
|
while((r = ssdv_enc_get_packet(&ssdv)) == SSDV_FEED_ME)
|
|
|
|
{
|
|
|
|
size_t r = c3_read(img, 64);
|
|
|
|
if(r == 0) break;
|
|
|
|
ssdv_enc_feed(&ssdv, img, r);
|
|
|
|
}
|
2010-06-09 15:32:22 +00:00
|
|
|
|
2010-09-30 22:28:13 +00:00
|
|
|
if(r != SSDV_OK)
|
2010-08-07 17:38:09 +00:00
|
|
|
{
|
2010-09-30 22:28:13 +00:00
|
|
|
/* Something went wrong! */
|
2010-08-07 17:38:09 +00:00
|
|
|
c3_close();
|
|
|
|
setup = 0;
|
2010-09-30 22:28:13 +00:00
|
|
|
rtx_string_P(PSTR(PREFIX CALLSIGN ":ssdv_enc_get_packet() failed\n"));
|
2010-08-07 17:38:09 +00:00
|
|
|
return(setup);
|
|
|
|
}
|
2010-08-07 15:58:06 +00:00
|
|
|
|
2010-10-04 18:56:10 +00:00
|
|
|
if(ssdv.state == S_EOI || c3_eof())
|
2010-07-06 11:16:42 +00:00
|
|
|
{
|
2010-09-30 22:28:13 +00:00
|
|
|
/* The end of the image has been reached */
|
2010-08-07 15:58:06 +00:00
|
|
|
c3_close();
|
|
|
|
setup = 0;
|
2010-07-06 11:16:42 +00:00
|
|
|
}
|
|
|
|
|
2010-09-30 22:28:13 +00:00
|
|
|
/* Got the packet! Transmit it */
|
|
|
|
rtx_data(pkt, SSDV_PKT_SIZE);
|
2010-08-03 22:42:15 +00:00
|
|
|
|
|
|
|
return(setup);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t crccat(char *msg)
|
|
|
|
{
|
|
|
|
uint16_t x;
|
|
|
|
for(x = 0xFFFF; *msg; msg++)
|
|
|
|
x = _crc_xmodem_update(x, *msg);
|
|
|
|
snprintf(msg, 8, "*%04X\n", x);
|
|
|
|
return(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
char tx_telemetry(void)
|
|
|
|
{
|
|
|
|
static unsigned int counter = 0;
|
|
|
|
gpsfix_t gps;
|
|
|
|
|
|
|
|
/* Read the GPS data */
|
|
|
|
gps_parse(&gps);
|
|
|
|
|
|
|
|
rtx_wait();
|
|
|
|
snprintf(msg, MSG_SIZE,
|
2010-10-27 18:22:54 +00:00
|
|
|
PREFIX CALLSIGN ",%u,%02i:%02i:%02i,%s%i.%06lu,%s%i.%06lu,%li,%i,%i,?",
|
2010-08-03 22:42:15 +00:00
|
|
|
counter++,
|
|
|
|
gps.hour, gps.minute, gps.second,
|
2010-08-05 21:25:15 +00:00
|
|
|
(gps.latitude_h == 'S' ? "-" : ""),
|
2010-08-03 22:42:15 +00:00
|
|
|
gps.latitude_i, gps.latitude_f,
|
2010-08-05 21:25:15 +00:00
|
|
|
(gps.longitude_h == 'W' ? "-" : ""),
|
2010-08-03 22:42:15 +00:00
|
|
|
gps.longitude_i, gps.longitude_f,
|
|
|
|
gps.altitude, gps.fix, gps.sats);
|
|
|
|
|
2010-10-12 10:43:18 +00:00
|
|
|
/* Append the checksum, skipping the $$ prefix */
|
|
|
|
crccat(msg + 2);
|
2010-08-03 22:42:15 +00:00
|
|
|
|
|
|
|
/* Begin transmitting */
|
|
|
|
rtx_string(msg);
|
2010-07-06 11:16:42 +00:00
|
|
|
|
2010-10-12 12:14:05 +00:00
|
|
|
/* Update the ascent / descent status */
|
|
|
|
if(gps.fix > 0)
|
|
|
|
{
|
|
|
|
int32_t i = ascent;
|
|
|
|
|
|
|
|
if(gps.altitude >= r_altitude + ALT_STEP)
|
|
|
|
{
|
|
|
|
/* Payload is rising */
|
|
|
|
ascent = 1;
|
|
|
|
r_altitude = gps.altitude;
|
|
|
|
}
|
|
|
|
else if(gps.altitude <= r_altitude - ALT_STEP)
|
|
|
|
{
|
|
|
|
/* Payload is falling */
|
|
|
|
ascent = 0;
|
|
|
|
r_altitude = gps.altitude;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If staring to fall above 4000 metres... */
|
|
|
|
if(gps.altitude >= 4000 && i == 1 && ascent == 0)
|
|
|
|
rtx_string_P(PSTR(PREFIX CALLSIGN ":Geronimo!!!!\n"));
|
|
|
|
}
|
|
|
|
|
2010-07-06 11:16:42 +00:00
|
|
|
return(0);
|
2010-06-09 15:32:22 +00:00
|
|
|
}
|
|
|
|
|
2010-06-07 11:45:35 +00:00
|
|
|
int main(void)
|
|
|
|
{
|
2010-08-03 22:42:15 +00:00
|
|
|
char r;
|
|
|
|
|
2010-07-06 11:16:42 +00:00
|
|
|
/* Initalise the various bits */
|
2010-06-08 10:19:37 +00:00
|
|
|
rtx_init();
|
2010-08-03 22:42:15 +00:00
|
|
|
gps_init();
|
2010-07-06 11:16:42 +00:00
|
|
|
c3_init();
|
|
|
|
|
2011-12-29 19:33:13 +00:00
|
|
|
/* Turn on the radio and let it settle before beginning */
|
|
|
|
rtx_enable(1);
|
2010-06-08 10:45:12 +00:00
|
|
|
_delay_ms(2000);
|
|
|
|
|
2010-07-06 11:16:42 +00:00
|
|
|
/* Start interrupts and enter the main loop */
|
2010-06-07 11:45:35 +00:00
|
|
|
sei();
|
2010-06-08 10:45:12 +00:00
|
|
|
|
2010-06-07 11:45:35 +00:00
|
|
|
while(1)
|
|
|
|
{
|
2010-08-03 22:42:15 +00:00
|
|
|
if(tx_image() == -1)
|
|
|
|
{
|
|
|
|
/* The camera goes to sleep while transmitting telemetry,
|
|
|
|
* sync'ing here seems to prevent it. */
|
|
|
|
c3_sync();
|
2011-01-08 17:06:05 +00:00
|
|
|
rtx_string_P(PSTR("\n"));
|
2010-08-03 22:42:15 +00:00
|
|
|
r = 1;
|
|
|
|
}
|
2011-01-08 17:06:05 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Put UBLOX5 GPS in proper nav mode */
|
|
|
|
if(gps_ubx_init() != 0)
|
|
|
|
rtx_string_P(PSTR(PREFIX CALLSIGN ":GPS mode set failed\n"));
|
|
|
|
|
|
|
|
r = 10;
|
|
|
|
}
|
2010-08-03 22:42:15 +00:00
|
|
|
|
|
|
|
for(; r > 0; r--) tx_telemetry();
|
2010-06-07 11:45:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|