/** * \brief Switches the PLL on * \ingroup group_tal_state_machine_212b */ static void switch_pll_on(void) { trx_irq_reason_t irq_status; uint8_t poll_counter = 0; /* Check if trx is in TRX_OFF; only from PLL_ON the following procedure * is applicable */ if (trx_bit_read(SR_TRX_STATUS) != TRX_OFF) { Assert( "Switch PLL_ON failed, because trx is not in TRX_OFF" == 0); return; } trx_reg_read(RG_IRQ_STATUS); /* clear PLL lock bit */ /* Switch PLL on */ trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); /* Check if PLL has been locked. */ do { irq_status = (trx_irq_reason_t)trx_reg_read(RG_IRQ_STATUS); if (irq_status & TRX_IRQ_0_PLL_LOCK) { return; /* PLL is locked now */ } /* Wait a time interval of typical value for timer TR4. */ pal_timer_delay(TRX_OFF_TO_PLL_ON_TIME_US); poll_counter++; } while (poll_counter < PLL_LOCK_ATTEMPTS); }
/** * \brief Initializes the transceiver * * This function is called to initialize the transceiver. * * \return MAC_SUCCESS if the transceiver state is changed to TRX_OFF and the * current device part number and version number are correct; * FAILURE otherwise */ static retval_t trx_init(void) { tal_trx_status_t trx_status; uint8_t poll_counter = 0; TRX_RST_HIGH(); TRX_SLP_TR_LOW(); /* Wait typical time of timer TR1. */ pal_timer_delay(P_ON_TO_CLKM_AVAILABLE_TYP_US); /* Apply reset pulse */ TRX_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); TRX_RST_HIGH(); #if !(defined FPGA_EMULATION) do { /* Wait not more than max. value of TR1. */ if (poll_counter == P_ON_TO_CLKM_ATTEMPTS) { return FAILURE; } /* Wait a short time interval. */ pal_timer_delay(TRX_POLL_WAIT_TIME_US); poll_counter++; /* Check if AT86RF233 is connected; omit manufacturer id check **/ } while (trx_reg_read(RG_PART_NUM) != PART_NUM_AT86RF233); #endif /* !defined FPGA_EMULATION */ /* Verify that TRX_OFF can be written */ trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); /* Verify that the trx has reached TRX_OFF. */ poll_counter = 0; do { /* Wait a short time interval. */ pal_timer_delay(TRX_POLL_WAIT_TIME_US); trx_status = /*(tal_trx_status_t)*/ trx_bit_read(SR_TRX_STATUS); /* Wait not more than max. value of TR15. */ if (poll_counter == P_ON_TO_TRX_OFF_ATTEMPTS) { #if (_DEBUG_ > 0) Assert( "MAX Attempts to switch to TRX_OFF state reached" == 0); #endif return FAILURE; } poll_counter++; } while (trx_status != TRX_OFF); tal_trx_status = TRX_OFF; return MAC_SUCCESS; }
/** * @brief Frame reception * */ void radio_receive_frame(void) { uint8_t len, lqi, crc_fail; int8_t ed; /* @todo add RSSI_BASE_VALUE to get a dBm value */ ed = (int8_t)trx_reg_read(RG_PHY_ED_LEVEL); len = trx_frame_read(radiostatus.rxframe, radiostatus.rxframesz, &lqi); len &= ~0x80; #if defined(SR_RX_CRC_VALID) crc_fail = trx_bit_read(SR_RX_CRC_VALID) ? 0 : 1; #else uint8_t *frm, i; uint16_t crc; crc = 0; frm = radiostatus.rxframe; for (i=0; i < len; i++) { crc = CRC_CCITT_UPDATE(crc, *frm++); } crc_fail = (crc == 0)? 0: 1; #endif radiostatus.rxframe = usr_radio_receive_frame(len, radiostatus.rxframe, lqi, ed, crc_fail); }
/** * @brief Start CCA. * * @param parameter Pointer to trx_id */ static void cca_start(void *parameter) { trx_id_t trx_id = *(trx_id_t *)parameter; /* Check if trx is currently detecting a frame ota */ if (trx_state[trx_id] == RF_RX) { uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; uint8_t agc_freeze = trx_bit_read(reg_offset + SR_RF09_AGCC_FRZS); if (agc_freeze) { csma_continue(trx_id); } else { #ifdef SUPPORT_MODE_SWITCH if (tal_pib[trx_id].ModeSwitchEnabled) { trigger_cca_meaurement(trx_id); } else #endif { transmit_frame(trx_id, WITH_CCA); } } } else { #ifdef SUPPORT_MODE_SWITCH if (tal_pib[trx_id].ModeSwitchEnabled) { trigger_cca_meaurement(trx_id); } else #endif { transmit_frame(trx_id, WITH_CCA); } } }
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; }
/** * \brief Save all user settings before Start of CW transmission */ void save_all_settings(void) { #if (ANTENNA_DIVERSITY == 1) tal_get_curr_trx_config(ANT_DIVERSITY, &ant_div_before_ct); if (ANT_DIV_DISABLE == ant_div_before_ct) { tal_get_curr_trx_config(ANT_CTRL, &ant_sel_before_ct); } #endif #if (TAL_TYPE == AT86RF233) cc_band_ct = trx_bit_read(SR_CC_BAND); cc_number_ct = trx_bit_read(SR_CC_NUMBER); #endif /* End of #if(TAL_TYPE == AT86RF233) */ }
inline uint8_t trx_frame_read_data_crc(uint8_t *data, uint8_t datasz, uint8_t *lqi, bool *crc_ok) { if (crc_ok != NULL) { *crc_ok = (trx_bit_read(SR_RX_CRC_VALID) == 1); } return trx_frame_read(data, datasz, lqi); }
/* * \brief Perform a CCA * * This function performs a CCA request. * * \return phy_enum_t PHY_IDLE or PHY_BUSY */ phy_enum_t tfa_cca_perform(void) { tal_trx_status_t trx_status; uint8_t cca_status; uint8_t cca_done; /* Ensure that trx is not in SLEEP for register access */ do { trx_status = set_trx_state(CMD_TRX_OFF); } while (trx_status != TRX_OFF); /* no interest in receiving frames while doing CCA */ trx_bit_write(SR_RX_PDT_DIS, RX_DISABLE); /* disable frame reception * indication */ /* Set trx to rx mode. */ do { trx_status = set_trx_state(CMD_RX_ON); } while (trx_status != RX_ON); /* Start CCA */ trx_bit_write(SR_CCA_REQUEST, CCA_START); /* wait until CCA is done */ pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US(CCA_DURATION_SYM)); do { /* poll until CCA is really done */ cca_done = trx_bit_read(SR_CCA_DONE); } while (cca_done != CCA_DETECTION_DONE); set_trx_state(CMD_TRX_OFF); /* Check if channel was idle or busy. */ if (trx_bit_read(SR_CCA_STATUS) == CCA_STATUS_CHANNEL_IS_IDLE) { cca_status = PHY_IDLE; } else { cca_status = PHY_BUSY; } /* Enable frame reception again. */ trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); return (phy_enum_t)cca_status; }
/** * \brief Switches the PLL on * \ingroup group_tal_state_machine */ static void switch_pll_on(void) { uint32_t start_time; uint32_t current_time; /* Check if trx is in TRX_OFF; only from PLL_ON the following procedure * is applicable */ if (trx_bit_read(SR_TRX_STATUS) != TRX_OFF) { Assert( "Switch PLL_ON failed, because trx is not in TRX_OFF" == 0); return; } /* Clear all pending trx interrupts */ trx_reg_read(RG_IRQ_STATUS); /* Get current IRQ mask */ uint8_t trx_irq_mask = trx_reg_read(RG_IRQ_MASK); /* Enable transceiver's PLL lock interrupt */ trx_reg_write(RG_IRQ_MASK, TRX_IRQ_0_PLL_LOCK); ENTER_TRX_REGION(); /* Disable trx interrupt handling */ /* Switch PLL on */ trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); pal_get_current_time(&start_time); /* Wait for transceiver interrupt: check for IRQ line */ while (TRX_IRQ_HIGH() == false) { /* Handle errata "potential long PLL settling duration". */ pal_get_current_time(¤t_time); if (pal_sub_time_us(current_time, start_time) > PLL_LOCK_DURATION_MAX_US) { uint8_t reg_value; reg_value = trx_reg_read(RG_PLL_CF); if (reg_value & 0x01) { reg_value &= 0xFE; } else { reg_value |= 0x01; } trx_reg_write(RG_PLL_CF, reg_value); pal_get_current_time(&start_time); } /* Wait until trx line has been raised. */ } /* Clear PLL lock interrupt at trx */ trx_reg_read(RG_IRQ_STATUS); /* Clear MCU's interrupt flag */ pal_trx_irq_flag_clr(); LEAVE_TRX_REGION(); /* Enable trx interrupt handling again */ /* Restore transceiver's interrupt mask. */ trx_reg_write(RG_IRQ_MASK, trx_irq_mask); }
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_io_init(DEFAULT_SPI_RATE); 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); #if RADIO_TYPE == RADIO_AT86RF212 trx_reg_write(RG_TRX_CTRL_0, 0x19); #ifdef CHINABAND trx_reg_write(RG_CC_CTRL_1, CCBAND ); trx_reg_write(RG_CC_CTRL_0, CCNUMBER);//channel 0 trx_reg_write(RG_TRX_CTRL_2, TRX_OQPSK250); /*trx_bit_write(SR_OQPSK_SUB1_RC_EN,1); trx_bit_write(SR_BPSK_OQPSK,1); trx_bit_write(SR_SUB_MODE,1); trx_bit_write(SR_OQPSK_DATA_RATE,0); trx_bit_write(SR_CC_BAND,CCBAND); */ DELAY_US(510); #endif trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); DELAY_US(510); #else trx_bit_write(SR_TRX_CMD, CMD_TRX_OFF); DELAY_US(510); #endif do { status = trx_bit_read(SR_TRX_STATUS); } while (status != TRX_OFF); trx_bit_write(SR_TX_AUTO_CRC_ON, 1); trx_reg_write(RG_IRQ_MASK, TRX_IRQ_RX_START | TRX_IRQ_TRX_END); radiostatus.state = STATE_OFF; radiostatus.idle_state = STATE_OFF; }
/** * @brief Frame reception * */ void radio_receive_frame(void) { uint8_t len, lqi, crc_fail; crc_fail = trx_bit_read(SR_RX_CRC_VALID) ? 0 : 1; len = trx_frame_read(radiostatus.rxframe, radiostatus.rxframesz, &lqi); len &= ~0x80; radiostatus.rxframe = usr_radio_receive_frame(len, radiostatus.rxframe, lqi, crc_fail); }
/** * @brief IRQ handler for radio functions. * * This function is called in the transceiver interrupt routine. * Keep the implementation of the callback functions * (usr_radio_irq, usr_radio_receive_frame) short and efficient. * * @parm cause value of the interrupt status register * */ void radio_irq_handler(uint8_t cause) { if (cause & TRX_IRQ_TRX_END) { if (STATE_RX == radiostatus.state || STATE_RXAUTO == radiostatus.state) { radio_receive_frame(); } else if (STATE_TX == radiostatus.state) { #ifdef TRX_TX_PA_EI TRX_TX_PA_DI(); #endif usr_radio_tx_done(TX_OK); radio_set_state(radiostatus.idle_state); } else if (STATE_TXAUTO == radiostatus.state) { #ifdef TRX_TX_PA_EI TRX_TX_PA_DI(); #endif uint8_t trac_status = trx_bit_read(SR_TRAC_STATUS); uint8_t result; switch (trac_status) { case TRAC_SUCCESS: #if defined TRAC_SUCCESS_DATA_PENDING case TRAC_SUCCESS_DATA_PENDING: #endif #if defined TRAC_SUCCESS_WAIT_FOR_ACK case TRAC_SUCCESS_WAIT_FOR_ACK: #endif result = TX_OK; break; case TRAC_CHANNEL_ACCESS_FAILURE: result = TX_CCA_FAIL; break; case TRAC_NO_ACK: result = TX_NO_ACK; break; default: result = TX_FAIL; } usr_radio_tx_done(result); radio_set_state(radiostatus.idle_state); } } usr_radio_irq(cause); }
/** * @brief Handle received frame interrupt * * This function handles transceiver interrupts for received frames. * * @param trx_id Transceiver identifier */ void handle_rx_end_irq(trx_id_t trx_id) { trx_state[trx_id] = RF_TXPREP; #if (defined RF215V1) && ((defined SUPPORT_FSK) || (defined SUPPORT_OQPSK)) stop_rpc(trx_id); #endif if (upload_frame(trx_id) == false) { return; } #ifdef RX_WHILE_BACKOFF if (tx_state[trx_id] == TX_BACKOFF) { /* Stop backoff timer */ stop_tal_timer(trx_id); tx_state[trx_id] = TX_DEFER; tal_pib[trx_id].NumRxFramesDuringBackoff++; } #endif #ifdef SUPPORT_MODE_SWITCH if (tal_pib[trx_id].ModeSwitchEnabled) { if (tal_pib[trx_id].phy.modulation == FSK) { uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; if (trx_bit_read(reg_offset + SR_BBC0_FSKPHRRX_MS) == 0x01) { handle_rx_ms_packet(trx_id); return; } } if (tal_state[trx_id] == TAL_NEW_MODE_RECEIVING) { /* Restore previous PHY, i.e. CSM */ /* Stop timer waiting for incoming frame at new mode */ stop_tal_timer(trx_id); set_csm(trx_id); tal_state[trx_id] = TAL_IDLE; } } #endif #ifdef PROMISCUOUS_MODE if (tal_pib[trx_id].PromiscuousMode) { complete_rx_transaction(trx_id); return; } #endif /* #ifdef PROMISCUOUS_MODE */ handle_incoming_frame(trx_id); }
/* * \brief Generates a 16-bit random number used as initial seed for srand() * * This function generates a 16-bit random number by means of using the * Random Number Generator from the transceiver. * The Random Number Generator generates 2-bit random values. These 2-bit * random values are concatenated to the required 16-bit random seed. * * The generated random 16-bit number is feed into function srand() * as initial seed. * * The transceiver state is initally set to RX_ON. * After the completion of the random seed generation, the * trancseiver is set to TRX_OFF. * * As a prerequisite the preamble detector must not be disabled. * * Also in case the function is called from a different state than TRX_OFF, * additional trx state handling is required, such as reading the original * value and restoring this state after finishing the sequence. * Since in our case the function is called from TRX_OFF, this is not required * here. */ void tal_generate_rand_seed(void) { uint16_t seed = 0; uint8_t cur_random_val = 0; /* RPC could influence the randomness; therefore disable it here. */ uint8_t previous_RPC_value = trx_reg_read(RG_TRX_RPC); trx_reg_write(RG_TRX_RPC, 0xC1); /* * We need to disable TRX IRQs while generating random values in RX_ON, * we do not want to receive frames at this point of time at all. */ ENTER_TRX_REGION(); /* Ensure that PLL has locked and receive mode is reached. */ tal_trx_status_t trx_state; do { trx_state = set_trx_state(CMD_RX_ON); } while (trx_state != RX_ON); /* Ensure that register bit RX_PDT_DIS is set to 0. */ trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* * The 16-bit random value is generated from various 2-bit random * values. */ for (uint8_t i = 0; i < 8; i++) { /* Now we can safely read the 2-bit random number. */ cur_random_val = trx_bit_read(SR_RND_VALUE); seed = seed << 2; seed |= cur_random_val; PAL_WAIT_1_US(); /* wait that the random value gets updated */ } set_trx_state(CMD_FORCE_TRX_OFF); /* * Now we need to clear potential pending TRX IRQs and * enable the TRX IRQs again. */ trx_reg_read(RG_IRQ_STATUS); pal_trx_irq_flag_clr(); LEAVE_TRX_REGION(); /* Set the seed for the random number generator. */ srand(seed); /* Restore RPC settings. */ trx_reg_write(RG_TRX_RPC, previous_RPC_value); }
/** * @brief Frame reception * */ void radio_receive_frame(void) { uint8_t len, lqi, crc_fail; int8_t ed; /* @todo add RSSI_BASE_VALUE to get a dBm value */ ed = (int8_t)trx_reg_read(RG_PHY_ED_LEVEL); crc_fail = trx_bit_read(SR_RX_CRC_VALID) ? 0 : 1; len = trx_frame_read(radiostatus.rxframe, radiostatus.rxframesz, &lqi); len &= ~0x80; radiostatus.rxframe = usr_radio_receive_frame(len, radiostatus.rxframe, lqi, ed, crc_fail); }
int main(void) { trx_regval_t rval; /* This will stop the application before initializing the radio transceiver * (ISP issue with MISO pin, see FAQ) */ trap_if_key_pressed(); /* Step 0: init MCU peripherals */ LED_INIT(); trx_io_init(SPI_RATE_1_2); LED_SET_VALUE(LED_MAX_VALUE); LED_SET_VALUE(0); /* Step 1: initialize the transceiver */ TRX_RESET_LOW(); TRX_SLPTR_LOW(); DELAY_US(TRX_RESET_TIME_US); TRX_RESET_HIGH(); trx_reg_write(RG_TRX_STATE,CMD_TRX_OFF); DELAY_US(TRX_INIT_TIME_US); rval = trx_bit_read(SR_TRX_STATUS); ERR_CHECK(TRX_OFF!=rval); LED_SET_VALUE(1); /* Step 2: setup transmitter * - configure radio channel * - go into RX state, * - enable "receive end" IRQ */ trx_bit_write(SR_CHANNEL,CHANNEL); trx_reg_write(RG_TRX_STATE,CMD_RX_ON); #if defined(TRX_IRQ_TRX_END) trx_reg_write(RG_IRQ_MASK,TRX_IRQ_TRX_END); #elif defined(TRX_IRQ_RX_END) trx_reg_write(RG_IRQ_MASK,TRX_IRQ_RX_END); #else # error "Unknown IRQ bits" #endif sei(); LED_SET_VALUE(2); /* Step 3: Going to receive frames */ rxcnt = 0; LED_SET_VALUE(0); while(1); }
/* * \brief handle the tx power settings in case of External PA enabled, * and the channel changes from or to 26.This is to meet the FCC compliance * * \param Current channel and Previous channel */ void limit_tx_power_in_ch26(uint8_t curr_chnl, uint8_t prev_chnl) { pib_value_t pib_value; /* If the cuurent channel set to 26*/ if (curr_chnl == CHANNEL_26) { /* Get last previous non 26 channel tx power */ if (prev_chnl != CHANNEL_26) { tal_pib_get(phyTransmitPower, &prev_non_26chn_tx_power); } /* If the Tx power is more than 13dBm, i.e. TX_PWR < 0x0d */ if (trx_bit_read(SR_TX_PWR) <= MAX_TX_PWR_REG_VAL_CH26) { pib_value.pib_value_8bit = DEFAULT_TX_POWER_CH26; tal_pib_set(phyTransmitPower, &pib_value); curr_trx_config_params.tx_power_reg = trx_bit_read( SR_TX_PWR); curr_trx_config_params.tx_power_dbm = CONV_phyTransmitPower_TO_DBM( pib_value.pib_value_8bit); } } else { /* if the channel changed from 26 to other */ if (prev_chnl == CHANNEL_26) { /* Set back the tx power to default value i.e. 20dBm, *TX_PWR 0x09 */ pib_value.pib_value_8bit = prev_non_26chn_tx_power; tal_pib_set(phyTransmitPower, &pib_value); curr_trx_config_params.tx_power_reg = trx_bit_read( SR_TX_PWR); curr_trx_config_params.tx_power_dbm = CONV_phyTransmitPower_TO_DBM( pib_value.pib_value_8bit); } } }
/* * \brief handling of CCA result. */ void cca_done_handling(void) { set_trx_state(CMD_PLL_ON); /* leave RX_ON */ /* Restore IRQ handling */ trx_irq_init((FUNC_PTR)trx_irq_handler_cb); trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* Enable frame reception. **/ /* Check if channel was idle or busy */ if (trx_bit_read(SR_CCA_STATUS) == CCA_STATUS_CHANNEL_IS_IDLE) { tx_frame(); } else { tal_state = TAL_CSMA_CONTINUE; } }
radio_cca_t radio_do_cca(void) { uint8_t tmp, trxcmd, trxstatus; radio_cca_t ret = RADIO_CCA_FREE; trxcmd = trx_reg_read(RG_TRX_STATE); trx_reg_write(RG_TRX_STATE, CMD_RX_ON); tmp = 130; do { trxstatus = trx_bit_read(SR_TRX_STATUS); if ((RX_ON == trxstatus) || (BUSY_RX == trxstatus)) { break; } DELAY_US(32); /* wait for one octett */ } while(--tmp); trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); trx_reg_write(RG_TRX_STATE, CMD_RX_ON); trx_bit_write(SR_CCA_REQUEST,1); DELAY_US(140); /* we need to read the whole status register * because CCA_DONE and CCA_STATUS are valid * only for one read, after the read they are reset */ tmp = trx_reg_read(RG_TRX_STATUS); if(0 == (tmp & 0x80)) { ret = RADIO_CCA_FAIL; } else if (tmp & 0x40) { ret = RADIO_CCA_FREE; } else { ret = RADIO_CCA_BUSY; } trx_reg_write(RG_TRX_STATE, trxcmd); return ret; }
/** * \brief Initializes the transceiver * * This function is called to initialize the transceiver. * * \return MAC_SUCCESS if the transceiver state is changed to TRX_OFF and the * current device part number and version number are correct; * FAILURE otherwise */ static retval_t trx_init(void) { tal_trx_status_t trx_status; uint8_t poll_counter = 0; sysclk_enable_peripheral_clock(&TRX_CTRL_0); TRX_RST_HIGH(); TRX_SLP_TR_LOW(); pal_timer_delay(P_ON_TO_CLKM_AVAILABLE_TYP_US); /* Apply reset pulse */ TRX_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); TRX_RST_HIGH(); /* Verify that the trx has reached TRX_OFF. */ poll_counter = 0; do { /* Wait a short time interval. */ pal_timer_delay(TRX_POLL_WAIT_TIME_US); trx_status = (tal_trx_status_t)trx_bit_read(SR_TRX_STATUS); /* Wait not more than max. value of TR2. */ if (poll_counter == RESET_TO_TRX_OFF_ATTEMPTS) { #if (_DEBUG_ > 0) Assert( "MAX Attempts to switch to TRX_OFF state reached" == 0); #endif return FAILURE; } poll_counter++; } while (trx_status != TRX_OFF); tal_trx_status = TRX_OFF; #if !defined(FPGA_EMULATION) /* Check if actually running on an ATmegaRFR2 device. */ if (ATMEGARFR2_PART_NUM != trx_reg_read(RG_PART_NUM)) { return FAILURE; } #endif return MAC_SUCCESS; }
retval_t tal_ext_pa_ctrl(bool pa_ext_sw_ctrl) { bool temp; trx_bit_write(SR_PA_EXT_EN, pa_ext_sw_ctrl); #if (TAL_TYPE == ATMEGARFA1) CONF_REG_WRITE(); #endif /* TAL_TYPE == ATMEGA128RFA1 */ /* Read the PA_EXT_EN bit to check the configuration */ temp = /*(bool)*/ trx_bit_read(SR_PA_EXT_EN); if (pa_ext_sw_ctrl == temp) { /* return success if the configuration is done correctly */ return MAC_SUCCESS; } else { /* return success if the configuration is not done correctly */ return FAILURE; } }
/** * @brief Handles incoming frame from transceiver * * @param trx_id Transceiver identifier */ static void handle_incoming_frame(trx_id_t trx_id) { uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; if (is_frame_an_ack(trx_id)) { if (tx_state[trx_id] == TX_WAITING_FOR_ACK) { if (is_ack_valid(trx_id)) { /* Stop ACK timeout timer */ stop_tal_timer(trx_id); /* Re-store frame filter to pass "normal" frames **/ /* Configure frame filter to receive all allowed *frame types */ #ifdef SUPPORT_FRAME_FILTER_CONFIGURATION trx_reg_write(reg_offset + RG_BBC0_AFFTM, tal_pib[trx_id].frame_types); #else trx_reg_write(reg_offset + RG_BBC0_AFFTM, DEFAULT_FRAME_TYPES); #endif tx_done_handling(trx_id, MAC_SUCCESS); } else { /* Continue waiting for incoming ACK */ switch_to_rx(trx_id); } } else { /* No interest in ACKs */ switch_to_rx(trx_id); } return; /* no further processing of ACK frames */ } /* Check if ACK transmission is done by transceiver */ bool ack_transmitting = trx_bit_read(reg_offset + SR_BBC0_AMCS_AACKFT); if (ack_transmitting) { } else { complete_rx_transaction(trx_id); #ifdef RX_WHILE_BACKOFF if (tx_state[trx_id] == TX_DEFER) { csma_start(trx_id); } #endif } }
/** * \brief Reset transceiver * * \return MAC_SUCCESS if the transceiver state is changed to TRX_OFF * FAILURE otherwise */ static retval_t trx_reset(void) { tal_trx_status_t trx_status; uint8_t poll_counter = 0; /* trx might sleep, so wake it up */ TRX_SLP_TR_LOW(); pal_timer_delay(SLEEP_TO_TRX_OFF_TYP_US); /* Apply reset pulse */ TRX_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); TRX_RST_HIGH(); /* verify that trx has reached TRX_OFF */ do { /* Wait a short time interval. */ pal_timer_delay(TRX_POLL_WAIT_TIME_US); trx_status = (tal_trx_status_t)trx_bit_read(SR_TRX_STATUS); /* Wait not more than max. value of TR2. */ if (poll_counter == SLEEP_TO_TRX_OFF_ATTEMPTS) { #if (_DEBUG_ > 0) Assert( "MAX Attempts to switch to TRX_OFF state reached" == 0); #endif return FAILURE; } poll_counter++; } while (trx_status != TRX_OFF); tal_trx_status = TRX_OFF; #ifdef STB_ON_SAL #if (SAL_TYPE == AT86RF2xx) stb_restart(); #endif #endif return MAC_SUCCESS; }
/** * \brief Transmit a frame already put in the radio with 'prepare' * \param payload_len Length of the frame to send * \return Returns success/fail, refer to radio.h for explanation */ int rf233_transmit() { static uint8_t status_now; status_now = rf233_status(); PRINTF("RF233: attempting transmit, in state %s\n", state_str(status_now)); if (status_now == STATE_BUSY_RX_AACK || status_now == STATE_BUSY_TX_ARET) { PRINTF("RF233: collision, was in state %s\n", state_str(status_now)); /* NOTE: to avoid loops */ return RADIO_TX_ERR;; } if (status_now != STATE_PLL_ON) { trx_reg_write(RF233_REG_TRX_STATE, STATE_PLL_ON); do { // I think this code is broken, does nothing -pal status_now = trx_bit_read(RF233_REG_TRX_STATUS, 0x1F, 0); } while (status_now == 0x1f); } if (rf233_status() != STATE_PLL_ON) { /* failed moving into PLL_ON state, gracefully try to recover */ PRINTF("RF233: failed going to STATE_PLL_ON\n"); RF233_COMMAND(TRXCMD_PLL_ON); /* try again */ static uint8_t state; state = rf233_status(); if(state != STATE_PLL_ON) { PRINTF("RF233: graceful recovery (in tx) failed, giving up. State: 0x%02X\n", rf233_status()); return RADIO_TX_ERR; } } /* perform transmission */ flag_transmit = 1; radio_tx = false; RF233_COMMAND(TRXCMD_TX_ARET_ON); RF233_COMMAND(TRXCMD_TX_START); PRINTF("RF233:: Issued TX_START, wait for completion interrupt.\n"); wait_for(&radio_tx); PRINTF("RF233: tx ok\n\n"); return RADIO_TX_OK; }
/* * \brief Generates a 16-bit random number used as initial seed for srand() * * This function generates a 16-bit random number by means of using the * Random Number Generator from the transceiver. * The Random Number Generator generates 2-bit random values. These 2-bit * random values are concatenated to the required 16-bit random seed. * * The generated random 16-bit number is feed into function srand() * as initial seed. * * The transceiver state is initally set to RX_ON. * After the completion of the random seed generation, the * trancseiver is set to TRX_OFF. * * As a prerequisite the preamble detector must not be disabled. * * Also in case the function is called from a different state than TRX_OFF, * additional trx state handling is required, such as reading the original * value and restoring this state after finishing the sequence. * Since in our case the function is called from TRX_OFF, this is not required * here. */ void tal_generate_rand_seed(void) { uint16_t seed = 0; uint8_t cur_random_val = 0; /* Ensure that PLL has locked and receive mode is reached. */ tal_trx_status_t trx_state; do { trx_state = set_trx_state(CMD_RX_ON); } while (trx_state != RX_ON); /* Ensure that register bit RX_PDT_DIS is set to 0. */ trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* * We need to disable TRX IRQs while generating random values in RX_ON, * we do not want to receive frames at this point of time at all. */ trx_reg_write(RG_IRQ_MASK, TRX_IRQ_NONE); /* * The 16-bit random value is generated from various 2-bit random * values. */ for (uint8_t i = 0; i < 8; i++) { /* Now we can safely read the 2-bit random number. */ cur_random_val = trx_bit_read(SR_RND_VALUE); seed = seed << 2; seed |= cur_random_val; PAL_WAIT_1_US(); /* wait that the random value gets updated */ } set_trx_state(CMD_FORCE_TRX_OFF); /* * Now we need to clear potential pending TRX IRQs and * enable the TRX IRQs again. */ trx_reg_write(RG_IRQ_STATUS, 0xFF); trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); /* Set the seed for the random number generator. */ srand(seed); }
retval_t tal_set_tx_pwr(bool type, int8_t pwr_value) { uint64_t temp_var; int8_t tx_pwr_dbm = 0; /* modify the register for tx_pwr and set the tal_pib accordingly */ if (true == type) { if (MAC_SUCCESS == tal_convert_reg_value_to_dBm(pwr_value, &tx_pwr_dbm)) { temp_var = CONV_DBM_TO_phyTransmitPower(tx_pwr_dbm); tal_pib_set(phyTransmitPower, (pib_value_t *)&temp_var); /* To make sure that TX_PWR register is updated with the * value whatever user povided.Otherwise lowest dBm * power * (highest reg value will be taken) */ trx_bit_write(SR_TX_PWR, pwr_value); #if (TAL_TYPE == ATMEGARFA1) CONF_REG_WRITE(); #endif /* TAL_TYPE == ATMEGA128RFA1 */ return MAC_SUCCESS; } else { /* return invalid parameter if out of range */ return MAC_INVALID_PARAMETER; } } else { temp_var = CONV_DBM_TO_phyTransmitPower(pwr_value); tal_pib_set(phyTransmitPower, (pib_value_t *)&temp_var); } uint8_t reg_value = convert_phyTransmitPower_to_reg_value( tal_pib.TransmitPower); /* check the value written in the transceiver register */ uint8_t temp = trx_bit_read(SR_TX_PWR); if (temp == reg_value) { return MAC_SUCCESS; } else { return FAILURE; } }
/** * \brief Performs CCA twice */ static uint8_t perform_cca_twice(void) { uint8_t cca_status; uint8_t cca_done; uint8_t CW = 2; uint32_t now_time_us; do { pal_get_current_time(&now_time_us); } while (pal_add_time_us(now_time_us, (SLEEP_TO_TRX_OFF_TYP_US + CCA_PREPARATION_DURATION_US)) < cca_starttime_us); #if ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) if (tal_beacon_transmission) { #if (_DEBUG_ > 0) Assert("Ongoing beacon transmission, slotted CSMA busy" == 0); #endif return PHY_BUSY; } #endif /* ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) */ /* Ensure that trx is at least in TRX_OFF mode at this time. */ if (tal_trx_status == TRX_SLEEP) { set_trx_state(CMD_TRX_OFF); } do { pal_get_current_time(&now_time_us); } while (pal_add_time_us(now_time_us, (TRX_OFF_TO_PLL_ON_TIME_US + CCA_PREPARATION_DURATION_US)) < cca_starttime_us); /* * Set trx to PLL_ON. * If trx is busy and trx cannot be set to PLL_ON, assess channel as * busy. */ if (set_trx_state(CMD_PLL_ON) != PLL_ON) { return PHY_BUSY; } /* no interest in receiving frames while doing CCA */ trx_bit_write(SR_RX_PDT_DIS, RX_DISABLE); /* disable frame reception * indication */ /* do CCA twice */ do { /* wait here until 16us before backoff boundary */ /* assume TRX is in PLL_ON */ do { pal_get_current_time(&now_time_us); } while (pal_add_time_us(now_time_us, CCA_PRE_START_DURATION_US) < cca_starttime_us); set_trx_state(CMD_RX_ON); /* debug pin to switch on: define ENABLE_DEBUG_PINS, * pal_config.h */ PIN_CCA_START(); /* Start CCA */ trx_bit_write(SR_CCA_REQUEST, CCA_START); /* wait until CCA is done and get status */ pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US(CCA_DURATION_SYM)); do { /* poll until CCA is really done; */ cca_done = trx_bit_read(SR_CCA_DONE); } while (cca_done != CCA_COMPLETED); /* between both CCA switch trx to PLL_ON to reduce power * consumption */ set_trx_state(CMD_PLL_ON); /* debug pin to switch on: define ENABLE_DEBUG_PINS, * pal_config.h */ PIN_CCA_END(); /* check if channel was idle or busy */ if (trx_bit_read(SR_CCA_STATUS) == CCA_CH_IDLE) { /* do next CCA at next backoff boundary */ cca_starttime_us = pal_add_time_us(cca_starttime_us, TAL_CONVERT_SYMBOLS_TO_US( aUnitBackoffPeriod)); CW--; cca_status = PHY_IDLE; } else { /* PHY busy */ cca_status = PHY_BUSY; set_trx_state(CMD_RX_AACK_ON); break; /* if channel is busy do no do CCA for the second * time */ } } while (CW > 0); /* * Keep trx ready for transmission if channel is idle. * The transceiver is still in PLL_ON. * If the channel is not idle, the trx handling is done in * csma_backoff(). */ /* * Clear CCA interrupt flag. * This is only necessary for debugging, because only in debug mode * interrupt that are not handled cause an assert in the ISR. */ #if (_DEBUG_ > 0) trx_reg_read(RG_IRQ_STATUS); #endif /* * Since we are not interested in any frames that might be received * during CCA, reject any information that indicates a previous frame * reception. */ trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* enable frame reception * indication */ return cca_status; }
/* * \brief Handles interrupts issued due to end of transmission */ void handle_tx_end_irq(void) { /* Check if TX_END interrupt, is issued due to automatic ACK * transmission. */ #if ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) if ((tal_state != TAL_TX_AUTO) && (!tal_beacon_transmission)) #else if (tal_state != TAL_TX_AUTO) #endif { /* Automatic ACK transmission completed -> No further * processing. */ return; } #if ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) if (tal_beacon_transmission) { tal_beacon_transmission = false; if (tal_csma_state == BACKOFF_WAITING_FOR_BEACON) { /* Slotted CSMA has been waiting for a beacon, now it * can continue. */ tal_csma_state = CSMA_HANDLE_BEACON; } } else #endif /* ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) */ { /* Read trac status before enabling RX_AACK_ON. */ trx_trac_status = (trx_trac_status_t)trx_bit_read( SR_TRAC_STATUS); #ifdef BEACON_SUPPORT if (tal_csma_state == FRAME_SENDING) { /* Transmission was * issued by slotted CSMA **/ PIN_TX_END(); tal_state = TAL_SLOTTED_CSMA; /* Map status message of transceiver to TAL constants. **/ switch (trx_trac_status) { case TRAC_SUCCESS_DATA_PENDING: PIN_ACK_OK_START(); tal_csma_state = TX_DONE_FRAME_PENDING; break; case TRAC_SUCCESS: PIN_ACK_OK_START(); tal_csma_state = TX_DONE_SUCCESS; break; case TRAC_CHANNEL_ACCESS_FAILURE: PIN_NO_ACK_START(); tal_csma_state = CSMA_ACCESS_FAILURE; break; case TRAC_NO_ACK: PIN_NO_ACK_START(); tal_csma_state = TX_DONE_NO_ACK; break; case TRAC_INVALID: /* Handle this in the same way as * default. */ default: Assert("not handled trac status" == 0); tal_csma_state = CSMA_ACCESS_FAILURE; break; } PIN_ACK_OK_END(); PIN_ACK_WAITING_END(); } else #endif /* BEACON_SUPPORT */ /* Trx has handled the entire transmission incl. CSMA */ { tal_state = TAL_TX_DONE; /* Further handling is done by * tx_done_handling() */ } } /* * After transmission has finished, switch receiver on again. * Check if receive buffer is available. */ if (NULL == tal_rx_buffer) { set_trx_state(CMD_PLL_ON); tal_rx_on_required = true; } else { set_trx_state(CMD_RX_AACK_ON); } }
/* * \brief Transceiver interrupt handler * * This function handles the transceiver generated interrupts. */ void trx_irq_handler_cb(void) { trx_irq_reason_t trx_irq_cause; trx_irq_cause = (trx_irq_reason_t)trx_reg_read(RG_IRQ_STATUS); #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) #if (ANTENNA_DIVERSITY == 1) || (DISABLE_TSTAMP_IRQ == 1) if (trx_irq_cause & TRX_IRQ_RX_START) { /* * Get timestamp. * * In case Antenna diversity is used or the utilization of * the Timestamp IRQ is disabled, the timestamp needs to be read * now * the "old-fashioned" way. * * The timestamping is generally only done for * beaconing networks or if timestamping is explicitly enabled. */ pal_trx_read_timestamp(&tal_rx_timestamp); } #endif /* #if (ANTENNA_DIVERSITY == 1) || (DISABLE_TSTAMP_IRQ == 1) */ #endif /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */ if (trx_irq_cause & TRX_IRQ_TRX_END) { /* * TRX_END reason depends on if the trx is currently used for * transmission or reception. */ #if ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) if ((tal_state == TAL_TX_AUTO) || tal_beacon_transmission) #else if (tal_state == TAL_TX_AUTO) #endif { /* Get the result and push it to the queue. */ if (trx_irq_cause & TRX_IRQ_TRX_UR) { handle_tx_end_irq(true); /* see tal_tx.c */ } else { handle_tx_end_irq(false); /* see tal_tx.c */ } } else { /* Other tal_state than TAL_TX_... */ /* Handle rx interrupt. */ handle_received_frame_irq(); /* see tal_rx.c */ #if (defined SW_CONTROLLED_CSMA) && (defined RX_WHILE_BACKOFF) if (tal_state == TAL_BACKOFF) { pal_timer_stop(TAL_T_BOFF); tal_state = TAL_CSMA_CONTINUE; } #endif } } #if (ANTENNA_DIVERSITY == 1) else if (trx_irq_cause & TRX_IRQ_RX_START) { /* * The antenna that has been selected automatically for the * current frame * reception is set for the ACK transmission too. */ if (trx_bit_read(SR_ANT_SEL) == ANT_SEL_ANTENNA_0) { trx_bit_write(SR_ANT_CTRL, ANT_CTRL_1); } else { /* antenna 1 is in use */ trx_bit_write(SR_ANT_CTRL, ANT_CTRL_2); } } #endif } /* trx_irq_handler_cb() */
/* * \brief Generates a 16-bit random number used as initial seed for srand() * */ static void rf_generate_random_seed(void) { uint16_t seed = 0; uint8_t cur_random_val = 0; /* * We need to disable TRX IRQs while generating random values in RX_ON, * we do not want to receive frames at this point of time at all. */ ENTER_TRX_REGION(); do { trx_reg_write(RF233_REG_TRX_STATE, TRXCMD_TRX_OFF); } while (TRXCMD_TRX_OFF != rf233_status()); do { /* Ensure that PLL has locked and receive mode is reached. */ trx_reg_write(RF233_REG_TRX_STATE, TRXCMD_PLL_ON); } while (TRXCMD_PLL_ON != rf233_status()); do { trx_reg_write(RF233_REG_TRX_STATE, TRXCMD_RX_ON); } while (TRXCMD_RX_ON != rf233_status()); /* Ensure that register bit RX_PDT_DIS is set to 0. */ trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* * The 16-bit random value is generated from various 2-bit random * values. */ for (uint8_t i = 0; i < 8; i++) { /* Now we can safely read the 2-bit random number. */ cur_random_val = trx_bit_read(SR_RND_VALUE); seed = seed << 2; seed |= cur_random_val; delay_us(1); /* wait that the random value gets updated */ } do { /* Ensure that PLL has locked and receive mode is reached. */ trx_reg_write(RF233_REG_TRX_STATE, TRXCMD_TRX_OFF); } while (TRXCMD_TRX_OFF != rf233_status()); /* * Now we need to clear potential pending TRX IRQs and * enable the TRX IRQs again. */ trx_reg_read(RF233_REG_IRQ_STATUS); trx_irq_flag_clr(); LEAVE_TRX_REGION(); /* Set the seed for the random number generator. */ srand(seed); }