Generates RTTY from a GPS receiver
Dependencies: mbed-dsp mbed-rtos mbed
Revision 0:dbb85bfd22fd, committed 2014-01-11
- Comitter:
- adwiens
- Date:
- Sat Jan 11 01:55:42 2014 +0000
- Child:
- 1:07d7070e9252
- Commit message:
- First commit
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Sat Jan 11 01:55:42 2014 +0000
@@ -0,0 +1,177 @@
+#include "mbed.h"
+#include "rtos.h" // mbed real time os library
+#include "dsp.h" // mbed digital signal processing library
+#include <cstring>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <map>
+
+#define GPS_CB_SIZE (16) /* size of gps circular buffer in characters */
+#define GPS_BAUD (9600) /* gps serial port speed in bps */
+#define RADIO_TX_WAIT (2000) /* time between radio transmissions in ms */
+#define RADIO_KEYUP_DELAY (1000) /* time to wait for radio transmitter to turn on */
+#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 AUDIO_VOL (0.25) /* range 0-1 */
+
+using namespace std;
+
+Serial pc(USBTX, USBRX); // pc serial port (via usb)
+
+// 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
+DigitalOut gps_led(LED1); // gps status led
+Serial gps(p9, p10); // gps serial port (uart3)
+stringstream rxbuf; // gps receive buffer
+map<string,string> nmea_data; // most recent nmea sentences
+Mutex nmea_data_mutex; // nmea data lock
+
+// 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
+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.
+// 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()
+{
+ cb[cb_isr_i] = LPC_UART3->RBR; // avoid mutex lockup (https://mbed.org/forum/bugs-suggestions/topic/4217/)
+ if(++cb_isr_i >= GPS_CB_SIZE) cb_isr_i = 0; // loop circular buffer index
+}
+
+// This function 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
+// this function updates a map containing K,V pairs. (The sentence
+// type is the key and the value is the NMEA sentence.)
+void gps_rx_thread(void const *argument)
+{
+ while(1) {
+ gps_led = 0;
+ Thread::wait((GPS_CB_SIZE)*1000*8/4/GPS_BAUD); // wait until cb 25% full
+ gps_led = 1;
+ while(cb_thr_i != cb_isr_i) {
+ char c = cb[cb_thr_i];
+ rxbuf << c; // add to string buffer
+ if(c == '\n') { // clear string buffer
+ const char *c = rxbuf.str().c_str();
+ const char *l = strchr(c, '$'), *r = strchr(c, ',');
+ if(l != NULL && r != NULL && r > l) { // check valid limits
+ char ctype[6];
+ memcpy(ctype,l+1,5);
+ ctype[5] = 0;
+ string type = ctype;
+ nmea_data_mutex.lock();
+ nmea_data[type] = rxbuf.str(); // update map
+ nmea_data_mutex.unlock();
+ }
+ rxbuf.str("");
+ rxbuf.clear();
+ }
+ if(++cb_thr_i >= GPS_CB_SIZE) cb_thr_i = 0; // loop circular buffer index
+ }
+ }
+}
+
+// This function writes individual audio samples to the dac.
+void rtty_sample_tick()
+{
+ 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
+ {
+ 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
+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;
+ ++bitn;
+ }
+ }
+}
+
+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();
+ 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;
+ }
+}
+
+void print_nmea_data() // useful for debug
+{
+ 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;
+}
+
+int main()
+{
+ Ticker sample_tick, bit_tick;
+ Thread gps_thread(gps_rx_thread); // gps receive thread
+ Thread rtty_thread(rtty_tx_thread); // rtty transmit 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
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-dsp.lib Sat Jan 11 01:55:42 2014 +0000 @@ -0,0 +1,1 @@ +https://mbed.org/users/mbed_official/code/mbed-dsp/#7a284390b0ce
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-rtos.lib Sat Jan 11 01:55:42 2014 +0000 @@ -0,0 +1,1 @@ +https://mbed.org/users/mbed_official/code/mbed-rtos/#29007aef10a4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Sat Jan 11 01:55:42 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f \ No newline at end of file