diff options
author | Keith Packard <keithp@keithp.com> | 2012-04-17 11:01:18 -0700 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2012-04-17 11:01:18 -0700 |
commit | 1489263b895a2a825e29d0560c9b1dbba8a3f431 (patch) | |
tree | ac77be0da392ca7a130fa24a6ce050c48022f116 /src/drivers | |
parent | cc305ea231ae22278abf91c0d9925f5992945369 (diff) |
altos: Starting to write cc1120 driver
This does "something" in radio test mode, appearing to generate a
730MHz signal.
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'src/drivers')
-rw-r--r-- | src/drivers/ao_cc1120.c | 534 | ||||
-rw-r--r-- | src/drivers/ao_cc1120.h | 320 | ||||
-rw-r--r-- | src/drivers/ao_cc1120_CC1120.h | 191 | ||||
-rw-r--r-- | src/drivers/ao_packet.c | 163 | ||||
-rw-r--r-- | src/drivers/ao_packet_master.c | 151 | ||||
-rw-r--r-- | src/drivers/ao_packet_slave.c | 66 |
6 files changed, 1425 insertions, 0 deletions
diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c index 9470fa87..272371d0 100644 --- a/src/drivers/ao_cc1120.c +++ b/src/drivers/ao_cc1120.c @@ -16,10 +16,544 @@ */ #include <ao.h> +#include <ao_cc1120.h> +#include <ao_exti.h> + +uint8_t ao_radio_done; +uint8_t ao_radio_mutex; +uint8_t ao_radio_abort; + +#define CC1120_DEBUG 1 uint32_t ao_radio_cal = 1186611; +#define ao_radio_select() ao_spi_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS) +#define ao_radio_deselect() ao_spi_put_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS) +#define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC1120_SPI_BUS) +#define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1120_SPI_BUS) +#define ao_radio_spi_recv(d,l) ao_spi_recv((d), (l), AO_CC1120_SPI_BUS) +#define ao_radio_duplex(o,i,l) ao_spi_duplex((o), (i), (l), AO_CC1120_SPI_BUS) + +static uint8_t +ao_radio_reg_read(uint16_t addr) +{ + uint8_t data[2]; + uint8_t d; + +#if CC1120_DEBUG + printf("ao_radio_reg_read (%04x): ", addr); flush(); +#endif + if (CC1120_IS_EXTENDED(addr)) { + data[0] = ((1 << CC1120_READ) | + (0 << CC1120_BURST) | + CC1120_EXTENDED); + data[1] = addr; + d = 2; + } else { + data[0] = ((1 << CC1120_READ) | + (0 << CC1120_BURST) | + addr); + d = 1; + } + ao_radio_select(); + ao_radio_spi_send(data, d); + ao_radio_spi_recv(data, 1); + ao_radio_deselect(); +#if CC1120_DEBUG + printf (" %02x\n", data[0]); +#endif + return data[0]; +} + +static void +ao_radio_reg_write(uint16_t addr, uint8_t value) +{ + uint8_t data[3]; + uint8_t d; + +#if CC1120_DEBUG + printf("ao_radio_reg_write (%04x): %02x\n", addr, value); +#endif + if (CC1120_IS_EXTENDED(addr)) { + data[0] = ((1 << CC1120_READ) | + (0 << CC1120_BURST) | + CC1120_EXTENDED); + data[1] = addr; + d = 2; + } else { + data[0] = ((1 << CC1120_READ) | + (0 << CC1120_BURST) | + addr); + d = 1; + } + data[d] = value; + ao_radio_select(); + ao_radio_spi_send(data, d+1); + ao_radio_deselect(); +} + +static uint8_t +ao_radio_strobe(uint8_t addr) +{ + uint8_t in; + + ao_radio_select(); + ao_radio_duplex(&addr, &in, 1); + ao_radio_deselect(); + return in; +} + +static uint8_t +ao_radio_fifo_read(uint8_t *data, uint8_t len) +{ + uint8_t addr = ((1 << CC1120_READ) | + (1 << CC1120_BURST) | + CC1120_FIFO); + uint8_t status; + + ao_radio_select(); + ao_radio_duplex(&addr, &status, 1); + ao_radio_spi_recv(data, len); + ao_radio_deselect(); + return status; +} + +static uint8_t +ao_radio_fifo_write(uint8_t *data, uint8_t len) +{ + uint8_t addr = ((0 << CC1120_READ) | + (1 << CC1120_BURST) | + CC1120_FIFO); + uint8_t status; + + ao_radio_select(); + ao_radio_duplex(&addr, &status, 1); + ao_radio_spi_send(data, len); + ao_radio_deselect(); + return status; +} + +static uint8_t +ao_radio_fifo_write_fixed(uint8_t data, uint8_t len) +{ + uint8_t addr = ((0 << CC1120_READ) | + (1 << CC1120_BURST) | + CC1120_FIFO); + uint8_t status; + + ao_radio_select(); + ao_radio_duplex(&addr, &status, 1); + ao_radio_spi_send_fixed(data, len); + ao_radio_deselect(); + return status; +} + +static uint8_t +ao_radio_status(void) +{ + return ao_radio_strobe (CC1120_SNOP); +} + void ao_radio_recv_abort(void) { + ao_radio_abort = 1; + ao_wakeup(&ao_radio_done); +} + +#define ao_radio_rdf_value 0x55 + +static const uint16_t rdf_setup[] = { +}; + +void +ao_radio_rdf(uint8_t len) +{ + int i; + + ao_radio_abort = 0; + ao_radio_get(len); + ao_radio_done = 0; + for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2) + ao_radio_reg_write(rdf_setup[i], rdf_setup[i+1]); + ao_radio_fifo_write_fixed(ao_radio_rdf_value, len); + ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG); + ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); + ao_radio_strobe(CC1120_STX); + cli(); + while (!ao_radio_done) + ao_sleep(&ao_radio_done); + sei(); + ao_radio_set_packet(); + ao_radio_put(); +} + +void +ao_radio_rdf_abort(void) +{ +} + +static void +ao_radio_test(void) +{ + uint8_t mode = 2; + uint8_t radio_on; + ao_cmd_white(); + if (ao_cmd_lex_c != '\n') { + ao_cmd_decimal(); + mode = (uint8_t) ao_cmd_lex_u32; + } + mode++; + if ((mode & 2) && !radio_on) { +#if HAS_MONITOR + ao_monitor_disable(); +#endif +#if PACKET_HAS_SLAVE + ao_packet_slave_stop(); +#endif + ao_radio_get(0xff); + ao_radio_strobe(CC1120_STX); + radio_on = 1; + } + if (mode == 3) { + printf ("Hit a character to stop..."); flush(); + getchar(); + putchar('\n'); + } + if ((mode & 1) && radio_on) { + ao_radio_idle(); + ao_radio_put(); + radio_on = 0; +#if HAS_MONITOR + ao_monitor_enable(); +#endif + } +} + +void +ao_radio_send(void *d, uint8_t size) +{ + ao_radio_get(size); + ao_radio_done = 0; + ao_radio_fifo_write(d, size); + ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG); + ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); + ao_radio_strobe(CC1120_STX); + cli(); + while (!ao_radio_done) + ao_sleep(&ao_radio_done); + sei(); + ao_radio_put(); +} + +uint8_t +ao_radio_recv(__xdata void *d, uint8_t size) +{ + /* configure interrupt pin */ + ao_radio_get(size); + ao_radio_done = 0; + ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_RXFIFO_THR_PKT); + ao_exti_enable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); + ao_radio_strobe(CC1120_SRX); + cli(); + while (!ao_radio_done && !ao_radio_abort) + ao_sleep(&ao_radio_done); + sei(); + if (ao_radio_done) + ao_radio_fifo_read(d, size); + ao_radio_put(); + return 0; +} + +static const uint16_t packet_setup[] = { +}; + +void +ao_radio_set_packet(void) +{ + int i; + + for (i = 0; i < sizeof (rdf_setup) / sizeof (rdf_setup[0]); i += 2) + ao_radio_reg_write(packet_setup[i], packet_setup[i+1]); +} + +void +ao_radio_idle(void) +{ + for (;;) { + uint8_t state = ao_radio_strobe(CC1120_SIDLE); + if ((state >> CC1120_STATUS_STATE) == CC1120_STATUS_STATE_IDLE) + break; + } +} + +static const uint16_t radio_setup[] = { +#include "ao_cc1120_CC1120.h" +}; + +static uint8_t ao_radio_configured = 0; + +static void +ao_radio_isr(void) +{ + ao_exti_disable(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); + ao_radio_done = 1; + ao_wakeup(&ao_radio_done); +} + +static void +ao_radio_setup(void) +{ + int i; + + for (i = 0; i < sizeof (radio_setup) / sizeof (radio_setup[0]); i += 2) + ao_radio_reg_write(radio_setup[i], radio_setup[i+1]); + + /* Disable GPIO2 pin (radio_int) */ + ao_radio_reg_write(CC1120_IOCFG2, CC1120_IOCFG_GPIO_CFG_HIGHZ); + + /* Enable the EXTI interrupt for the appropriate pin */ + ao_enable_port(AO_CC1120_INT_PORT); + ao_exti_setup(&AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, AO_EXTI_MODE_RISING, ao_radio_isr); + + ao_radio_set_packet(); + ao_radio_configured = 1; +} + +void +ao_radio_get(uint8_t len) +{ + ao_mutex_get(&ao_radio_mutex); + if (!ao_radio_configured) + ao_radio_setup(); + ao_radio_reg_write(CC1120_PKT_LEN, len); +} + +#if CC1120_DEBUG +static char *cc1120_state_name[] = { + [CC1120_STATUS_STATE_IDLE] = "IDLE", + [CC1120_STATUS_STATE_RX] = "RX", + [CC1120_STATUS_STATE_TX] = "TX", + [CC1120_STATUS_STATE_FSTXON] = "FSTXON", + [CC1120_STATUS_STATE_CALIBRATE] = "CALIBRATE", + [CC1120_STATUS_STATE_SETTLING] = "SETTLING", + [CC1120_STATUS_STATE_RX_FIFO_ERROR] = "RX_FIFO_ERROR", + [CC1120_STATUS_STATE_TX_FIFO_ERROR] = "TX_FIFO_ERROR", +}; + +struct ao_cc1120_reg { + uint16_t addr; + char *name; +}; + +const static struct ao_cc1120_reg ao_cc1120_reg[] = { + { .addr = CC1120_IOCFG3, .name = "IOCFG3" }, + { .addr = CC1120_IOCFG2, .name = "IOCFG2" }, + { .addr = CC1120_IOCFG1, .name = "IOCFG1" }, + { .addr = CC1120_IOCFG0, .name = "IOCFG0" }, + { .addr = CC1120_SYNC3, .name = "SYNC3" }, + { .addr = CC1120_SYNC2, .name = "SYNC2" }, + { .addr = CC1120_SYNC1, .name = "SYNC1" }, + { .addr = CC1120_SYNC0, .name = "SYNC0" }, + { .addr = CC1120_SYNC_CFG1, .name = "SYNC_CFG1" }, + { .addr = CC1120_SYNC_CFG0, .name = "SYNC_CFG0" }, + { .addr = CC1120_DEVIATION_M, .name = "DEVIATION_M" }, + { .addr = CC1120_MODCFG_DEV_E, .name = "MODCFG_DEV_E" }, + { .addr = CC1120_DCFILT_CFG, .name = "DCFILT_CFG" }, + { .addr = CC1120_PREAMBLE_CFG1, .name = "PREAMBLE_CFG1" }, + { .addr = CC1120_PREAMBLE_CFG0, .name = "PREAMBLE_CFG0" }, + { .addr = CC1120_FREQ_IF_CFG, .name = "FREQ_IF_CFG" }, + { .addr = CC1120_IQIC, .name = "IQIC" }, + { .addr = CC1120_CHAN_BW, .name = "CHAN_BW" }, + { .addr = CC1120_MDMCFG1, .name = "MDMCFG1" }, + { .addr = CC1120_MDMCFG0, .name = "MDMCFG0" }, + { .addr = CC1120_DRATE2, .name = "DRATE2" }, + { .addr = CC1120_DRATE1, .name = "DRATE1" }, + { .addr = CC1120_DRATE0, .name = "DRATE0" }, + { .addr = CC1120_AGC_REF, .name = "AGC_REF" }, + { .addr = CC1120_AGC_CS_THR, .name = "AGC_CS_THR" }, + { .addr = CC1120_AGC_GAIN_ADJUST, .name = "AGC_GAIN_ADJUST" }, + { .addr = CC1120_AGC_CFG3, .name = "AGC_CFG3" }, + { .addr = CC1120_AGC_CFG2, .name = "AGC_CFG2" }, + { .addr = CC1120_AGC_CFG1, .name = "AGC_CFG1" }, + { .addr = CC1120_AGC_CFG0, .name = "AGC_CFG0" }, + { .addr = CC1120_FIFO_CFG, .name = "FIFO_CFG" }, + { .addr = CC1120_DEV_ADDR, .name = "DEV_ADDR" }, + { .addr = CC1120_SETTLING_CFG, .name = "SETTLING_CFG" }, + { .addr = CC1120_FS_CFG, .name = "FS_CFG" }, + { .addr = CC1120_WOR_CFG1, .name = "WOR_CFG1" }, + { .addr = CC1120_WOR_CFG0, .name = "WOR_CFG0" }, + { .addr = CC1120_WOR_EVENT0_MSB, .name = "WOR_EVENT0_MSB" }, + { .addr = CC1120_WOR_EVENT0_LSB, .name = "WOR_EVENT0_LSB" }, + { .addr = CC1120_PKT_CFG2, .name = "PKT_CFG2" }, + { .addr = CC1120_PKT_CFG1, .name = "PKT_CFG1" }, + { .addr = CC1120_PKT_CFG0, .name = "PKT_CFG0" }, + { .addr = CC1120_RFEND_CFG1, .name = "RFEND_CFG1" }, + { .addr = CC1120_RFEND_CFG0, .name = "RFEND_CFG0" }, + { .addr = CC1120_PA_CFG2, .name = "PA_CFG2" }, + { .addr = CC1120_PA_CFG1, .name = "PA_CFG1" }, + { .addr = CC1120_PA_CFG0, .name = "PA_CFG0" }, + { .addr = CC1120_PKT_LEN, .name = "PKT_LEN" }, + { .addr = CC1120_IF_MIX_CFG, .name = "IF_MIX_CFG" }, + { .addr = CC1120_FREQOFF_CFG, .name = "FREQOFF_CFG" }, + { .addr = CC1120_TOC_CFG, .name = "TOC_CFG" }, + { .addr = CC1120_MARC_SPARE, .name = "MARC_SPARE" }, + { .addr = CC1120_ECG_CFG, .name = "ECG_CFG" }, + { .addr = CC1120_SOFT_TX_DATA_CFG, .name = "SOFT_TX_DATA_CFG" }, + { .addr = CC1120_EXT_CTRL, .name = "EXT_CTRL" }, + { .addr = CC1120_RCCAL_FINE, .name = "RCCAL_FINE" }, + { .addr = CC1120_RCCAL_COARSE, .name = "RCCAL_COARSE" }, + { .addr = CC1120_RCCAL_OFFSET, .name = "RCCAL_OFFSET" }, + { .addr = CC1120_FREQOFF1, .name = "FREQOFF1" }, + { .addr = CC1120_FREQOFF0, .name = "FREQOFF0" }, + { .addr = CC1120_FREQ2, .name = "FREQ2" }, + { .addr = CC1120_FREQ1, .name = "FREQ1" }, + { .addr = CC1120_FREQ0, .name = "FREQ0" }, + { .addr = CC1120_IF_ADC2, .name = "IF_ADC2" }, + { .addr = CC1120_IF_ADC1, .name = "IF_ADC1" }, + { .addr = CC1120_IF_ADC0, .name = "IF_ADC0" }, + { .addr = CC1120_FS_DIG1, .name = "FS_DIG1" }, + { .addr = CC1120_FS_DIG0, .name = "FS_DIG0" }, + { .addr = CC1120_FS_CAL3, .name = "FS_CAL3" }, + { .addr = CC1120_FS_CAL2, .name = "FS_CAL2" }, + { .addr = CC1120_FS_CAL1, .name = "FS_CAL1" }, + { .addr = CC1120_FS_CAL0, .name = "FS_CAL0" }, + { .addr = CC1120_FS_CHP, .name = "FS_CHP" }, + { .addr = CC1120_FS_DIVTWO, .name = "FS_DIVTWO" }, + { .addr = CC1120_FS_DSM1, .name = "FS_DSM1" }, + { .addr = CC1120_FS_DSM0, .name = "FS_DSM0" }, + { .addr = CC1120_FS_DVC1, .name = "FS_DVC1" }, + { .addr = CC1120_FS_DVC0, .name = "FS_DVC0" }, + { .addr = CC1120_FS_LBI, .name = "FS_LBI" }, + { .addr = CC1120_FS_PFD, .name = "FS_PFD" }, + { .addr = CC1120_FS_PRE, .name = "FS_PRE" }, + { .addr = CC1120_FS_REG_DIV_CML, .name = "FS_REG_DIV_CML" }, + { .addr = CC1120_FS_SPARE, .name = "FS_SPARE" }, + { .addr = CC1120_FS_VCO4, .name = "FS_VCO4" }, + { .addr = CC1120_FS_VCO3, .name = "FS_VCO3" }, + { .addr = CC1120_FS_VCO2, .name = "FS_VCO2" }, + { .addr = CC1120_FS_VCO1, .name = "FS_VCO1" }, + { .addr = CC1120_FS_VCO0, .name = "FS_VCO0" }, + { .addr = CC1120_GBIAS6, .name = "GBIAS6" }, + { .addr = CC1120_GBIAS5, .name = "GBIAS5" }, + { .addr = CC1120_GBIAS4, .name = "GBIAS4" }, + { .addr = CC1120_GBIAS3, .name = "GBIAS3" }, + { .addr = CC1120_GBIAS2, .name = "GBIAS2" }, + { .addr = CC1120_GBIAS1, .name = "GBIAS1" }, + { .addr = CC1120_GBIAS0, .name = "GBIAS0" }, + { .addr = CC1120_IFAMP, .name = "IFAMP" }, + { .addr = CC1120_LNA, .name = "LNA" }, + { .addr = CC1120_RXMIX, .name = "RXMIX" }, + { .addr = CC1120_XOSC5, .name = "XOSC5" }, + { .addr = CC1120_XOSC4, .name = "XOSC4" }, + { .addr = CC1120_XOSC3, .name = "XOSC3" }, + { .addr = CC1120_XOSC2, .name = "XOSC2" }, + { .addr = CC1120_XOSC1, .name = "XOSC1" }, + { .addr = CC1120_XOSC0, .name = "XOSC0" }, + { .addr = CC1120_ANALOG_SPARE, .name = "ANALOG_SPARE" }, + { .addr = CC1120_PA_CFG3, .name = "PA_CFG3" }, + { .addr = CC1120_WOR_TIME1, .name = "WOR_TIME1" }, + { .addr = CC1120_WOR_TIME0, .name = "WOR_TIME0" }, + { .addr = CC1120_WOR_CAPTURE1, .name = "WOR_CAPTURE1" }, + { .addr = CC1120_WOR_CAPTURE0, .name = "WOR_CAPTURE0" }, + { .addr = CC1120_BIST, .name = "BIST" }, + { .addr = CC1120_DCFILTOFFSET_I1, .name = "DCFILTOFFSET_I1" }, + { .addr = CC1120_DCFILTOFFSET_I0, .name = "DCFILTOFFSET_I0" }, + { .addr = CC1120_DCFILTOFFSET_Q1, .name = "DCFILTOFFSET_Q1" }, + { .addr = CC1120_DCFILTOFFSET_Q0, .name = "DCFILTOFFSET_Q0" }, + { .addr = CC1120_IQIE_I1, .name = "IQIE_I1" }, + { .addr = CC1120_IQIE_I0, .name = "IQIE_I0" }, + { .addr = CC1120_IQIE_Q1, .name = "IQIE_Q1" }, + { .addr = CC1120_IQIE_Q0, .name = "IQIE_Q0" }, + { .addr = CC1120_RSSI1, .name = "RSSI1" }, + { .addr = CC1120_RSSI0, .name = "RSSI0" }, + { .addr = CC1120_MARCSTATE, .name = "MARCSTATE" }, + { .addr = CC1120_LQI_VAL, .name = "LQI_VAL" }, + { .addr = CC1120_PQT_SYNC_ERR, .name = "PQT_SYNC_ERR" }, + { .addr = CC1120_DEM_STATUS, .name = "DEM_STATUS" }, + { .addr = CC1120_FREQOFF_EST1, .name = "FREQOFF_EST1" }, + { .addr = CC1120_FREQOFF_EST0, .name = "FREQOFF_EST0" }, + { .addr = CC1120_AGC_GAIN3, .name = "AGC_GAIN3" }, + { .addr = CC1120_AGC_GAIN2, .name = "AGC_GAIN2" }, + { .addr = CC1120_AGC_GAIN1, .name = "AGC_GAIN1" }, + { .addr = CC1120_AGC_GAIN0, .name = "AGC_GAIN0" }, + { .addr = CC1120_SOFT_RX_DATA_OUT, .name = "SOFT_RX_DATA_OUT" }, + { .addr = CC1120_SOFT_TX_DATA_IN, .name = "SOFT_TX_DATA_IN" }, + { .addr = CC1120_ASK_SOFT_RX_DATA, .name = "ASK_SOFT_RX_DATA" }, + { .addr = CC1120_RNDGEN, .name = "RNDGEN" }, + { .addr = CC1120_MAGN2, .name = "MAGN2" }, + { .addr = CC1120_MAGN1, .name = "MAGN1" }, + { .addr = CC1120_MAGN0, .name = "MAGN0" }, + { .addr = CC1120_ANG1, .name = "ANG1" }, + { .addr = CC1120_ANG0, .name = "ANG0" }, + { .addr = CC1120_CHFILT_I2, .name = "CHFILT_I2" }, + { .addr = CC1120_CHFILT_I1, .name = "CHFILT_I1" }, + { .addr = CC1120_CHFILT_I0, .name = "CHFILT_I0" }, + { .addr = CC1120_CHFILT_Q2, .name = "CHFILT_Q2" }, + { .addr = CC1120_CHFILT_Q1, .name = "CHFILT_Q1" }, + { .addr = CC1120_CHFILT_Q0, .name = "CHFILT_Q0" }, + { .addr = CC1120_GPIO_STATUS, .name = "GPIO_STATUS" }, + { .addr = CC1120_FSCAL_CTRL, .name = "FSCAL_CTRL" }, + { .addr = CC1120_PHASE_ADJUST, .name = "PHASE_ADJUST" }, + { .addr = CC1120_PARTNUMBER, .name = "PARTNUMBER" }, + { .addr = CC1120_PARTVERSION, .name = "PARTVERSION" }, + { .addr = CC1120_SERIAL_STATUS, .name = "SERIAL_STATUS" }, + { .addr = CC1120_RX_STATUS, .name = "RX_STATUS" }, + { .addr = CC1120_TX_STATUS, .name = "TX_STATUS" }, + { .addr = CC1120_MARC_STATUS1, .name = "MARC_STATUS1" }, + { .addr = CC1120_MARC_STATUS0, .name = "MARC_STATUS0" }, + { .addr = CC1120_PA_IFAMP_TEST, .name = "PA_IFAMP_TEST" }, + { .addr = CC1120_FSRF_TEST, .name = "FSRF_TEST" }, + { .addr = CC1120_PRE_TEST, .name = "PRE_TEST" }, + { .addr = CC1120_PRE_OVR, .name = "PRE_OVR" }, + { .addr = CC1120_ADC_TEST, .name = "ADC_TEST" }, + { .addr = CC1120_DVC_TEST, .name = "DVC_TEST" }, + { .addr = CC1120_ATEST, .name = "ATEST" }, + { .addr = CC1120_ATEST_LVDS, .name = "ATEST_LVDS" }, + { .addr = CC1120_ATEST_MODE, .name = "ATEST_MODE" }, + { .addr = CC1120_XOSC_TEST1, .name = "XOSC_TEST1" }, + { .addr = CC1120_XOSC_TEST0, .name = "XOSC_TEST0" }, + { .addr = CC1120_RXFIRST, .name = "RXFIRST" }, + { .addr = CC1120_TXFIRST, .name = "TXFIRST" }, + { .addr = CC1120_RXLAST, .name = "RXLAST" }, + { .addr = CC1120_TXLAST, .name = "TXLAST" }, + { .addr = CC1120_NUM_TXBYTES, .name = "NUM_TXBYTES" }, + { .addr = CC1120_NUM_RXBYTES, .name = "NUM_RXBYTES" }, + { .addr = CC1120_FIFO_NUM_TXBYTES, .name = "FIFO_NUM_TXBYTES" }, + { .addr = CC1120_FIFO_NUM_RXBYTES, .name = "FIFO_NUM_RXBYTES" }, +}; + +#define AO_NUM_CC1120_REG (sizeof ao_cc1120_reg / sizeof ao_cc1120_reg[0]) + +static void ao_radio_show(void) { + uint8_t status = ao_radio_status(); + int i; + + ao_radio_get(0xff); + status = ao_radio_status(); + printf ("Status: %02x\n", status); + printf ("CHIP_RDY: %d\n", (status >> CC1120_STATUS_CHIP_RDY) & 1); + printf ("STATE: %s\n", cc1120_state_name[(status >> CC1120_STATUS_STATE) & CC1120_STATUS_STATE_MASK]); + + for (i = 0; i < AO_NUM_CC1120_REG; i++) + printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1120_reg[i].addr), ao_cc1120_reg[i].name); + ao_radio_put(); +} +#endif + +static const struct ao_cmds ao_radio_cmds[] = { + { ao_radio_test, "C <1 start, 0 stop, none both>\0Radio carrier test" }, +#if CC1120_DEBUG + { ao_radio_show, "R\0Show CC1120 status" }, +#endif + { 0, NULL } +}; + +void +ao_radio_init(void) +{ + ao_radio_configured = 0; + ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN)); + + ao_cmd_register(&ao_radio_cmds[0]); } diff --git a/src/drivers/ao_cc1120.h b/src/drivers/ao_cc1120.h new file mode 100644 index 00000000..67c0a1b8 --- /dev/null +++ b/src/drivers/ao_cc1120.h @@ -0,0 +1,320 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_CC1120_H_ +#define _AO_CC1120_H_ + +#define CC1120_READ (7) +#define CC1120_BURST (6) + +/* Register space */ +#define CC1120_IOCFG3 0x00 +#define CC1120_IOCFG_GPIO_ATRAN 7 +#define CC1120_IOCFG_GPIO_INV 6 +#define CC1120_IOCFG_GPIO_CFG 0 +#define CC1120_IOCFG_GPIO_CFG_RXFIFO_THR 0 +#define CC1120_IOCFG_GPIO_CFG_RXFIFO_THR_PKT 1 +#define CC1120_IOCFG_GPIO_CFG_TXFIFO_THR 2 +#define CC1120_IOCFG_GPIO_CFG_TXFIFO_THR_PKT 3 +#define CC1120_IOCFG_GPIO_CFG_RXFIFO_OVERFLOW 4 +#define CC1120_IOCFG_GPIO_CFG_TXFIFO_UNDERFLOW 5 +#define CC1120_IOCFG_GPIO_CFG_PKT_SYNC_RXTX 6 +#define CC1120_IOCFG_GPIO_CFG_CRC_OK 7 +#define CC1120_IOCFG_GPIO_CFG_SERIAL_CLK 8 +#define CC1120_IOCFG_GPIO_CFG_SERIAL_RX 9 +#define CC1120_IOCFG_GPIO_CFG_PQT_REACHED 11 +#define CC1120_IOCFG_GPIO_CFG_PQT_VALID 12 +#define CC1120_IOCFG_GPIO_CFG_RSSI_VALID 13 +#define CC1120_IOCFG_GPIO3_CFG_RSSI_UPDATE 14 +#define CC1120_IOCFG_GPIO2_CFG_RSSI_UPDATE 14 +#define CC1120_IOCFG_GPIO1_CFG_AGC_HOLD 14 +#define CC1120_IOCFG_GPIO0_CFG_AGC_UPDATE 14 +#define CC1120_IOCFG_GPIO3_CFG_CGA_STATUS 15 +#define CC1120_IOCFG_GPIO2_CFG_TXONCCA_DONE 15 +#define CC1120_IOCFG_GPIO1_CFG_CCA_STATUS 15 +#define CC1120_IOCFG_GPIO0_CFG_TXONCCA_FAILED 15 +#define CC1120_IOCFG_GPIO_CFG_CARRIER_SENSE_VALID 16 +#define CC1120_IOCFG_GPIO_CFG_CARRIER_SENSE 17 +#define CC1120_IOCFG_GPIO3_CFG_DSSS_CLK 18 +#define CC1120_IOCFG_GPIO2_CFG_DSSS_DATA0 18 +#define CC1120_IOCFG_GPIO1_CFG_DSSS_CLK 18 +#define CC1120_IOCFG_GPIO0_CFG_DSSS_DATA1 18 +#define CC1120_IOCFG_GPIO_CFG_PKT_CRC_OK 19 +#define CC1120_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP 20 +#define CC1120_IOCFG_GPIO_CFG_SYNC_LOW0_HIGH1 21 +#define CC1120_IOCFG_GPIO_CFG_LNA_PA_REG_PD 23 +#define CC1120_IOCFG_GPIO_CFG_LNA_PD 24 +#define CC1120_IOCFG_GPIO_CFG_PA_RD 25 +#define CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG 26 +#define CC1120_IOCFG_GPIO_CFG_IMAGE_FOUND 28 +#define CC1120_IOCFG_GPIO_CFG_CLKEN_SOFT 29 +#define CC1120_IOCFG_GPIO_CFG_SOFT_TX_DATA_CLK 30 +#define CC1120_IOCFG_GPIO_CFG_RSSI_STEP_FOUND 33 +#define CC1120_IOCFG_GPIO_CFG_RSSI_STEP_EVENT 34 +#define CC1120_IOCFG_GPIO_CFG_ANTENNA_SELECT 36 +#define CC1120_IOCFG_GPIO_CFG_MARC_2PIN_STATUS1 37 +#define CC1120_IOCFG_GPIO_CFG_MARC_2PIN_STATUS0 38 +#define CC1120_IOCFG_GPIO2_CFG_TXFIFO_OVERFLOW 39 +#define CC1120_IOCFG_GPIO0_CFG_RXFIFO_UNDERFLOW 39 +#define CC1120_IOCFG_GPIO3_CFG_MAGN_VALID 40 +#define CC1120_IOCFG_GPIO2_CFG_CHFILT_VALID 40 +#define CC1120_IOCFG_GPIO1_CFG_RCC_CAL_VALID 40 +#define CC1120_IOCFG_GPIO0_CFG_CHFILTER_STARTUP_VALID 40 +#define CC1120_IOCFG_GPIO3_CFG_COLLISION_FOUND 41 +#define CC1120_IOCFG_GPIO2_CFG_SYNC_EVENT 41 +#define CC1120_IOCFG_GPIO1_CFG_COLLISION_FOUND 41 +#define CC1120_IOCFG_GPIO0_CFG_COLLISION_EVENT 41 +#define CC1120_IOCFG_GPIO_CFG_PA_RAMP_UP 42 +#define CC1120_IOCFG_GPIO3_CFG_CRC_FAILED 43 +#define CC1120_IOCFG_GPIO2_CFG_LENGTH_FAILED 43 +#define CC1120_IOCFG_GPIO1_CFG_ADDR_FAILED 43 +#define CC1120_IOCFG_GPIO0_CFG_UART_FRAMING_ERROR 43 +#define CC1120_IOCFG_GPIO_CFG_AGC_STABLE_GAIN 44 +#define CC1120_IOCFG_GPIO_CFG_AGC_UPDATE 45 +#define CC1120_IOCFG_GPIO3_CFG_ADC_CLOCK 46 +#define CC1120_IOCFG_GPIO2_CFG_ADC_Q_DATA_SAMPLE 46 +#define CC1120_IOCFG_GPIO1_CFG_ADC_CLOCK 46 +#define CC1120_IOCFG_GPIO0_CFG_ADC_I_DATA_SAMPLE 46 +#define CC1120_IOCFG_GPIO_CFG_HIGHZ 48 +#define CC1120_IOCFG_GPIO_CFG_EXT_CLOCK 49 +#define CC1120_IOCFG_GPIO_CFG_CHIP_RDY 50 +#define CC1120_IOCFG_GPIO_CFG_HW0 51 +#define CC1120_IOCFG_GPIO_CFG_CLOCK_32K 54 +#define CC1120_IOCFG_GPIO_CFG_WOR_EVENT0 55 +#define CC1120_IOCFG_GPIO_CFG_WOR_EVENT1 56 +#define CC1120_IOCFG_GPIO_CFG_WOR_EVENT2 57 +#define CC1120_IOCFG_GPIO_CFG_XOSC_STABLE 59 +#define CC1120_IOCFG_GPIO_CFG_EXT_OSC_EN 60 +#define CC1120_IOCFG_GPIO_CFG_MASK 0x3f + +#define CC1120_IOCFG3 0x00 +#define CC1120_IOCFG2 0x01 +#define CC1120_IOCFG1 0x02 +#define CC1120_IOCFG0 0x03 +#define CC1120_SYNC3 0x04 +#define CC1120_SYNC2 0x05 +#define CC1120_SYNC1 0x06 +#define CC1120_SYNC0 0x07 +#define CC1120_SYNC_CFG1 0x08 +#define CC1120_SYNC_CFG0 0x09 +#define CC1120_DEVIATION_M 0x0a +#define CC1120_MODCFG_DEV_E 0x0b +#define CC1120_DCFILT_CFG 0x0c +#define CC1120_PREAMBLE_CFG1 0x0d +#define CC1120_PREAMBLE_CFG0 0x0e +#define CC1120_FREQ_IF_CFG 0x0f +#define CC1120_IQIC 0x10 +#define CC1120_CHAN_BW 0x11 +#define CC1120_MDMCFG1 0x12 +#define CC1120_MDMCFG0 0x13 +#define CC1120_DRATE2 0x14 +#define CC1120_DRATE1 0x15 +#define CC1120_DRATE0 0x16 +#define CC1120_AGC_REF 0x17 +#define CC1120_AGC_CS_THR 0x18 +#define CC1120_AGC_GAIN_ADJUST 0x19 +#define CC1120_AGC_CFG3 0x1a +#define CC1120_AGC_CFG2 0x1b +#define CC1120_AGC_CFG1 0x1c +#define CC1120_AGC_CFG0 0x1d +#define CC1120_FIFO_CFG 0x1e +#define CC1120_DEV_ADDR 0x1f +#define CC1120_SETTLING_CFG 0x20 +#define CC1120_FS_CFG 0x21 +#define CC1120_WOR_CFG1 0x22 +#define CC1120_WOR_CFG0 0x23 +#define CC1120_WOR_EVENT0_MSB 0x24 +#define CC1120_WOR_EVENT0_LSB 0x25 +#define CC1120_PKT_CFG2 0x26 +#define CC1120_PKT_CFG1 0x27 +#define CC1120_PKT_CFG0 0x28 +#define CC1120_RFEND_CFG1 0x29 +#define CC1120_RFEND_CFG0 0x2a +#define CC1120_PA_CFG2 0x2b +#define CC1120_PA_CFG1 0x2c +#define CC1120_PA_CFG0 0x2d +#define CC1120_PKT_LEN 0x2e + +#define CC1120_EXTENDED 0x2f + +/* Command strobes */ +#define CC1120_SRES 0x30 +#define CC1120_SFSTXON 0x31 +#define CC1120_SXOFF 0x32 +#define CC1120_SCAL 0x33 +#define CC1120_SRX 0x34 +#define CC1120_STX 0x35 +#define CC1120_SIDLE 0x36 +#define CC1120_SAFC 0x37 +#define CC1120_SWOR 0x38 +#define CC1120_SPWD 0x39 +#define CC1120_SFRX 0x3a +#define CC1120_SFTX 0x3b +#define CC1120_SWORRST 0x3c +#define CC1120_SNOP 0x3d + +#define CC1120_DIRECT_FIFO 0x3e +#define CC1120_FIFO 0x3f + +/* Extended register space */ + +#define CC1120_EXTENDED_BIT 0x8000 + +#define CC1120_IS_EXTENDED(r) ((r) & CC1120_EXTENDED_BIT) + +#define CC1120_IF_MIX_CFG (CC1120_EXTENDED_BIT | 0x00) +#define CC1120_FREQOFF_CFG (CC1120_EXTENDED_BIT | 0x01) +#define CC1120_TOC_CFG (CC1120_EXTENDED_BIT | 0x02) +#define CC1120_MARC_SPARE (CC1120_EXTENDED_BIT | 0x03) +#define CC1120_ECG_CFG (CC1120_EXTENDED_BIT | 0x04) +#define CC1120_SOFT_TX_DATA_CFG (CC1120_EXTENDED_BIT | 0x05) +#define CC1120_EXT_CTRL (CC1120_EXTENDED_BIT | 0x06) +#define CC1120_RCCAL_FINE (CC1120_EXTENDED_BIT | 0x07) +#define CC1120_RCCAL_COARSE (CC1120_EXTENDED_BIT | 0x08) +#define CC1120_RCCAL_OFFSET (CC1120_EXTENDED_BIT | 0x09) +#define CC1120_FREQOFF1 (CC1120_EXTENDED_BIT | 0x0A) +#define CC1120_FREQOFF0 (CC1120_EXTENDED_BIT | 0x0B) +#define CC1120_FREQ2 (CC1120_EXTENDED_BIT | 0x0C) +#define CC1120_FREQ1 (CC1120_EXTENDED_BIT | 0x0D) +#define CC1120_FREQ0 (CC1120_EXTENDED_BIT | 0x0E) +#define CC1120_IF_ADC2 (CC1120_EXTENDED_BIT | 0x0F) +#define CC1120_IF_ADC1 (CC1120_EXTENDED_BIT | 0x10) +#define CC1120_IF_ADC0 (CC1120_EXTENDED_BIT | 0x11) +#define CC1120_FS_DIG1 (CC1120_EXTENDED_BIT | 0x12) +#define CC1120_FS_DIG0 (CC1120_EXTENDED_BIT | 0x13) +#define CC1120_FS_CAL3 (CC1120_EXTENDED_BIT | 0x14) +#define CC1120_FS_CAL2 (CC1120_EXTENDED_BIT | 0x15) +#define CC1120_FS_CAL1 (CC1120_EXTENDED_BIT | 0x16) +#define CC1120_FS_CAL0 (CC1120_EXTENDED_BIT | 0x17) +#define CC1120_FS_CHP (CC1120_EXTENDED_BIT | 0x18) +#define CC1120_FS_DIVTWO (CC1120_EXTENDED_BIT | 0x19) +#define CC1120_FS_DSM1 (CC1120_EXTENDED_BIT | 0x1A) +#define CC1120_FS_DSM0 (CC1120_EXTENDED_BIT | 0x1B) +#define CC1120_FS_DVC1 (CC1120_EXTENDED_BIT | 0x1C) +#define CC1120_FS_DVC0 (CC1120_EXTENDED_BIT | 0x1D) +#define CC1120_FS_LBI (CC1120_EXTENDED_BIT | 0x1E) +#define CC1120_FS_PFD (CC1120_EXTENDED_BIT | 0x1F) +#define CC1120_FS_PRE (CC1120_EXTENDED_BIT | 0x20) +#define CC1120_FS_REG_DIV_CML (CC1120_EXTENDED_BIT | 0x21) +#define CC1120_FS_SPARE (CC1120_EXTENDED_BIT | 0x22) +#define CC1120_FS_VCO4 (CC1120_EXTENDED_BIT | 0x23) +#define CC1120_FS_VCO3 (CC1120_EXTENDED_BIT | 0x24) +#define CC1120_FS_VCO2 (CC1120_EXTENDED_BIT | 0x25) +#define CC1120_FS_VCO1 (CC1120_EXTENDED_BIT | 0x26) +#define CC1120_FS_VCO0 (CC1120_EXTENDED_BIT | 0x27) +#define CC1120_GBIAS6 (CC1120_EXTENDED_BIT | 0x28) +#define CC1120_GBIAS5 (CC1120_EXTENDED_BIT | 0x29) +#define CC1120_GBIAS4 (CC1120_EXTENDED_BIT | 0x2A) +#define CC1120_GBIAS3 (CC1120_EXTENDED_BIT | 0x2B) +#define CC1120_GBIAS2 (CC1120_EXTENDED_BIT | 0x2C) +#define CC1120_GBIAS1 (CC1120_EXTENDED_BIT | 0x2D) +#define CC1120_GBIAS0 (CC1120_EXTENDED_BIT | 0x2E) +#define CC1120_IFAMP (CC1120_EXTENDED_BIT | 0x2F) +#define CC1120_LNA (CC1120_EXTENDED_BIT | 0x30) +#define CC1120_RXMIX (CC1120_EXTENDED_BIT | 0x31) +#define CC1120_XOSC5 (CC1120_EXTENDED_BIT | 0x32) +#define CC1120_XOSC4 (CC1120_EXTENDED_BIT | 0x33) +#define CC1120_XOSC3 (CC1120_EXTENDED_BIT | 0x34) +#define CC1120_XOSC2 (CC1120_EXTENDED_BIT | 0x35) +#define CC1120_XOSC1 (CC1120_EXTENDED_BIT | 0x36) +#define CC1120_XOSC0 (CC1120_EXTENDED_BIT | 0x37) +#define CC1120_ANALOG_SPARE (CC1120_EXTENDED_BIT | 0x38) +#define CC1120_PA_CFG3 (CC1120_EXTENDED_BIT | 0x39) +#define CC1120_WOR_TIME1 (CC1120_EXTENDED_BIT | 0x64) +#define CC1120_WOR_TIME0 (CC1120_EXTENDED_BIT | 0x65) +#define CC1120_WOR_CAPTURE1 (CC1120_EXTENDED_BIT | 0x66) +#define CC1120_WOR_CAPTURE0 (CC1120_EXTENDED_BIT | 0x67) +#define CC1120_BIST (CC1120_EXTENDED_BIT | 0x68) +#define CC1120_DCFILTOFFSET_I1 (CC1120_EXTENDED_BIT | 0x69) +#define CC1120_DCFILTOFFSET_I0 (CC1120_EXTENDED_BIT | 0x6A) +#define CC1120_DCFILTOFFSET_Q1 (CC1120_EXTENDED_BIT | 0x6B) +#define CC1120_DCFILTOFFSET_Q0 (CC1120_EXTENDED_BIT | 0x6C) +#define CC1120_IQIE_I1 (CC1120_EXTENDED_BIT | 0x6D) +#define CC1120_IQIE_I0 (CC1120_EXTENDED_BIT | 0x6E) +#define CC1120_IQIE_Q1 (CC1120_EXTENDED_BIT | 0x6f) +#define CC1120_IQIE_Q0 (CC1120_EXTENDED_BIT | 0x70) +#define CC1120_RSSI1 (CC1120_EXTENDED_BIT | 0x71) +#define CC1120_RSSI0 (CC1120_EXTENDED_BIT | 0x72) +#define CC1120_MARCSTATE (CC1120_EXTENDED_BIT | 0x73) +#define CC1120_LQI_VAL (CC1120_EXTENDED_BIT | 0x74) +#define CC1120_PQT_SYNC_ERR (CC1120_EXTENDED_BIT | 0x75) +#define CC1120_DEM_STATUS (CC1120_EXTENDED_BIT | 0x76) +#define CC1120_FREQOFF_EST1 (CC1120_EXTENDED_BIT | 0x77) +#define CC1120_FREQOFF_EST0 (CC1120_EXTENDED_BIT | 0x78) +#define CC1120_AGC_GAIN3 (CC1120_EXTENDED_BIT | 0x79) +#define CC1120_AGC_GAIN2 (CC1120_EXTENDED_BIT | 0x7a) +#define CC1120_AGC_GAIN1 (CC1120_EXTENDED_BIT | 0x7b) +#define CC1120_AGC_GAIN0 (CC1120_EXTENDED_BIT | 0x7c) +#define CC1120_SOFT_RX_DATA_OUT (CC1120_EXTENDED_BIT | 0x7d) +#define CC1120_SOFT_TX_DATA_IN (CC1120_EXTENDED_BIT | 0x7e) +#define CC1120_ASK_SOFT_RX_DATA (CC1120_EXTENDED_BIT | 0x7f) +#define CC1120_RNDGEN (CC1120_EXTENDED_BIT | 0x80) +#define CC1120_MAGN2 (CC1120_EXTENDED_BIT | 0x81) +#define CC1120_MAGN1 (CC1120_EXTENDED_BIT | 0x82) +#define CC1120_MAGN0 (CC1120_EXTENDED_BIT | 0x83) +#define CC1120_ANG1 (CC1120_EXTENDED_BIT | 0x84) +#define CC1120_ANG0 (CC1120_EXTENDED_BIT | 0x85) +#define CC1120_CHFILT_I2 (CC1120_EXTENDED_BIT | 0x86) +#define CC1120_CHFILT_I1 (CC1120_EXTENDED_BIT | 0x87) +#define CC1120_CHFILT_I0 (CC1120_EXTENDED_BIT | 0x88) +#define CC1120_CHFILT_Q2 (CC1120_EXTENDED_BIT | 0x89) +#define CC1120_CHFILT_Q1 (CC1120_EXTENDED_BIT | 0x8a) +#define CC1120_CHFILT_Q0 (CC1120_EXTENDED_BIT | 0x8b) +#define CC1120_GPIO_STATUS (CC1120_EXTENDED_BIT | 0x8c) +#define CC1120_FSCAL_CTRL (CC1120_EXTENDED_BIT | 0x8d) +#define CC1120_PHASE_ADJUST (CC1120_EXTENDED_BIT | 0x8e) +#define CC1120_PARTNUMBER (CC1120_EXTENDED_BIT | 0x8f) +#define CC1120_PARTVERSION (CC1120_EXTENDED_BIT | 0x90) +#define CC1120_SERIAL_STATUS (CC1120_EXTENDED_BIT | 0x91) +#define CC1120_RX_STATUS (CC1120_EXTENDED_BIT | 0x92) +#define CC1120_TX_STATUS (CC1120_EXTENDED_BIT | 0x93) +#define CC1120_MARC_STATUS1 (CC1120_EXTENDED_BIT | 0x94) +#define CC1120_MARC_STATUS0 (CC1120_EXTENDED_BIT | 0x95) +#define CC1120_PA_IFAMP_TEST (CC1120_EXTENDED_BIT | 0x96) +#define CC1120_FSRF_TEST (CC1120_EXTENDED_BIT | 0x97) +#define CC1120_PRE_TEST (CC1120_EXTENDED_BIT | 0x98) +#define CC1120_PRE_OVR (CC1120_EXTENDED_BIT | 0x99) +#define CC1120_ADC_TEST (CC1120_EXTENDED_BIT | 0x9a) +#define CC1120_DVC_TEST (CC1120_EXTENDED_BIT | 0x9b) +#define CC1120_ATEST (CC1120_EXTENDED_BIT | 0x9c) +#define CC1120_ATEST_LVDS (CC1120_EXTENDED_BIT | 0x9d) +#define CC1120_ATEST_MODE (CC1120_EXTENDED_BIT | 0x9e) +#define CC1120_XOSC_TEST1 (CC1120_EXTENDED_BIT | 0x9f) +#define CC1120_XOSC_TEST0 (CC1120_EXTENDED_BIT | 0xa0) +#define CC1120_RXFIRST (CC1120_EXTENDED_BIT | 0xd2) +#define CC1120_TXFIRST (CC1120_EXTENDED_BIT | 0xd3) +#define CC1120_RXLAST (CC1120_EXTENDED_BIT | 0xd4) +#define CC1120_TXLAST (CC1120_EXTENDED_BIT | 0xd5) +#define CC1120_NUM_TXBYTES (CC1120_EXTENDED_BIT | 0xd6) +#define CC1120_NUM_RXBYTES (CC1120_EXTENDED_BIT | 0xd7) +#define CC1120_FIFO_NUM_TXBYTES (CC1120_EXTENDED_BIT | 0xd8) +#define CC1120_FIFO_NUM_RXBYTES (CC1120_EXTENDED_BIT | 0xd9) + +/* Status byte */ +#define CC1120_STATUS_CHIP_RDY 7 +#define CC1120_STATUS_STATE 4 +#define CC1120_STATUS_STATE_IDLE 0 +#define CC1120_STATUS_STATE_RX 1 +#define CC1120_STATUS_STATE_TX 2 +#define CC1120_STATUS_STATE_FSTXON 3 +#define CC1120_STATUS_STATE_CALIBRATE 4 +#define CC1120_STATUS_STATE_SETTLING 5 +#define CC1120_STATUS_STATE_RX_FIFO_ERROR 6 +#define CC1120_STATUS_STATE_TX_FIFO_ERROR 7 +#define CC1120_STATUS_STATE_MASK 7 + +#endif /* _AO_CC1120_H_ */ diff --git a/src/drivers/ao_cc1120_CC1120.h b/src/drivers/ao_cc1120_CC1120.h new file mode 100644 index 00000000..a96c22fc --- /dev/null +++ b/src/drivers/ao_cc1120_CC1120.h @@ -0,0 +1,191 @@ +/* RX filter BW = 100.000000 */
+/* Address config = No address check */
+/* Packet length = 255 */
+/* Symbol rate = 38.3606 */
+/* PA ramping = false */
+/* Carrier frequency = 434.549988 */
+/* Bit rate = 38.3606 */
+/* Whitening = true */
+/* Manchester enable = false */
+/* Modulation format = 2-GFSK */
+/* Packet length mode = Variable */
+/* Device address = 0 */
+/* TX power = 15 */
+/* Deviation = 20.507812 */
+/***************************************************************
+ * SmartRF Studio(tm) Export
+ *
+ * Radio register settings specifed with address, value
+ *
+ * RF device: CC1120
+ *
+ ***************************************************************/
+
+
+ CC1120_SYNC3, 0x93, /* Sync Word Configuration [31:24] */
+ CC1120_SYNC2, 0x0b, /* Sync Word Configuration [23:16] */
+ CC1120_SYNC1, 0x51, /* Sync Word Configuration [15:8] */
+ CC1120_SYNC0, 0xde, /* Sync Word Configuration [7:0] */
+ CC1120_SYNC_CFG1, 0x08, /* Sync Word Detection Configuration */
+ CC1120_SYNC_CFG0, 0x17, /* Sync Word Length Configuration */
+ CC1120_DEVIATION_M, 0x50, /* Frequency Deviation Configuration */
+ CC1120_MODCFG_DEV_E, 0x0d, /* Modulation Format and Frequency Deviation Configuration */
+ CC1120_DCFILT_CFG, 0x1c, /* Digital DC Removal Configuration */
+ CC1120_PREAMBLE_CFG1, 0x18, /* Preamble Length Configuration */
+ CC1120_PREAMBLE_CFG0, 0x2a, /* */
+ CC1120_FREQ_IF_CFG, 0x40, /* RX Mixer Frequency Configuration */
+ CC1120_IQIC, 0x46, /* Digital Image Channel Compensation Configuration */
+ CC1120_CHAN_BW, 0x02, /* Channel Filter Configuration */
+ CC1120_MDMCFG1, 0x46, /* General Modem Parameter Configuration */
+ CC1120_MDMCFG0, 0x05, /* General Modem Parameter Configuration */
+ CC1120_DRATE2, 0x93, /* Data Rate Configuration Exponent and Mantissa [19:16] */
+ CC1120_DRATE1, 0xa4, /* Data Rate Configuration Mantissa [15:8] */
+ CC1120_DRATE0, 0x00, /* Data Rate Configuration Mantissa [7:0] */
+ CC1120_AGC_REF, 0x20, /* AGC Reference Level Configuration */
+ CC1120_AGC_CS_THR, 0x19, /* Carrier Sense Threshold Configuration */
+ CC1120_AGC_GAIN_ADJUST, 0x00, /* RSSI Offset Configuration */
+ CC1120_AGC_CFG3, 0x91, /* AGC Configuration */
+ CC1120_AGC_CFG2, 0x20, /* AGC Configuration */
+ CC1120_AGC_CFG1, 0xa9, /* AGC Configuration */
+ CC1120_AGC_CFG0, 0xcf, /* AGC Configuration */
+ CC1120_FIFO_CFG, 0x00, /* FIFO Configuration */
+ CC1120_DEV_ADDR, 0x00, /* Device Address Configuration */
+ CC1120_SETTLING_CFG, 0x03, /* Frequency Synthesizer Calibration and Settling Configuration */
+ CC1120_FS_CFG, 0x14, /* Frequency Synthesizer Configuration */
+ CC1120_WOR_CFG1, 0x08, /* eWOR Configuration, Reg 1 */
+ CC1120_WOR_CFG0, 0x21, /* eWOR Configuration, Reg 0 */
+ CC1120_WOR_EVENT0_MSB, 0x00, /* Event 0 Configuration */
+ CC1120_WOR_EVENT0_LSB, 0x00, /* Event 0 Configuration */
+ CC1120_PKT_CFG2, 0x04, /* Packet Configuration, Reg 2 */
+ CC1120_PKT_CFG1, 0x45, /* Packet Configuration, Reg 1 */
+ CC1120_PKT_CFG0, 0x20, /* Packet Configuration, Reg 0 */
+ CC1120_RFEND_CFG1, 0x0f, /* RFEND Configuration, Reg 1 */
+ CC1120_RFEND_CFG0, 0x00, /* RFEND Configuration, Reg 0 */
+ CC1120_PA_CFG2, 0x3f, /* Power Amplifier Configuration, Reg 2 */
+ CC1120_PA_CFG1, 0x56, /* Power Amplifier Configuration, Reg 1 */
+ CC1120_PA_CFG0, 0x7b, /* Power Amplifier Configuration, Reg 0 */
+ CC1120_PKT_LEN, 0xff, /* Packet Length Configuration */
+ CC1120_IF_MIX_CFG, 0x00, /* IF Mix Configuration */
+ CC1120_FREQOFF_CFG, 0x22, /* Frequency Offset Correction Configuration */
+ CC1120_TOC_CFG, 0x0b, /* Timing Offset Correction Configuration */
+ CC1120_MARC_SPARE, 0x00, /* MARC Spare */
+ CC1120_ECG_CFG, 0x00, /* External Clock Frequency Configuration */
+ CC1120_SOFT_TX_DATA_CFG, 0x00, /* Soft TX Data Configuration */
+ CC1120_EXT_CTRL, 0x01, /* External Control Configuration */
+ CC1120_RCCAL_FINE, 0x00, /* RC Oscillator Calibration (fine) */
+ CC1120_RCCAL_COARSE, 0x00, /* RC Oscillator Calibration (coarse) */
+ CC1120_RCCAL_OFFSET, 0x00, /* RC Oscillator Calibration Clock Offset */
+ CC1120_FREQOFF1, 0x00, /* Frequency Offset (MSB) */
+ CC1120_FREQOFF0, 0x00, /* Frequency Offset (LSB) */
+ CC1120_FREQ2, 0x6c, /* Frequency Configuration [23:16] */
+ CC1120_FREQ1, 0xa3, /* Frequency Configuration [15:8] */
+ CC1120_FREQ0, 0x33, /* Frequency Configuration [7:0] */
+ CC1120_IF_ADC2, 0x02, /* Analog to Digital Converter Configuration, Reg 2 */
+ CC1120_IF_ADC1, 0xa6, /* Analog to Digital Converter Configuration, Reg 1 */
+ CC1120_IF_ADC0, 0x04, /* Analog to Digital Converter Configuration, Reg 0 */
+ CC1120_FS_DIG1, 0x00, /* */
+ CC1120_FS_DIG0, 0x5f, /* */
+ CC1120_FS_CAL3, 0x00, /* */
+ CC1120_FS_CAL2, 0x20, /* */
+ CC1120_FS_CAL1, 0x40, /* */
+ CC1120_FS_CAL0, 0x0e, /* */
+ CC1120_FS_CHP, 0x28, /* Charge Pump Configuration */
+ CC1120_FS_DIVTWO, 0x03, /* Divide by 2 */
+ CC1120_FS_DSM1, 0x00, /* Digital Synthesizer Module Configuration, Reg 1 */
+ CC1120_FS_DSM0, 0x33, /* Digital Synthesizer Module Configuration, Reg 0 */
+ CC1120_FS_DVC1, 0xff, /* Divider Chain Configuration, Reg 1 */
+ CC1120_FS_DVC0, 0x17, /* Divider Chain Configuration, Reg 0 */
+ CC1120_FS_LBI, 0x00, /* Local Bias Configuration */
+ CC1120_FS_PFD, 0x50, /* Phase Frequency Detector Configuration */
+ CC1120_FS_PRE, 0x6e, /* Prescaler Configuration */
+ CC1120_FS_REG_DIV_CML, 0x14, /* */
+ CC1120_FS_SPARE, 0xac, /* */
+ CC1120_FS_VCO4, 0x14, /* VCO Configuration, Reg 4 */
+ CC1120_FS_VCO3, 0x00, /* VCO Configuration, Reg 3 */
+ CC1120_FS_VCO2, 0x00, /* VCO Configuration, Reg 2 */
+ CC1120_FS_VCO1, 0x00, /* VCO Configuration, Reg 1 */
+ CC1120_FS_VCO0, 0xb4, /* VCO Configuration, Reg 0 */
+ CC1120_GBIAS6, 0x00, /* Global Bias Configuration, Reg 6 */
+ CC1120_GBIAS5, 0x02, /* Global Bias Configuration, Reg 5 */
+ CC1120_GBIAS4, 0x00, /* Global Bias Configuration, Reg 4 */
+ CC1120_GBIAS3, 0x00, /* Global Bias Configuration, Reg 3 */
+ CC1120_GBIAS2, 0x10, /* Global Bias Configuration, Reg 2 */
+ CC1120_GBIAS1, 0x00, /* Global Bias Configuration, Reg 1 */
+ CC1120_GBIAS0, 0x00, /* Global Bias Configuration, Reg 0 */
+ CC1120_IFAMP, 0x01, /* Intermediate Frequency Amplifier Configuration */
+ CC1120_LNA, 0x01, /* Low Noise Amplifier Configuration */
+ CC1120_RXMIX, 0x01, /* RX Mixer Configuration */
+ CC1120_XOSC5, 0x0e, /* Crystal Oscillator Configuration, Reg 5 */
+ CC1120_XOSC4, 0xa0, /* Crystal Oscillator Configuration, Reg 4 */
+ CC1120_XOSC3, 0x03, /* Crystal Oscillator Configuration, Reg 3 */
+ CC1120_XOSC2, 0x04, /* Crystal Oscillator Configuration, Reg 2 */
+ CC1120_XOSC1, 0x01, /* Crystal Oscillator Configuration, Reg 1 */
+ CC1120_XOSC0, 0x00, /* Crystal Oscillator Configuration, Reg 0 */
+ CC1120_ANALOG_SPARE, 0x00, /* */
+ CC1120_PA_CFG3, 0x00, /* Power Amplifier Configuration, Reg 3 */
+ CC1120_WOR_TIME1, 0x00, /* eWOR Timer Status (MSB) */
+ CC1120_WOR_TIME0, 0x00, /* eWOR Timer Status (LSB) */
+ CC1120_WOR_CAPTURE1, 0x00, /* eWOR Timer Capture (MSB) */
+ CC1120_WOR_CAPTURE0, 0x00, /* eWOR Timer Capture (LSB) */
+ CC1120_BIST, 0x00, /* MARC BIST */
+ CC1120_DCFILTOFFSET_I1, 0x00, /* DC Filter Offset I (MSB) */
+ CC1120_DCFILTOFFSET_I0, 0x00, /* DC Filter Offset I (LSB) */
+ CC1120_DCFILTOFFSET_Q1, 0x00, /* DC Filter Offset Q (MSB) */
+ CC1120_DCFILTOFFSET_Q0, 0x00, /* DC Filter Offset Q (LSB) */
+ CC1120_IQIE_I1, 0x00, /* IQ Imbalance Value I (MSB) */
+ CC1120_IQIE_I0, 0x00, /* IQ Imbalance Value I (LSB) */
+ CC1120_IQIE_Q1, 0x00, /* IQ Imbalance Value Q (MSB) */
+ CC1120_IQIE_Q0, 0x00, /* IQ Imbalance Value Q (LSB) */
+ CC1120_RSSI1, 0x80, /* Received Signal Strength Indicator (MSB) */
+ CC1120_RSSI0, 0x00, /* Received Signal Strength Indicator (LSB) */
+ CC1120_MARCSTATE, 0x41, /* MARC State */
+ CC1120_LQI_VAL, 0x00, /* Link Quality Indicator Value */
+ CC1120_PQT_SYNC_ERR, 0xff, /* Preamble and Sync Word Error */
+ CC1120_DEM_STATUS, 0x00, /* Demodulator Status */
+ CC1120_FREQOFF_EST1, 0x00, /* Frequency Offset Estimate (MSB) */
+ CC1120_FREQOFF_EST0, 0x00, /* Frequency Offset Estimate (LSB) */
+ CC1120_AGC_GAIN3, 0x00, /* AGC Gain, Reg 3 */
+ CC1120_AGC_GAIN2, 0xd1, /* AGC Gain, Reg 2 */
+ CC1120_AGC_GAIN1, 0x00, /* AGC Gain, Reg 1 */
+ CC1120_AGC_GAIN0, 0x3f, /* AGC Gain, Reg 0 */
+ CC1120_SOFT_RX_DATA_OUT, 0x00, /* Soft Decision Symbol Data */
+ CC1120_SOFT_TX_DATA_IN, 0x00, /* Soft TX Data Input Register */
+ CC1120_ASK_SOFT_RX_DATA, 0x30, /* AGC ASK Soft Decision Output */
+ CC1120_RNDGEN, 0x7f, /* Random Number Value */
+ CC1120_MAGN2, 0x00, /* Signal Magnitude after CORDIC [16] */
+ CC1120_MAGN1, 0x00, /* Signal Magnitude after CORDIC [15:8] */
+ CC1120_MAGN0, 0x00, /* Signal Magnitude after CORDIC [7:0] */
+ CC1120_ANG1, 0x00, /* Signal Angular after CORDIC [9:8] */
+ CC1120_ANG0, 0x00, /* Signal Angular after CORDIC [7:0] */
+ CC1120_CHFILT_I2, 0x08, /* Channel Filter Data Real Part [18:16] */
+ CC1120_CHFILT_I1, 0x00, /* Channel Filter Data Real Part [15:8] */
+ CC1120_CHFILT_I0, 0x00, /* Channel Filter Data Real Part [7:0] */
+ CC1120_CHFILT_Q2, 0x00, /* Channel Filter Data Imaginary Part [18:16] */
+ CC1120_CHFILT_Q1, 0x00, /* Channel Filter Data Imaginary Part [15:8] */
+ CC1120_CHFILT_Q0, 0x00, /* Channel Filter Data Imaginary Part [7:0] */
+ CC1120_GPIO_STATUS, 0x00, /* GPIO Status */
+ CC1120_FSCAL_CTRL, 0x01, /* */
+ CC1120_PHASE_ADJUST, 0x00, /* */
+ CC1120_PARTNUMBER, 0x00, /* Part Number */
+ CC1120_PARTVERSION, 0x00, /* Part Revision */
+ CC1120_SERIAL_STATUS, 0x00, /* Serial Status */
+ CC1120_RX_STATUS, 0x01, /* RX Status */
+ CC1120_TX_STATUS, 0x00, /* TX Status */
+ CC1120_MARC_STATUS1, 0x00, /* MARC Status, Reg 1 */
+ CC1120_MARC_STATUS0, 0x00, /* MARC Status, Reg 0 */
+ CC1120_PA_IFAMP_TEST, 0x00, /* */
+ CC1120_FSRF_TEST, 0x00, /* */
+ CC1120_PRE_TEST, 0x00, /* */
+ CC1120_PRE_OVR, 0x00, /* */
+ CC1120_ADC_TEST, 0x00, /* ADC Test */
+ CC1120_DVC_TEST, 0x0b, /* DVC Test */
+ CC1120_ATEST, 0x40, /* */
+ CC1120_ATEST_LVDS, 0x00, /* */
+ CC1120_ATEST_MODE, 0x00, /* */
+ CC1120_XOSC_TEST1, 0x3c, /* */
+ CC1120_XOSC_TEST0, 0x00, /* */
+ CC1120_RXFIRST, 0x00, /* RX FIFO Pointer (first entry) */
+ CC1120_TXFIRST, 0x00, /* TX FIFO Pointer (first entry) */
+ CC1120_RXLAST, 0x00, /* RX FIFO Pointer (last entry) */
+ CC1120_TXLAST, 0x00, /* TX FIFO Pointer (last entry) */
+
diff --git a/src/drivers/ao_packet.c b/src/drivers/ao_packet.c new file mode 100644 index 00000000..19fe0558 --- /dev/null +++ b/src/drivers/ao_packet.c @@ -0,0 +1,163 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +__xdata struct ao_packet_recv ao_rx_packet; +__xdata struct ao_packet ao_tx_packet; +__pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used; + +static __xdata char tx_data[AO_PACKET_MAX]; +static __xdata char rx_data[AO_PACKET_MAX]; +static __pdata uint8_t rx_seq; + +__xdata struct ao_task ao_packet_task; +__xdata uint8_t ao_packet_enable; +__xdata uint8_t ao_packet_master_sleeping; + +void +ao_packet_send(void) +{ +#ifdef AO_LED_RED + ao_led_on(AO_LED_RED); +#endif + /* If any tx data is pending then copy it into the tx packet */ + if (ao_packet_tx_used && ao_tx_packet.len == 0) { + ao_xmemcpy(&ao_tx_packet.d, tx_data, ao_packet_tx_used); + ao_tx_packet.len = ao_packet_tx_used; + ao_tx_packet.seq++; + ao_packet_tx_used = 0; + ao_wakeup(&tx_data); + } + ao_radio_send(&ao_tx_packet, sizeof (ao_tx_packet)); +#ifdef AO_LED_RED + ao_led_off(AO_LED_RED); +#endif +} + +uint8_t +ao_packet_recv(void) +{ + uint8_t dma_done; + +#ifdef AO_LED_GREEN + ao_led_on(AO_LED_GREEN); +#endif + dma_done = ao_radio_recv(&ao_rx_packet, sizeof (struct ao_packet_recv)); +#ifdef AO_LED_GREEN + ao_led_off(AO_LED_GREEN); +#endif + + /* Check to see if we got a valid packet */ + if (!dma_done) + return 0; +#ifdef PKT_APPEND_STATUS_1_CRC_OK + if (!(ao_rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK)) + return 0; +#endif + + /* Accept packets with matching call signs, or any packet if + * our callsign hasn't been configured + */ + if (ao_xmemcmp(ao_rx_packet.packet.callsign, + ao_config.callsign, + AO_MAX_CALLSIGN) != 0 && + ao_xmemcmp(ao_config.callsign, CODE_TO_XDATA("N0CALL"), 7) != 0) + return 0; + + /* SYN packets carry no data */ + if (ao_rx_packet.packet.len == AO_PACKET_SYN) { + rx_seq = ao_rx_packet.packet.seq; + ao_tx_packet.seq = ao_rx_packet.packet.ack; + ao_tx_packet.ack = rx_seq; + } else if (ao_rx_packet.packet.len) { + + /* Check for incoming data at the next sequence and + * for an empty data buffer + */ + if (ao_rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) && + ao_packet_rx_used == ao_packet_rx_len) { + + /* Copy data to the receive data buffer and set up the + * offsets + */ + ao_xmemcpy(rx_data, ao_rx_packet.packet.d, ao_rx_packet.packet.len); + ao_packet_rx_used = 0; + ao_packet_rx_len = ao_rx_packet.packet.len; + + /* Mark the sequence that we've received to + * let the sender know when we return a packet + */ + rx_seq = ao_rx_packet.packet.seq; + ao_tx_packet.ack = rx_seq; + + /* Poke anyone looking for received data */ + ao_wakeup(&ao_stdin_ready); + } + } + + /* If the other side has seen the latest data we queued, + * wake up any task waiting to send data and let them go again + */ + if (ao_rx_packet.packet.ack == ao_tx_packet.seq) { + ao_tx_packet.len = 0; + ao_wakeup(&ao_tx_packet); + } + return 1; +} + +#ifndef PACKET_HAS_MASTER +#define PACKET_HAS_MASTER 1 +#endif + +#if PACKET_HAS_MASTER +void +ao_packet_flush(void) +{ + /* If there is data to send, and this is the master, + * then poke the master to send all queued data + */ + if (ao_packet_tx_used && ao_packet_master_sleeping) + ao_wakeup(&ao_packet_master_sleeping); +} +#endif /* PACKET_HAS_MASTER */ + +void +ao_packet_putchar(char c) __reentrant +{ + while (ao_packet_tx_used == AO_PACKET_MAX && ao_packet_enable) { +#if PACKET_HAS_MASTER + ao_packet_flush(); +#endif + ao_sleep(&tx_data); + } + + if (ao_packet_enable) + tx_data[ao_packet_tx_used++] = c; +} + +char +ao_packet_pollchar(void) __critical +{ + if (!ao_packet_enable) + return AO_READ_AGAIN; + + if (ao_packet_rx_used == ao_packet_rx_len) + return AO_READ_AGAIN; + + return rx_data[ao_packet_rx_used++]; +} diff --git a/src/drivers/ao_packet_master.c b/src/drivers/ao_packet_master.c new file mode 100644 index 00000000..66f94288 --- /dev/null +++ b/src/drivers/ao_packet_master.c @@ -0,0 +1,151 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +static char +ao_packet_getchar(void) __critical +{ + char c; + while ((c = ao_packet_pollchar()) == AO_READ_AGAIN) { + if (!ao_packet_enable) + break; + if (ao_packet_master_sleeping) + ao_wakeup(&ao_packet_master_sleeping); + flush(); + ao_sleep(&ao_stdin_ready); + } + return c; +} + +static void +ao_packet_echo(void) __reentrant +{ + char c; + while (ao_packet_enable) { + c = ao_packet_getchar(); + if (c != AO_READ_AGAIN) + putchar(c); + } + ao_exit(); +} + +static __xdata struct ao_task ao_packet_echo_task; +static __xdata uint16_t ao_packet_master_delay; +static __xdata uint16_t ao_packet_master_time; + +#define AO_PACKET_MASTER_DELAY_SHORT AO_MS_TO_TICKS(100) +#define AO_PACKET_MASTER_DELAY_LONG AO_MS_TO_TICKS(1000) +#define AO_PACKET_MASTER_DELAY_TIMEOUT AO_MS_TO_TICKS(2000) + +static void +ao_packet_master_busy(void) +{ + ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT; + ao_packet_master_time = ao_time(); +} + +static void +ao_packet_master_check_busy(void) +{ + int16_t idle; + if (ao_packet_master_delay != AO_PACKET_MASTER_DELAY_SHORT) + return; + idle = (int16_t) (ao_time() - ao_packet_master_time); + + if (idle > AO_PACKET_MASTER_DELAY_TIMEOUT) + ao_packet_master_delay = AO_PACKET_MASTER_DELAY_LONG; +} + +void +ao_packet_master(void) +{ + ao_config_get(); + ao_tx_packet.addr = ao_serial_number; + ao_tx_packet.len = AO_PACKET_SYN; + ao_packet_master_time = ao_time(); + ao_packet_master_delay = AO_PACKET_MASTER_DELAY_SHORT; + while (ao_packet_enable) { + uint8_t r; + ao_xmemcpy(ao_tx_packet.callsign, ao_config.callsign, AO_MAX_CALLSIGN); + ao_packet_send(); + if (ao_tx_packet.len) + ao_packet_master_busy(); + ao_packet_master_check_busy(); + ao_alarm(ao_packet_master_delay); + r = ao_packet_recv(); + ao_clear_alarm(); + if (r) { + /* if we can transmit data, do so */ + if (ao_packet_tx_used && ao_tx_packet.len == 0) + continue; + if (ao_rx_packet.packet.len) + ao_packet_master_busy(); + ao_packet_master_sleeping = 1; + ao_alarm(ao_packet_master_delay); + ao_sleep(&ao_packet_master_sleeping); + ao_clear_alarm(); + ao_packet_master_sleeping = 0; + } + } + ao_exit(); +} + +static void +ao_packet_forward(void) __reentrant +{ + char c; + ao_packet_enable = 1; + ao_cmd_white(); + + flush(); +#if HAS_MONITOR + ao_monitor_disable(); +#endif + ao_add_task(&ao_packet_task, ao_packet_master, "master"); + ao_add_task(&ao_packet_echo_task, ao_packet_echo, "echo"); + while ((c = getchar()) != '~') { + if (c == '\r') c = '\n'; + ao_packet_putchar(c); + } + + /* Wait for a second if there is any pending data */ + for (c = 0; (ao_packet_tx_used || ao_tx_packet.len) && c < 10; c++) + ao_delay(AO_MS_TO_TICKS(100)); + ao_packet_enable = 0; + while (ao_packet_echo_task.wchan || ao_packet_task.wchan) { + ao_radio_recv_abort(); + ao_wakeup(&ao_stdin_ready); + ao_delay(AO_MS_TO_TICKS(10)); + } +#if HAS_MONITOR + ao_monitor_enable(); +#endif +} + + + +__code struct ao_cmds ao_packet_master_cmds[] = { + { ao_packet_forward, "p\0Remote packet link." }, + { 0, NULL }, +}; + +void +ao_packet_master_init(void) +{ + ao_cmd_register(&ao_packet_master_cmds[0]); +} diff --git a/src/drivers/ao_packet_slave.c b/src/drivers/ao_packet_slave.c new file mode 100644 index 00000000..fd5d443e --- /dev/null +++ b/src/drivers/ao_packet_slave.c @@ -0,0 +1,66 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +void +ao_packet_slave(void) +{ + ao_tx_packet.addr = ao_serial_number; + ao_tx_packet.len = AO_PACKET_SYN; + while (ao_packet_enable) { + if (ao_packet_recv()) { + ao_xmemcpy(&ao_tx_packet.callsign, &ao_rx_packet.packet.callsign, AO_MAX_CALLSIGN); +#if HAS_FLIGHT + ao_flight_force_idle = TRUE; +#endif + ao_packet_send(); + } + } + ao_exit(); +} + +void +ao_packet_slave_start(void) +{ + if (!ao_packet_enable) { + ao_packet_enable = 1; + ao_add_task(&ao_packet_task, ao_packet_slave, "slave"); + } +} + +void +ao_packet_slave_stop(void) +{ + if (ao_packet_enable) { + ao_packet_enable = 0; + while (ao_packet_task.wchan) { + ao_radio_recv_abort(); + ao_delay(AO_MS_TO_TICKS(10)); + } + } +} + +void +ao_packet_slave_init(uint8_t enable) +{ + ao_add_stdio(ao_packet_pollchar, + ao_packet_putchar, + NULL); + if (enable) + ao_packet_slave_start(); +} |