Generates RTTY from a GPS receiver
Dependencies: mbed-dsp mbed-rtos mbed
Diff: main.cpp
- Revision:
- 1:07d7070e9252
- Parent:
- 0:dbb85bfd22fd
- Child:
- 2:1f19f8e52c75
--- a/main.cpp Sat Jan 11 01:55:42 2014 +0000 +++ b/main.cpp Sat Jan 11 05:46:49 2014 +0000 @@ -8,14 +8,17 @@ #include <map> #define GPS_CB_SIZE (16) /* size of gps circular buffer in characters */ +#define RTTY_CB_SIZE (2048) /* characters in rtty buffer */ #define GPS_BAUD (9600) /* gps serial port speed in bps */ -#define RADIO_TX_WAIT (2000) /* time between radio transmissions in ms */ +#define RADIO_TX_WAIT (20000) /* time between radio transmissions in ms */ #define RADIO_KEYUP_DELAY (1000) /* time to wait for radio transmitter to turn on */ +#define PRINT_NMEA_WAIT (2000) /* time between console debug messages */ #define AUDIO_FS (22050) /* audio sample rate in hz */ #define RTTY_BAUD (45.45) /* rtty bit rate in bps */ -#define MARK_FREQ (2125) /* mark frequency (1) in hz */ -#define SPACE_FREQ (2295) /* space frequency (0) in hz */ +#define MARK_FREQ (2295) /* mark frequency (1) in hz */ +#define SPACE_FREQ (2125) /* space frequency (0) in hz */ #define AUDIO_VOL (0.25) /* range 0-1 */ +#define RTTY_NUM_ZEROS (3) /* number of empty characters to append before each rtty message */ using namespace std; @@ -23,8 +26,8 @@ // GPS variables: char cb[GPS_CB_SIZE]; // c-string circular buffer for gps rx isr -int cb_isr_i = 0; // isr index -int cb_thr_i = 0; // thread index +int cb_isr_i = 0; // gps isr index +int cb_thr_i = 0; // gps thread index DigitalOut gps_led(LED1); // gps status led Serial gps(p9, p10); // gps serial port (uart3) stringstream rxbuf; // gps receive buffer @@ -34,16 +37,16 @@ // RTTY variables: AnalogOut dac(p18); // mbed built-in digital to analog converter DigitalOut ptt(p17); // radio push to talk button -DigitalOut tx_led(LED2); // tx status led -stringstream txbuf; // rtty tx buffer -string txbufstr; -const char *txchar = NULL; // current character to transmit +DigitalOut rtty_led(LED2); // tx status led +char r_cb[RTTY_CB_SIZE]; // c-string circular buffer for rtty tx isr +int r_cb_isr_i = 0; // rtty isr index +int r_cb_thr_i = 0; // rtty thread index float angle = 0.0; // current sine angle int ifreq = MARK_FREQ; // instantaneous frequency int bitn = -1; // current bit number bool txen = false; // tx enable flag -// This function is the interrupt service routine for the gps. +// Interrupt service routine for the gps. // It is called when the serial port receives a character, // and it puts the character into a circular buffer for the gps thread. void gps_rx_isr() @@ -52,7 +55,7 @@ if(++cb_isr_i >= GPS_CB_SIZE) cb_isr_i = 0; // loop circular buffer index } -// This function reads new characters from the gps circular +// Reads new characters from the gps circular // buffer when the circular buffer is about 25 percent full // and adds the new characters to a string containing the current // nmea sentence. Each time a complete NMEA sentence is received @@ -82,83 +85,84 @@ rxbuf.str(""); rxbuf.clear(); } - if(++cb_thr_i >= GPS_CB_SIZE) cb_thr_i = 0; // loop circular buffer index + if(++cb_thr_i >= GPS_CB_SIZE) cb_thr_i = 0; // incr/loop circular buffer index } } } -// This function writes individual audio samples to the dac. +// Writes individual audio samples to the dac. It uses the +// instantaneous frequency from the bit ticker. void rtty_sample_tick() { - if(txen) - { + if(txen) { angle += 2 * PI * ifreq / AUDIO_FS; if(angle > 2 * PI) angle -= 2*PI; dac = (arm_sin_f32(angle) + 1.0) / 2.0 * AUDIO_VOL; // write sample to dac - } - else - { + } else { dac = 0; } } -// This function controls whether the current rtty bit is a mark or a space. -// Format is 1 start bit, 1 stop bit, 8 bit ascii +// Handles whether the current rtty bit is a mark or a space. +// It reads one character at a time from the rtty circular buffer and sets +// the instantaneous frequency of the sample ticker for each bit. (1==mark, +// 0==space.) void rtty_bit_tick() { - if(txen) { - if(bitn < 0) { - ifreq = SPACE_FREQ; // start bit (space/0) - ++bitn; - } else if(bitn > 7) { - ifreq = MARK_FREQ; // stop bit (mark/1) - bitn = -1; - if(txchar != NULL && *txchar != NULL) - ++txchar; // go to next character - } else { // data bit - if(txchar != NULL && *txchar != NULL) - ifreq = ((*txchar & (1<<bitn)) == 0) ? SPACE_FREQ : MARK_FREQ; - else - ifreq = MARK_FREQ; + if(bitn < 0) { + txen = (r_cb_isr_i != r_cb_thr_i); + if(txen) { + ifreq = SPACE_FREQ; // start bit + if(++r_cb_isr_i >= RTTY_CB_SIZE) r_cb_isr_i = 0; // incr/loop circular buffer index ++bitn; } + } else if(bitn < 8 && txen) { + ifreq = ((r_cb[r_cb_isr_i] & (1<<(bitn++))) == 0) ? SPACE_FREQ : MARK_FREQ; // data bit + } else if(txen) { + ifreq = MARK_FREQ; // stop bit + bitn = -1; } } +// Adds NMEA sentences periodically to a buffer for the other RTTY +// functions to process. void rtty_tx_thread(void const *argument) { while(1) { - txen = false; - ptt = 1; // turn off transmitter - tx_led = 0; Thread::wait(RADIO_TX_WAIT); // wait for a certain amount of time between transmissions - txbuf.str(""); // empty tx buffer - txbuf.clear(); + stringstream txbuf; nmea_data_mutex.lock(); for (map<string,string>::iterator iter = nmea_data.begin(); iter != nmea_data.end(); ++iter) { txbuf << (iter->second); // fill the packet with the most recent nmea sentences } nmea_data_mutex.unlock(); - txbufstr = txbuf.str(); - txchar = txbufstr.c_str(); - ptt = 0; // key up the radio - tx_led = 1; - txen = true; - Thread::wait(RADIO_KEYUP_DELAY); // wait for radio to key up - while(txchar != NULL && *txchar != NULL); // wait for rtty to finish - Thread::wait(RADIO_KEYUP_DELAY); - txen = false; + for(int i = 0; i < RTTY_NUM_ZEROS; ++i) { + if(++r_cb_thr_i >= RTTY_CB_SIZE) r_cb_thr_i = 0; // incr/loop circular buffer index + r_cb[r_cb_thr_i] = 0; // append a zero + } + for(const char* it = txbuf.str().c_str(); *it; ++it) { // add all characters to buffer + if(++r_cb_thr_i >= RTTY_CB_SIZE) r_cb_thr_i = 0; // incr/loop circular buffer index + r_cb[r_cb_thr_i] = *it; + } + for(int i = 0; i < RTTY_NUM_ZEROS; ++i) { + if(++r_cb_thr_i >= RTTY_CB_SIZE) r_cb_thr_i = 0; // incr/loop circular buffer index + r_cb[r_cb_thr_i] = 0; // append a zero + } } } -void print_nmea_data() // useful for debug +// Writes debug messages periodically to the console. Useful for debug. +void print_nmea_thread(void const *argument) { - nmea_data_mutex.lock(); - for (map<string,string>::iterator iter = nmea_data.begin(); iter != nmea_data.end(); ++iter) { - cout << (iter->second); + while(1) { + nmea_data_mutex.lock(); + for (map<string,string>::iterator iter = nmea_data.begin(); iter != nmea_data.end(); ++iter) { + cout << (iter->second); + } + nmea_data_mutex.unlock(); + cout << endl; + Thread::wait(PRINT_NMEA_WAIT); } - nmea_data_mutex.unlock(); - cout << endl; } int main() @@ -166,12 +170,10 @@ Ticker sample_tick, bit_tick; Thread gps_thread(gps_rx_thread); // gps receive thread Thread rtty_thread(rtty_tx_thread); // rtty transmit thread + Thread print_thread(print_nmea_thread); // debug print thread gps.baud(GPS_BAUD); // set gps bit rate gps.attach(&gps_rx_isr); // set up gps receive interrupt service routine sample_tick.attach_us(&rtty_sample_tick,1000000/AUDIO_FS); // begin generating audio bit_tick.attach_us(&rtty_bit_tick,1000000/RTTY_BAUD); // begin sending characters - while(1) { - Thread::wait(2000); - print_nmea_data(); // debug - } + while(1); // idle forever }