altos: Hook APRS up to the radio
authorKeith Packard <keithp@keithp.com>
Thu, 6 Dec 2012 18:12:11 +0000 (10:12 -0800)
committerKeith Packard <keithp@keithp.com>
Thu, 6 Dec 2012 18:12:11 +0000 (10:12 -0800)
This adds an arbitrary-length packet writing function to the radio
code.

Signed-off-by: Keith Packard <keithp@keithp.com>
src/core/ao.h
src/drivers/ao_aprs.c
src/drivers/ao_cc1120.c
src/megametrum-v0.1/Makefile
src/test/ao_aprs_test.c

index 54018b371a058d60ba888b8020c45bbbda41d70f..d6e27707d7137e7d9077ee6c887bdcad2af48648 100644 (file)
@@ -529,6 +529,11 @@ ao_radio_recv_abort(void);
 void
 ao_radio_test(uint8_t on);
 
+typedef int16_t (*ao_radio_fill_func)(uint8_t *buffer, int16_t len);
+
+void
+ao_radio_send_lots(ao_radio_fill_func fill);
+
 /*
  * Compute the packet length as follows:
  *
index 1a074ba516fed78c691d3fc01d629cc60e8cf754..e273908f50e513b956096a602b4c2630e8339607 100644 (file)
 
 #include <ao_aprs.h>
 
-typedef int bool_t;
-typedef int32_t int32;
-#define false 0
-#define true 1
-
 // Public methods, constants, and data structures for each class.
 
 static void timeInit(void);
@@ -285,9 +280,6 @@ static uint8_t tncLength;
 /// A copy of the last 5 bits we've transmitted to determine if we need to bit stuff on the next bit.
 static uint8_t tncBitStuff;
 
-/// Pointer to TNC buffer as we save each byte during message preparation.
-static uint8_t *tncBufferPnt;
-
 /// Buffer to hold the message portion of the AX.25 packet as we prepare it.
 static uint8_t tncBuffer[TNC_BUFFER_SIZE];
 
@@ -471,18 +463,18 @@ static void tnc1200TimerTick()
 /**
  *   Generate the plain text position packet.
  */
-static void tncPositionPacket(void)
+static int tncPositionPacket(void)
 {
-    int32_t    latitude = 45.4694766 * 10000000;
-    int32_t    longitude = -122.7376250 * 10000000;
-    uint32_t   altitude = 10000;
+    int32_t    latitude = ao_gps_data.latitude;
+    int32_t    longitude = ao_gps_data.longitude;
+    int32_t    altitude = ao_gps_data.altitude;
+
     uint16_t   lat_deg;
     uint16_t   lon_deg;
     uint16_t   lat_min;
     uint16_t   lat_frac;
     uint16_t   lon_min;
     uint16_t   lon_frac;
-    int                c;
 
     char       lat_sign = 'N', lon_sign = 'E';
 
@@ -510,12 +502,15 @@ static void tncPositionPacket(void)
     longitude -= lon_min * 10000000;
     lon_frac = (longitude + 50000) / 100000;
 
-    c = sprintf ((char *) tncBufferPnt, "=%02u%02u.%02u%c\\%03u%02u.%02u%cO /A=%06u\015",
-               lat_deg, lat_min, lat_frac, lat_sign,
-               lon_deg, lon_min, lon_frac, lon_sign,
-               altitude * 100 / 3048);
-    tncBufferPnt += c;
-    tncLength += c;
+    if (altitude < 0)
+       altitude = 0;
+
+    altitude = altitude * (int32_t) 1000 / (int32_t) 3048;
+    
+    return sprintf ((char *) tncBuffer, "=%02u%02u.%02u%c\\%03u%02u.%02u%cO /A=%06u\015",
+                   lat_deg, lat_min, lat_frac, lat_sign,
+                   lon_deg, lon_min, lon_frac, lon_sign,
+                   altitude);
 }
 
 static int16_t
@@ -553,24 +548,15 @@ void ao_aprs_send(void)
     timeInit();
     tncInit();
 
-    // Set a pointer to our TNC output buffer.
-    tncBufferPnt = tncBuffer;
-
-    // Set the message length counter.
-    tncLength = 0;
-
-    tncPositionPacket();
+    tncLength = tncPositionPacket();
 
     // Calculate the CRC for the header and message.
     crc = sysCRC16(TNC_AX25_HEADER, sizeof(TNC_AX25_HEADER), 0xffff);
     crc = sysCRC16(tncBuffer, tncLength, crc ^ 0xffff);
 
     // Save the CRC in the message.
-    *tncBufferPnt++ = crc & 0xff;
-    *tncBufferPnt = (crc >> 8) & 0xff;
-
-    // Update the length to include the CRC bytes.
-    tncLength += 2;
+    tncBuffer[tncLength++] = crc & 0xff;
+    tncBuffer[tncLength++] = (crc >> 8) & 0xff;
 
     // Prepare the variables that are used in the real-time clock interrupt.
     tncBitCount = 0;
