From: Keith Packard Date: Thu, 6 Dec 2012 18:12:11 +0000 (-0800) Subject: altos: Hook APRS up to the radio X-Git-Tag: 1.1.9.3~10^2~23 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=c1e6fa32b856b91afa355cd272d2d7287d3ccca1;hp=51ef826372f466f44901c4c609ed6a987d30fda4 altos: Hook APRS up to the radio This adds an arbitrary-length packet writing function to the radio code. Signed-off-by: Keith Packard --- diff --git a/src/core/ao.h b/src/core/ao.h index 54018b37..d6e27707 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -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: * diff --git a/src/drivers/ao_aprs.c b/src/drivers/ao_aprs.c index 1a074ba5..e273908f 100644 --- a/src/drivers/ao_aprs.c +++ b/src/drivers/ao_aprs.c @@ -145,11 +145,6 @@ #include -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; diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c index f27958f9..ed26e28d 100644 --- a/src/drivers/ao_cc1120.c +++ b/src/drivers/ao_cc1120.c @@ -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(); } diff --git a/src/megametrum-v0.1/Makefile b/src/megametrum-v0.1/Makefile index 7d6c7388..25d0ed03 100644 --- a/src/megametrum-v0.1/Makefile +++ b/src/megametrum-v0.1/Makefile @@ -90,6 +90,7 @@ ALTOS_SRC = \ ao_packet.c \ ao_companion.c \ ao_pyro.c \ + ao_aprs.c \ $(PROFILE) \ $(SAMPLE_PROFILE) \ $(STACK_GUARD) diff --git a/src/test/ao_aprs_test.c b/src/test/ao_aprs_test.c index d0cfb52d..f16c94e8 100644 --- a/src/test/ao_aprs_test.c +++ b/src/test/ao_aprs_test.c @@ -23,6 +23,8 @@ #include +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();