void radio_init(uint8_t * rxbuf, uint8_t rxbufsz) { trx_regval_t status; /* init cpu peripherals and global IRQ enable */ radiostatus.rxframe = rxbuf; radiostatus.rxframesz = rxbufsz; //trx_set_irq_handler(radio_irq_handler); /* transceiver initialization */ TRX_RESET_LOW(); TRX_SLPTR_LOW(); DELAY_US(TRX_RESET_TIME_US); #if defined(CUSTOM_RESET_TIME_MS) DELAY_MS(CUSTOM_RESET_TIME_MS); #endif TRX_RESET_HIGH(); /* disable IRQ and clear any pending IRQs */ trx_reg_write(RG_IRQ_MASK, 0); trx_reg_read(RG_IRQ_STATUS); trx_bit_write(SR_TRX_CMD, CMD_TRX_OFF); DELAY_US(510); status = trx_bit_read(SR_TRX_STATUS); if (status != TRX_OFF) { radio_error(STATE_SET_FAILED); } trx_bit_write(SR_TX_AUTO_CRC_ON, 1); trx_reg_write(RG_IRQ_MASK, TRX_IRQ_RX_START | TRX_IRQ_RX_END | TRX_IRQ_TX_END); radiostatus.state = STATE_OFF; radiostatus.idle_state = STATE_OFF; }
void radio_set_param(radio_attribute_t attr, radio_param_t parm) { switch (attr) { case phyCurrentChannel: if (((int)parm.channel >= TRX_MIN_CHANNEL) && ((int)parm.channel <= TRX_MAX_CHANNEL)) { #ifdef CHINABAND trx_reg_write(RG_CC_CTRL_1, CCBAND); trx_reg_write(RG_CC_CTRL_0, parm.channel*2+CCNUMBER); #else trx_bit_write(SR_CHANNEL, parm.channel); #endif radiostatus.channel = parm.channel; } else { radio_error(SET_PARM_FAILED); } break; case phyTransmitPower: #if RADIO_TYPE == RADIO_AT86RF212 #ifdef CHINABAND if (parm.tx_pwr >= -11 && parm.tx_pwr <= 8) { /** @todo move this into a radio-specific header file */ static const uint8_t pwrtable[] = { 0x0A, 0x09, 0x08, /* -11...-9 dBm */ 0x07, 0x06, 0x05, /* -8...-6 dBm */ 0x04, 0x03, 0x25, /* -5...-3 dBm */ 0x46, 0xAC, 0xAB, /* -2...0 dBm */ 0xAA, /* 1 dBm */ 0xCA, /* 2 dBm */ 0xEA, /* 3 dBm */ 0xE9, /* 4 dBm */ 0xE8, /* 5 dBm */ 0xE6, /* 6 dBm */ 0xE5, /* 7 dBm */ 0xE4, /* 8 dBm */ }; radiostatus.tx_pwr = parm.tx_pwr; uint8_t idx = parm.tx_pwr + 11; uint8_t pwrval = pgm_read_byte(pwrtable[idx]); trx_reg_write(RG_PHY_TX_PWR, pwrval); } else { radio_error(SET_PARM_FAILED); } #endif//chinaband #else if (parm.tx_pwr >= -17 && parm.tx_pwr <= 3) { /** @todo move this into a radio-specific header file */ static const uint8_t pwrtable[] = { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, /* -17...-13 dBm */ 0x0E, 0x0E, 0x0E, /* -12...-10 dBm */ 0x0D, 0x0D, /* -9...-8 dBm */ 0x0C, 0x0C, /* -7...-6 dBm */ 0x0B, /* -5 dBm */ 0x0A, /* -4 dBm */ 0x09, /* -3 dBm */ 0x08, /* -2 dBm */ 0x07, /* -1 dBm */ 0x06, /* 0 dBm */ 0x04, /* 1 dBm */ 0x02, /* 2 dBm */ 0x00 /* 3 dBm */ }; radiostatus.tx_pwr = parm.tx_pwr; uint8_t idx = parm.tx_pwr + 17; uint8_t pwrval = pgm_read_byte(pwrtable[idx]); trx_bit_write(SR_TX_PWR, pwrval); } else { radio_error(SET_PARM_FAILED); } #endif//rf212 break; case phyCCAMode: if (parm.cca_mode <= 3) { radiostatus.cca_mode = parm.cca_mode; trx_bit_write(SR_CCA_MODE, radiostatus.cca_mode); } else { radio_error(SET_PARM_FAILED); } break; case phyIdleState: radiostatus.idle_state = parm.idle_state; radio_set_state(parm.idle_state); break; case phyChannelsSupported: break; case phyPanId: trx_set_panid(parm.pan_id); break; case phyShortAddr: trx_set_shortaddr(parm.short_addr); break; case phyLongAddr: { uint8_t regno, *ap; for (regno = RG_IEEE_ADDR_0, ap = (uint8_t *)parm.long_addr; regno <= RG_IEEE_ADDR_7; regno++, ap++) trx_reg_write(regno, *ap); break; } case phyDataRate: trx_set_datarate(parm.data_rate); break; default: radio_error(SET_PARM_FAILED); break; } }
void radio_set_state(volatile radio_state_t state) { volatile trx_regval_t cmd, expstatus, currstatus; uint8_t retries; bool do_sleep = false; switch(state) { case STATE_OFF: expstatus = TRX_OFF; cmd = CMD_TRX_OFF; break; case STATE_RX: expstatus = RX_ON; cmd = CMD_RX_ON; break; case STATE_TX: expstatus = PLL_ON; cmd = CMD_PLL_ON; break; case STATE_RXAUTO: expstatus = RX_AACK_ON; cmd = CMD_RX_AACK_ON; break; case STATE_TXAUTO: expstatus = TX_ARET_ON; cmd = CMD_TX_ARET_ON; break; case STATE_SLEEP: expstatus = TRX_OFF; cmd = CMD_FORCE_TRX_OFF; do_sleep = true; break; default: radio_error(GENERAL_ERROR); expstatus = TRX_OFF; cmd = CMD_TRX_OFF; break; } if (STATE_SLEEP == radiostatus.state) { if (do_sleep) { return; } TRX_SLPTR_LOW(); /* * Give the xosc some time to start up. Once it started, the * SPI interface is operational, and the transceiver state can * be polled. The state reads as 0b0011111 ("state transition * in progress") while the transceiver is still in its startup * phase, which does not match any of the "expstatus" values, * so polling just continues. */ DELAY_US(500); /* * The exact wake-up timing is very board-dependent. * Contributing parameters are the effective series resitance * of the crystal, and the external bypass capacitor that has * to be charged by the voltage regulator. Give the crystal * oscillator some time to start up. 5 ms (100 * 50 us) ought * to be enough under all circumstances. */ retries = 100; do { currstatus = trx_bit_read(SR_TRX_STATUS); /* * Sleep could only be entered from TRX_OFF, so that's * what is expected again. */ if (TRX_OFF == currstatus) { break; } DELAY_US(50); } while (--retries); if (currstatus != TRX_OFF) { /* radio didn't wake up */ radio_error(STATE_SET_FAILED); } } trx_bit_write(SR_TRX_CMD, cmd); retries = 140; /* enough to await an ongoing frame * reception */ do { currstatus = trx_bit_read(SR_TRX_STATUS); if (expstatus == currstatus) { break; } /** @todo must wait longer for 790/868/900 MHz radios */ DELAY_US(32); } while (--retries); if (expstatus != currstatus) { radio_error(STATE_SET_FAILED); } if (do_sleep) { TRX_SLPTR_HIGH(); } radiostatus.state = state; }
void radio_set_param(radio_attribute_t attr, radio_param_t parm) { switch (attr) { case phyCurrentChannel: if (((int)parm.channel >= TRX_MIN_CHANNEL) && ((int)parm.channel <= TRX_MAX_CHANNEL)) { trx_bit_write(SR_CHANNEL, parm.channel); radiostatus.channel = parm.channel; } else { radio_error(SET_PARM_FAILED); } break; case phyTransmitPower: if (parm.tx_pwr >= -17 && parm.tx_pwr <= 3) { /** @todo move this into a radio-specific header file */ static const uint8_t pwrtable[] = { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, /* -17...-13 dBm */ 0x0E, 0x0E, 0x0E, /* -12...-10 dBm */ 0x0D, 0x0D, /* -9...-8 dBm */ 0x0C, 0x0C, /* -7...-6 dBm */ 0x0B, /* -5 dBm */ 0x0A, /* -4 dBm */ 0x09, /* -3 dBm */ 0x08, /* -2 dBm */ 0x07, /* -1 dBm */ 0x06, /* 0 dBm */ 0x04, /* 1 dBm */ 0x02, /* 2 dBm */ 0x00 /* 3 dBm */ }; radiostatus.tx_pwr = parm.tx_pwr; uint8_t idx = parm.tx_pwr + 17; uint8_t pwrval = pgm_read_byte(pwrtable[idx]); trx_bit_write(SR_TX_PWR, pwrval); } else { radio_error(SET_PARM_FAILED); } break; case phyCCAMode: if (parm.cca_mode <= 3) { radiostatus.cca_mode = parm.cca_mode; trx_bit_write(SR_CCA_MODE, radiostatus.cca_mode); } else { radio_error(SET_PARM_FAILED); } break; case phyIdleState: radiostatus.idle_state = parm.idle_state; radio_set_state(parm.idle_state); break; case phyChannelsSupported: break; case phyPanId: trx_set_panid(parm.pan_id); break; case phyShortAddr: trx_set_shortaddr(parm.short_addr); break; case phyLongAddr: { uint8_t regno, *ap; for (regno = RG_IEEE_ADDR_0, ap = (uint8_t *)parm.long_addr; regno <= RG_IEEE_ADDR_7; regno++, ap++) trx_reg_write(regno, *ap); break; } case phyDataRate: trx_set_datarate(parm.data_rate); break; #ifdef TRX_TX_PA_EI case phyTxPa: radiostatus.tx_pa = parm.tx_pa; break; #endif #ifdef TRX_RX_LNA_EI case phyRxLna: radiostatus.rx_lna = parm.rx_lna; break; #endif default: radio_error(SET_PARM_FAILED); break; } }
void radio_set_state(radio_state_t state) { volatile trx_regval_t cmd, expstatus, currstatus; uint8_t retries; bool do_sleep = false; switch(state) { case STATE_OFF: expstatus = TRX_OFF; cmd = CMD_TRX_OFF; break; case STATE_RX: expstatus = RX_ON; cmd = CMD_RX_ON; break; case STATE_TX: expstatus = PLL_ON; cmd = CMD_PLL_ON; break; case STATE_RXAUTO: expstatus = RX_AACK_ON; cmd = CMD_RX_AACK_ON; break; case STATE_TXAUTO: expstatus = TX_ARET_ON; cmd = CMD_TX_ARET_ON; break; case STATE_SLEEP: expstatus = TRX_OFF; cmd = CMD_FORCE_TRX_OFF; do_sleep = true; break; default: radio_error(GENERAL_ERROR); expstatus = TRX_OFF; cmd = CMD_TRX_OFF; break; } if (STATE_SLEEP == radiostatus.state) { if (do_sleep) { return; } TRX_SLPTR_LOW(); /* * Give the xosc some time to start up. Once it started, the * SPI interface is operational, and the transceiver state can * be polled. The state reads as 0b0011111 ("state transition * in progress") while the transceiver is still in its startup * phase, which does not match any of the "expstatus" values, * so polling just continues. */ DELAY_US(500); } trx_bit_write(SR_TRX_CMD, cmd); retries = 140; /* enough to await an ongoing frame * reception */ do { currstatus = trx_bit_read(SR_TRX_STATUS); if (expstatus == currstatus) { break; } /** @todo must wait longer for 790/868/900 MHz radios */ DELAY_US(32); } while (--retries); if (expstatus != currstatus) { radio_error(STATE_SET_FAILED); } if (do_sleep) { TRX_SLPTR_HIGH(); } radiostatus.state = state; }