index f27958f96ae397776248f17a64f1f687da780b0b..ed26e28d3fbea55b4a25c91767b8ab09793bc8a7 100644 (file)
@@ -323,12 +323,12 @@ static const uint16_t packet_rx_setup[] = {
 /*
  * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone)
  *
- *              (2**20 - DATARATE_M) * 2 ** DATARATE_E
+ *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
  *     Rdata = -------------------------------------- * fosc
  *                          2 ** 39
  *
- *     DATARATE_M = 511705
- *     DATARATE_E = 6
+ *     DATARATE_M = 25166
+ *     DATARATE_E = 5
  *
  * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes
  */
@@ -358,7 +358,64 @@ static const uint16_t rdf_setup[] = {
                                 (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
 };
 
-static uint8_t ao_radio_mode;
+/*
+ * APRS deviation is 5kHz
+ *
+ *     fdev = fosc >> 24 * (256 + dev_m) << dev_e
+ *
+ *             32e6Hz / (2 ** 24) * (256 + 71) * (2 ** 3) = 4989
+ */
+
+#define APRS_DEV_E     3
+#define APRS_DEV_M     71
+#define APRS_PACKET_LEN        50
+
+/*
+ * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate)
+ *
+ *              (2**20 + DATARATE_M) * 2 ** DATARATE_E
+ *     Rdata = -------------------------------------- * fosc
+ *                          2 ** 39
+ *
+ *     DATARATE_M = 239914
+ *     DATARATE_E = 7
+ *
+ *     Rdata = 9599.998593330383301
+ *
+ */
+#define APRS_DRATE_E   5
+#define APRS_DRATE_M   25166
+
+static const uint16_t aprs_setup[] = {
+       CC1120_DEVIATION_M,     APRS_DEV_M,
+       CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
+                                (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
+                                (APRS_DEV_E << CC1120_MODCFG_DEV_E_DEV_E)),
+       CC1120_DRATE2,          ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
+                                (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
+       CC1120_DRATE1,          ((APRS_DRATE_M >> 8) & 0xff),
+       CC1120_DRATE0,          ((APRS_DRATE_M >> 0) & 0xff),
+       CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
+                                (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
+       CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
+                                (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
+                                (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
+                                (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
+};
+
+#define AO_PKT_CFG0_INFINITE ((0 << CC1120_PKT_CFG0_RESERVED7) |       \
+                             (CC1120_PKT_CFG0_LENGTH_CONFIG_INFINITE << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
+                             (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |      \
+                             (0 << CC1120_PKT_CFG0_UART_MODE_EN) |     \
+                             (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
+
+#define AO_PKT_CFG0_FIXED ((0 << CC1120_PKT_CFG0_RESERVED7) |          \
+                          (CC1120_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1120_PKT_CFG0_LENGTH_CONFIG) | \
+                          (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |         \
+                          (0 << CC1120_PKT_CFG0_UART_MODE_EN) |        \
+                          (0 << CC1120_PKT_CFG0_UART_SWAP_EN))
+
+static uint16_t ao_radio_mode;
 
 #define AO_RADIO_MODE_BITS_PACKET      1
 #define AO_RADIO_MODE_BITS_PACKET_TX   2
@@ -366,17 +423,22 @@ static uint8_t ao_radio_mode;
 #define AO_RADIO_MODE_BITS_TX_FINISH   8
 #define AO_RADIO_MODE_BITS_PACKET_RX   16
 #define AO_RADIO_MODE_BITS_RDF         32
+#define AO_RADIO_MODE_BITS_APRS                64
+#define AO_RADIO_MODE_BITS_INFINITE    128
+#define AO_RADIO_MODE_BITS_FIXED       256
 
 #define AO_RADIO_MODE_NONE             0
 #define AO_RADIO_MODE_PACKET_TX_BUF    (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)
 #define AO_RADIO_MODE_PACKET_TX_FINISH (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_FINISH)
 #define AO_RADIO_MODE_PACKET_RX                (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_RX)
 #define AO_RADIO_MODE_RDF              (AO_RADIO_MODE_BITS_RDF | AO_RADIO_MODE_BITS_TX_FINISH)
+#define AO_RADIO_MODE_APRS_BUF         (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE)
+#define AO_RADIO_MODE_APRS_FINISH      (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED)
 
 static void
-ao_radio_set_mode(uint8_t new_mode)
+ao_radio_set_mode(uint16_t new_mode)
 {
-       uint8_t changes;
+       uint16_t changes;
        int i;
 
        if (new_mode == ao_radio_mode)
@@ -404,6 +466,17 @@ ao_radio_set_mode(uint8_t new_mode)
        if (changes & AO_RADIO_MODE_BITS_RDF)
                for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2)
                        ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]);
+
+       if (changes & AO_RADIO_MODE_BITS_APRS)
+               for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
+                       ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
+
+       if (changes & AO_RADIO_MODE_BITS_INFINITE)
+               ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_INFINITE);
+
+       if (changes & AO_RADIO_MODE_BITS_FIXED)
+               ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_FIXED);
+
        ao_radio_mode = new_mode;
 }
 
@@ -430,11 +503,21 @@ ao_radio_setup(void)
        ao_radio_configured = 1;
 }
 
+static void
+ao_radio_set_len(uint8_t len)
+{
+       static uint8_t  last_len;
+
+       if (len != last_len) {
+               ao_radio_reg_write(CC1120_PKT_LEN, len);
+               last_len = len;
+       }
+}
+
 static void
 ao_radio_get(uint8_t len)
 {
        static uint32_t last_radio_setting;
-       static uint8_t  last_len;
 
        ao_mutex_get(&ao_radio_mutex);
        if (!ao_radio_configured)
@@ -445,10 +528,7 @@ ao_radio_get(uint8_t len)
                ao_radio_reg_write(CC1120_FREQ0, ao_config.radio_setting);
                last_radio_setting = ao_config.radio_setting;
        }
-       if (len != last_len) {
-               ao_radio_reg_write(CC1120_PKT_LEN, len);
-               last_len = len;
-       }
+       ao_radio_set_len(len);
 }
 
 #define ao_radio_put() ao_mutex_put(&ao_radio_mutex)
@@ -562,6 +642,24 @@ ao_radio_test_cmd(void)
        }
 }
 
+static uint8_t
+ao_radio_wait_tx(uint8_t wait_fifo)
+{
+       uint8_t fifo_space = 0;
+
+       do {
+               ao_radio_wake = 0;
+               ao_arch_block_interrupts();
+               while (!ao_radio_wake)
+                       ao_sleep(&ao_radio_wake);
+               ao_arch_release_interrupts();
+               if (!wait_fifo)
+                       return 0;
+               fifo_space = ao_radio_tx_fifo_space();
+       } while (!fifo_space);
+       return fifo_space;
+}
+
 static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
 
 void
@@ -601,16 +699,51 @@ ao_radio_send(const void *d, uint8_t size)
                        ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
                }
                        
-               do {
-                       ao_radio_wake = 0;
-                       ao_arch_block_interrupts();
-                       while (!ao_radio_wake)
-                               ao_sleep(&ao_radio_wake);
-                       ao_arch_release_interrupts();
-                       if (!encode_len)
-                               break;
-                       fifo_space = ao_radio_tx_fifo_space();
-               } while (!fifo_space);
+               fifo_space = ao_radio_wait_tx(encode_len != 0);
+       }
+       ao_radio_put();
+}
+
+#define AO_RADIO_LOTS  64
+
+void
+ao_radio_send_lots(ao_radio_fill_func fill)
+{
+       uint8_t buf[AO_RADIO_LOTS], *b;
+       int     cnt;
+       int     total = 0;
+       uint8_t done = 0;
+       uint8_t started = 0;
+       uint8_t fifo_space;
+
+       ao_radio_get(0xff);
+       fifo_space = CC1120_FIFO_SIZE;
+       while (!done) {
+               cnt = (*fill)(buf, sizeof(buf));
+               if (cnt < 0) {
+                       done = 1;
+                       cnt = -cnt;
+               }
+               total += cnt;
+               if (done) {
+                       ao_radio_set_len(total & 0xff);
+                       ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
+               } else
+                       ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
+               b = buf;
+               while (cnt) {
+                       uint8_t this_len = cnt;
+                       if (this_len > fifo_space)
+                               this_len = fifo_space;
+                       ao_radio_fifo_write(b, this_len);
+                       b += this_len;
+                       cnt -= this_len;
+                       if (!started) {
+                               ao_radio_start_tx();
+                               started = 1;
+                       }
+                       fifo_space = ao_radio_wait_tx(!done || cnt);
+               }
        }
        ao_radio_put();
 }
index 7d6c7388fa14f8328be8840be9b891ab03fa2323..25d0ed0399c44071648838c83647d2ee0c306dc3 100644 (file)
@@ -90,6 +90,7 @@ ALTOS_SRC = \
        ao_packet.c \
        ao_companion.c \
        ao_pyro.c \
+       ao_aprs.c \
        $(PROFILE) \
        $(SAMPLE_PROFILE) \
        $(STACK_GUARD)
index d0cfb52d955ca2119fc9c6233985f6937daaaf19..f16c94e8d696b93b53f0ca21732781b979826c4a 100644 (file)
@@ -23,6 +23,8 @@
 
 #include <ao_telemetry.h>
 
+struct ao_telemetry_location ao_gps_data;
+
 #define AO_APRS_TEST
 
 typedef int16_t (*ao_radio_fill_func)(uint8_t *buffer, int16_t len);
@@ -91,6 +93,10 @@ int main(int argc, char **argv)
 {
     audio_gap(1);
 
+    ao_gps_data.latitude = 45.4694766 * 10000000;
+    ao_gps_data.longitude = -122.7376250 * 10000000;
+    ao_gps_data.altitude = 83;
+
     /* Transmit one packet */
     ao_aprs_send();