/** * @brief Configures RF according FSK * * @param mod_type Modulation order / type; i.e. F2FSK or F4FSK * @param srate Data rate * @param mod_idx Modulation index * @param trx_id Transceiver identifier */ retval_t fsk_rfcfg(fsk_mod_type_t mod_type, fsk_data_rate_t srate, mod_idx_t mod_idx, trx_id_t trx_id) { retval_t status = MAC_SUCCESS; uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; uint8_t srate_midx = (srate << 3) + mod_idx; /* TX configuration: */ /* - PA ramp time + TX-SSBF fcut */ /* - DFE sampling rate reduction + TX-DFE fcut */ { uint8_t temp[2]; PGM_READ_BLOCK(temp, (uint8_t *)&fsk_params_tbl[srate_midx][0], 2); rf_blk_write(reg_offset + RG_RF09_TXCUTC, temp, 2); } /* - Transmit Power*/ #ifdef IQ_RADIO pal_dev_reg_write(RF215_RF, reg_offset + RG_RF09_PAC, ((3 << PAC_PACUR_SHIFT) | (DEFAULT_TX_PWR_REG << PAC_TXPWR_SHIFT))); #else trx_reg_write(reg_offset + RG_RF09_PAC, ((3 << PAC_PACUR_SHIFT) | (DEFAULT_TX_PWR_REG << PAC_TXPWR_SHIFT))); #endif /* RX configuration: */ /* - RX-SSBF bandwidth + RX-SSBF IF shift */ /* - DFE sampling rate reduction + RX-DFE cut-off ratio */ if (trx_id == RF09) { uint8_t temp[2]; PGM_READ_BLOCK(temp, (uint8_t *)&fsk_params_tbl[srate_midx][5], 2); rf_blk_write(RG_RF09_RXBWC, temp, 2); } else { uint8_t temp[2]; PGM_READ_BLOCK(temp, (uint8_t *)&fsk_params_tbl[srate_midx][7], 2); rf_blk_write(RG_RF24_RXBWC, temp, 2); } /* - AGC input + AGC average period */ /* - AGC target */ { uint8_t temp[2]; PGM_READ_BLOCK(temp, (uint8_t *)&fsk_params_tbl[srate_midx][9], 2); rf_blk_write(reg_offset + RG_RF09_AGCC, temp, 2); } #ifndef FWNAME uint8_t agcc = (uint8_t)PGM_READ_BYTE(&fsk_params_tbl[srate_midx][9]); uint8_t agci = (agcc & AGCC_AGCI_MASK) >> AGCC_AGCI_SHIFT; uint8_t avgs = (agcc & AGCC_AVGS_MASK) >> AGCC_AVGS_SHIFT; uint8_t rxdfe; if (trx_id == RF09) { rxdfe = (uint8_t)PGM_READ_BYTE(&fsk_params_tbl[srate_midx][6]); } else { rxdfe = (uint8_t)PGM_READ_BYTE(&fsk_params_tbl[srate_midx][8]); } uint8_t sr = rxdfe & RXDFE_SR_MASK; tal_pib[trx_id].agc_settle_dur = get_agc_settling_period(sr, avgs, agci); #endif #if (!defined RF215v2) /* Keep compiler happy */ mod_type = mod_type; #endif return status; }
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_MS(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 * - enable transmitters automatic crc16 generation * - go into RX AACK state, * - configure address filter * - enable "receive end" IRQ */ trx_bit_write(SR_CHANNEL,CHANNEL); trx_bit_write(SR_TX_AUTO_CRC_ON,1); trx_reg_write(RG_PAN_ID_0,(PANID&0xff)); trx_reg_write(RG_PAN_ID_1,(PANID>>8)); trx_reg_write(RG_SHORT_ADDR_0,(SHORT_ADDR&0xff)); trx_reg_write(RG_SHORT_ADDR_1,(SHORT_ADDR>>8)); trx_reg_write(RG_TRX_STATE,CMD_RX_AACK_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: send a frame each 500ms */ tx_cnt = 0; tx_in_progress = false; LED_SET_VALUE(0); while(1); }
/** * \brief Init the radio * \return Returns success/fail * \retval 0 Success */ int rf233_init(void) { volatile uint8_t regtemp; volatile uint8_t radio_state; /* don't optimize this away, it's important */ PRINTF("RF233: init.\r\n"); /* init SPI and GPIOs, wake up from sleep/power up. */ //rf233_arch_init(); trx_spi_init(); /* reset will put us into TRX_OFF state */ /* reset the radio core */ port_pin_set_output_level(AT86RFX_RST_PIN, false); delay_cycles_ms(1); port_pin_set_output_level(AT86RFX_RST_PIN, true); port_pin_set_output_level(AT86RFX_SLP_PIN, false); /*wakeup from sleep*/ /* before enabling interrupts, make sure we have cleared IRQ status */ regtemp = trx_reg_read(RF233_REG_IRQ_STATUS); PRINTF("After wake from sleep\r\n"); radio_state = rf233_status(); PRINTF("After arch read reg: state 0x%04x\r\n", radio_state); if(radio_state == STATE_P_ON) { trx_reg_write(RF233_REG_TRX_STATE, TRXCMD_TRX_OFF); } /* Assign regtemp to regtemp to avoid compiler warnings */ regtemp = regtemp; trx_irq_init((FUNC_PTR)rf233_interrupt_poll); ENABLE_TRX_IRQ(); system_interrupt_enable_global(); /* Configure the radio using the default values except these. */ trx_reg_write(RF233_REG_TRX_CTRL_1, RF233_REG_TRX_CTRL_1_CONF); trx_reg_write(RF233_REG_PHY_CC_CCA, RF233_REG_PHY_CC_CCA_CONF); trx_reg_write(RF233_REG_PHY_TX_PWR, RF233_REG_PHY_TX_PWR_CONF); trx_reg_write(RF233_REG_TRX_CTRL_2, RF233_REG_TRX_CTRL_2_CONF); trx_reg_write(RF233_REG_IRQ_MASK, RF233_REG_IRQ_MASK_CONF); // trx_reg_write(0x17, 0x02); #if HW_CSMA_FRAME_RETRIES trx_bit_write(SR_MAX_FRAME_RETRIES, 3); trx_bit_write(SR_MAX_CSMA_RETRIES, 4); #else trx_bit_write(SR_MAX_FRAME_RETRIES, 0); trx_bit_write(SR_MAX_CSMA_RETRIES, 7); #endif SetPanId(IEEE802154_CONF_PANID); rf_generate_random_seed(); for(uint8_t i=0;i<8;i++) { regtemp =trx_reg_read(0x24+i); } /* 11_09_rel */ trx_reg_write(RF233_REG_TRX_RPC,0xFF); /* Enable RPC feature by default */ // regtemp = trx_reg_read(RF233_REG_PHY_TX_PWR); /* start the radio process */ process_start(&rf233_radio_process, NULL); return 0; }
/* * \brief Get the transceiver's supply voltage * * \return mv Milli Volt; 0 if below threshold, 0xFFFF if above threshold */ uint16_t tfa_get_batmon_voltage(void) { tal_trx_status_t previous_trx_status; uint8_t vth_val; uint8_t i; uint16_t mv = 1; /* 1 used as indicator flag */ bool range; previous_trx_status = tal_trx_status; if (tal_trx_status == TRX_SLEEP) { set_trx_state(CMD_TRX_OFF); } /* * Disable all trx interrupts. * This needs to be done AFTER the transceiver has been woken up. */ trx_reg_write(RG_IRQ_MASK, TRX_IRQ_NONE); /* Check if supply voltage is within lower range */ trx_bit_write(SR_BATMON_HR, BATMON_LOW_RANGE); trx_bit_write(SR_BATMON_VTH, 0x0F); pal_timer_delay(5); /* Wait until Batmon has been settled. */ if (trx_bit_read(SR_BATMON_OK) == BATMON_BELOW_THRES) { /* Lower range */ /* Check if supply voltage is below lower limit */ trx_bit_write(SR_BATMON_VTH, 0); pal_timer_delay(2); /* Wait until Batmon has been settled. */ if (trx_bit_read(SR_BATMON_OK) == BATMON_BELOW_THRES) { /* below lower limit */ mv = SUPPLY_VOLTAGE_BELOW_LOWER_LIMIT; } range = LOW; } else { /* Higher range */ trx_bit_write(SR_BATMON_HR, BATMON_HIGH_RANGE); /* Check if supply voltage is above upper limit */ trx_bit_write(SR_BATMON_VTH, 0x0F); pal_timer_delay(5); /* Wait until Batmon has been settled. */ if (trx_bit_read(SR_BATMON_OK) == BATMON_ABOVE_THRES) { /* above upper limit */ mv = SUPPLY_VOLTAGE_ABOVE_UPPER_LIMIT; } range = HIGH; } /* Scan through the current range for the matching threshold. */ if (mv == 1) { vth_val = 0x0F; for (i = 0; i < 16; i++) { trx_bit_write(SR_BATMON_VTH, i); pal_timer_delay(2); /* Wait until Batmon has been * settled. */ if (trx_bit_read(SR_BATMON_OK) == BATMON_BELOW_THRES) { if (i > 0) { vth_val = i - 1; } else { vth_val = i; } break; } } if (range == HIGH) { mv = 2550 + (75 * vth_val); } else { mv = 1700 + (50 * vth_val); } } trx_reg_read(RG_IRQ_STATUS); /* Clear all pending interrupts. */ pal_trx_irq_flag_clr_rx_end(); pal_trx_irq_flag_clr_tx_end(); pal_trx_irq_flag_clr_tstamp(); /* * Enable all trx interrupts. * This needs to be done BEFORE putting the transceiver back to slee. */ trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); if (previous_trx_status == TRX_SLEEP) { set_trx_state(CMD_SLEEP); } return mv; }
/** * \brief Configures the transceiver * * This function is called to configure the transceiver after reset. */ void trx_config(void) { /* Set pin driver strength */ trx_bit_write(SR_CLKM_SHA_SEL, CLKM_SHA_DISABLE); trx_bit_write(SR_CLKM_CTRL, CLKM_1MHZ); /* * After we have initialized a proper seed for rand(), * the transceiver's CSMA seed can be initialized. * It needs to be assured that a seed for function rand() * had been generated before. */ /* * Init the SEED value of the CSMA backoff algorithm. */ uint16_t rand_value = (uint16_t)rand(); trx_reg_write(RG_CSMA_SEED_0, (uint8_t)rand_value); trx_bit_write(SR_CSMA_SEED_1, (uint8_t)(rand_value >> 8)); /* * Since the TAL is supporting 802.15.4-2006, * frames with version number 0 (compatible to 802.15.4-2003) and * with version number 1 (compatible to 802.15.4-2006) are acknowledged. */ trx_bit_write(SR_AACK_FVN_MODE, FRAME_VERSION_01); trx_bit_write(SR_AACK_SET_PD, SET_PD); /* ACKs for data requests, * indicate pending data */ trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_ENABLE); /* Enable * buffer * protection * mode */ trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); /* The TRX_END * interrupt of the * transceiver is * enabled. */ trx_reg_write(RG_TRX_RPC, 0xFF); /* RPC feature configuration. */ #if (ANTENNA_DIVERSITY == 1) /* Use antenna diversity */ trx_bit_write(SR_ANT_CTRL, ANTENNA_DEFAULT); trx_bit_write(SR_PDT_THRES, THRES_ANT_DIV_ENABLE); trx_bit_write(SR_ANT_DIV_EN, ANT_DIV_ENABLE); trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE); #endif /* ANTENNA_DIVERSITY */ #if (DISABLE_TSTAMP_IRQ == 0) #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) /* Enable Rx timestamping */ trx_bit_write(SR_IRQ_2_EXT_EN, RX_TIMESTAMPING_ENABLE); /* Enable Tx timestamping */ trx_bit_write(SR_ARET_TX_TS_EN, TX_ARET_TIMESTAMPING_ENABLE); #endif /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */ #endif #ifdef CCA_ED_THRESHOLD /* * Set CCA ED Threshold to other value than standard register due to * board specific loss (see pal_config.h). */ trx_bit_write(SR_CCA_ED_THRES, CCA_ED_THRESHOLD); #endif #ifdef EXT_RF_FRONT_END_CTRL /* Enable RF front end control */ trx_bit_write(SR_PA_EXT_EN, 1); #endif }
/** * \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; /* Ensure control lines have correct levels. */ 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(); /* Verify that TRX_OFF can be written */ 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 AT86RF231 is connected; omit manufacturer id check **/ } while ((trx_reg_read(RG_VERSION_NUM) != AT86RF231_VERSION_NUM) || (trx_reg_read(RG_PART_NUM) != AT86RF231_PART_NUM)); /* 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 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; return MAC_SUCCESS; }
// Section 9.8 of the RF233 manual suggests recalibrating filters at // least every 5 minutes of operation. Transitioning out of sleep // resets the filters automatically. void calibrate_filters() { PRINTF("RF233: Calibrating filters.\n"); trx_reg_write(RF233_REG_FTN_CTRL, 0x80); while (trx_reg_read(RF233_REG_FTN_CTRL) & 0x80); }
/** * @brief Perform a CCA * * This blocking function performs a CCA request. * * @return phy_enum_t PHY_IDLE or PHY_BUSY */ phy_enum_t tfa_cca_perform(trx_id_t trx_id) { phy_enum_t ret; if (tal_state[trx_id] != TAL_IDLE) { ret = PHY_BUSY; } else { rf_cmd_state_t previous_state = trx_state[trx_id]; if (trx_state[trx_id] == RF_TRXOFF) { switch_to_txprep(trx_id); } if (trx_state[trx_id] != RF_RX) { switch_to_rx(trx_id); pal_timer_delay(tal_pib[trx_id].agc_settle_dur); /* * allow * filters * to * settle */ } /* Disable BB */ uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; trx_bit_write(reg_offset + SR_BBC0_PC_BBEN, 0); #ifndef BASIC_MODE /* Enable EDC interrupt */ trx_bit_write(reg_offset + SR_RF09_IRQM_EDC, 1); #endif /* Start single ED measurement; use reg_write - it's the only *subregister */ tal_state[trx_id] = TAL_TFA_CCA; #ifdef IQ_RADIO /* Enable EDC interrupt */ pal_dev_bit_write(RF215_RF, reg_offset + SR_RF09_IRQM_EDC, 1); pal_dev_reg_write(RF215_RF, reg_offset + RG_RF09_EDC, RF_EDSINGLE); #else trx_reg_write(reg_offset + RG_RF09_EDC, RF_EDSINGLE); #endif /* Wait until measurement is completed */ while (TAL_RF_IS_IRQ_SET(trx_id, RF_IRQ_EDC) == false) { } TAL_RF_IRQ_CLR(trx_id, RF_IRQ_EDC); #ifndef BASIC_MODE /* Disable EDC interrupt again */ trx_bit_write(reg_offset + SR_RF09_IRQM_EDC, 0); #endif #ifdef IQ_RADIO pal_dev_bit_write(RF215_RF, reg_offset + SR_RF09_IRQM_EDC, 0); #endif /* Since it is a blocking function, restore TAL state */ tal_state[trx_id] = TAL_IDLE; switch_to_txprep(trx_id); /* Leave Rx mode */ /* Switch BB on again */ trx_bit_write(reg_offset + SR_BBC0_PC_BBEN, 1); /* Capture ED value for current frame / ED scan */ #ifdef IQ_RADIO tal_current_ed_val[trx_id] = pal_dev_reg_read(RF215_RF, reg_offset + RG_RF09_EDV); #else tal_current_ed_val[trx_id] = trx_reg_read( reg_offset + RG_RF09_EDV); #endif if (tal_current_ed_val[trx_id] < tal_pib[trx_id].CCAThreshold) { /* Idle */ ret = PHY_IDLE; } else { /* Busy */ ret = PHY_BUSY; } /* Restore previous trx state */ if (previous_state == RF_RX) { switch_to_rx(trx_id); } else { /* Switch to TRXOFF */ trx_reg_write(reg_offset + RG_RF09_CMD, RF_TRXOFF); #ifdef IQ_RADIO pal_dev_reg_write(RF215_RF, reg_offset + RG_RF09_CMD, RF_TRXOFF); #endif trx_state[trx_id] = RF_TRXOFF; } } return ret; }
/** * \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_write(RG_IRQ_STATUS, 0xFF); #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 Starts continuous transmission on current channel * * \param tx_mode Mode of continuous transmission (CW or PRBS) * \param random_content Use random content if true * * The comment 'step #' refers to the step mentioned in the RF212's datasheet. */ void tfa_continuous_tx_start(continuous_tx_mode_t tx_mode, bool random_content) { uint8_t txcwdata[128]; uint8_t i; /* step 3,6: Channel is assumed to be set before */ trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); /* step 7: Enable continuous transmission - step #1 */ trx_reg_write(0x36, 0x0F); if (tx_mode == CW_MODE) { /* step 8: Register access: CW at Fc +/- 0.1 MHz */ if (((tal_pib.CurrentPage == 0) || (tal_pib.CurrentPage == 2) || \ (tal_pib.CurrentPage == 16) || (tal_pib.CurrentPage == 17)) && (tal_pib.CurrentChannel == 0)) { /* * *868.3MHz **/ trx_reg_write(RG_TRX_CTRL_2, 0x0A); /* 400 kchip/s * mode, step 8 * ,SUB_MODE = 0 */ } else { trx_reg_write(RG_TRX_CTRL_2, 0x0E); /* 1000kchip/s * ,SUB_MODE = 1 */ } txcwdata[0] = 1; /* length */ txcwdata[1] = 0; /* step 9: Frame buffer access */ trx_frame_write(txcwdata, 2); } else { /* PRBS mode */ /* step 8: */ /* * Step 8 is not explicitly written here, because the proper * value is set during reset or by updating the Channel Page. * After finishing CW/PRBS another reset is performed with * parameter set_default_pib set to false, which restores the * original value based on the current Channel Page. * * I.e., in order to use PRBS with a specific data rate, * the Channel Page needs to be udpated before starting PRBS. */ txcwdata[0] = 127; /* = max length */ for (i = 1; i < 128; i++) { if (random_content) { txcwdata[i] = (uint8_t)rand(); } else { txcwdata[i] = 0; } } /* step 9: Frame buffer access */ trx_frame_write(txcwdata, 128); } /* step 10: Enable continuous transmission - step #2 */ trx_reg_write(RG_PART_NUM, 0x54); /* step 11: Enable continuous transmission - step #3 */ trx_reg_write(RG_PART_NUM, 0x46); /* step 12, 13: Stwitch PLL on */ set_trx_state(CMD_PLL_ON); /* step 14: Initiate transmission using SLP_TR line */ TRX_SLP_TR_HIGH(); TRX_SLP_TR_LOW(); }
/** * @brief Resets transceiver(s) * * @param trx_id Transceiver identifier * * @return MAC_SUCCESS if the transceiver returns TRX_OFF * FAILURE otherwise */ retval_t trx_reset(trx_id_t trx_id) { ENTER_TRX_REGION(); uint32_t start_time; uint32_t current_time; pal_get_current_time(&start_time); if (trx_id == RFBOTH) { TAL_RF_IRQ_CLR_ALL(RF09); TAL_RF_IRQ_CLR_ALL(RF24); tal_state[RF09] = TAL_RESET; tal_state[RF24] = TAL_RESET; /* Apply reset pulse; low active */ #ifdef IQ_RADIO RST_LOW(); PAL_WAIT_1_US(); PAL_WAIT_1_US(); RST_HIGH(); #if (BOARD_TYPE == EVAL215_FPGA) pal_timer_delay(10000); #endif RST_LOW(); PAL_WAIT_1_US(); RST_HIGH(); #else RST_LOW(); PAL_WAIT_1_US(); RST_HIGH(); #endif /* Wait for IRQ line */ while (1) { /* * @ToDo: Use a different macro for IRQ line; the *polarity might be * different after reset */ #ifdef IQ_RADIO if ((PAL_DEV_IRQ_GET(RF215_BB) == HIGH) && (PAL_DEV_IRQ_GET(RF215_RF) == HIGH)) { break; } #else if (TRX_IRQ_GET() == HIGH) { break; } #endif /* Handle timeout */ pal_get_current_time(¤t_time); /* @ToDo: Remove magic number */ if (pal_sub_time_us(current_time, start_time) > 1000) { return FAILURE; } } #ifdef IQ_RADIO trx_state[RF09] = (rf_cmd_state_t)pal_dev_reg_read(RF215_RF, RG_RF09_STATE); trx_state[RF24] = (rf_cmd_state_t)pal_dev_reg_read(RF215_RF, RG_RF24_STATE); rf_cmd_state_t bb_trx_state[NUM_TRX]; bb_trx_state[RF09] = (rf_cmd_state_t)pal_dev_reg_read(RF215_BB, RG_RF09_STATE); bb_trx_state[RF24] = (rf_cmd_state_t)pal_dev_reg_read(RF215_BB, RG_RF24_STATE); if ((bb_trx_state[RF09] != RF_TRXOFF) || (bb_trx_state[RF24] != RF_TRXOFF)) { return FAILURE; } #else trx_state[RF09] = trx_reg_read(RG_RF09_STATE); trx_state[RF24] = trx_reg_read(RG_RF24_STATE); #endif if ((trx_state[RF09] != RF_TRXOFF) || (trx_state[RF24] != RF_TRXOFF)) { return FAILURE; } /* Get all IRQ status information */ #ifdef IQ_RADIO bb_irq_handler_cb(); rf_irq_handler_cb(); #else trx_irq_handler_cb(); #endif TAL_RF_IRQ_CLR(RF09, RF_IRQ_WAKEUP); TAL_RF_IRQ_CLR(RF24, RF_IRQ_WAKEUP); } else { TAL_RF_IRQ_CLR_ALL(trx_id); tal_state[trx_id] = TAL_RESET; /* Trigger reset of device */ uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; #ifdef IQ_RADIO pal_trx_reg_write(RF215_RF, reg_offset + RG_RF09_CMD, RF_RESET); pal_trx_reg_write(RF215_BB, reg_offset + RG_RF09_CMD, RF_RESET); #else trx_reg_write(reg_offset + RG_RF09_CMD, RF_RESET); #endif /* Wait for IRQ line */ while (1) { #ifdef IQ_RADIO if ((PAL_DEV_IRQ_GET(RF215_BB) == HIGH) && (PAL_DEV_IRQ_GET(RF215_RF) == HIGH)) { break; } #else if (TRX_IRQ_GET() == HIGH) { break; } #endif /* Handle timeout */ pal_get_current_time(¤t_time); /* @ToDo: Remove magic number */ if (pal_sub_time_us(current_time, start_time) > 1000) { return FAILURE; } } trx_state[trx_id] = RF_TRXOFF; /* Get all IRQ status information */ #ifdef IQ_RADIO bb_irq_handler_cb(); rf_irq_handler_cb(); #else trx_irq_handler_cb(); #endif TAL_RF_IRQ_CLR(trx_id, RF_IRQ_WAKEUP); } #ifdef IQ_RADIO pal_trx_irq_flag_clr(RF215_BB); pal_trx_irq_flag_clr(RF215_RF); #else pal_trx_irq_flag_clr(); #endif LEAVE_TRX_REGION(); return MAC_SUCCESS; }
/** * @brief Resets TAL state machine and sets the default PIB values if requested * * @param trx_id Transceiver identifier * @param set_default_pib Defines whether PIB values need to be set * to its default values * * @return * - @ref MAC_SUCCESS if the transceiver state is changed to TRX_OFF * - @ref FAILURE otherwise * @ingroup apiTalApi */ retval_t tal_reset(trx_id_t trx_id, bool set_default_pib) { rf_cmd_state_t previous_trx_state[NUM_TRX]; previous_trx_state[RF09] = trx_state[RF09]; previous_trx_state[RF24] = trx_state[RF24]; /* Reset the actual device or part of the device */ if (trx_reset(trx_id) != MAC_SUCCESS) { return FAILURE; } /* Init Trx if necessary, e.g. trx was in deep sleep */ if (((previous_trx_state[RF09] == RF_SLEEP) && (previous_trx_state[RF24] == RF_SLEEP)) || (trx_id == RFBOTH)) { trx_init(); /* Initialize generic trx functionality */ } if (trx_id == RFBOTH) { for (uint8_t i = 0; i < NUM_TRX; i++) { /* Clean TAL and removed any pending tasks */ cleanup_tal((trx_id_t)i); /* Configure the transceiver register values. */ trx_config((trx_id_t)i); if (set_default_pib) { /* Set the default PIB values */ init_tal_pib((trx_id_t)i); /* see 'tal_pib.c' */ calculate_pib_values(trx_id); } else { /* nothing to do - the current TAL PIB attribute *values are used */ } write_all_tal_pib_to_trx((trx_id_t)i); /* see *'tal_pib.c' */ config_phy((trx_id_t)i); /* Reset TAL variables. */ tal_state[(trx_id_t)i] = TAL_IDLE; tx_state[(trx_id_t)i] = TX_IDLE; #ifdef ENABLE_FTN_PLL_CALIBRATION /* Stop FTN timer */ stop_ftn_timer((trx_id_t)i); #endif /* ENABLE_FTN_PLL_CALIBRATION */ } } else { /* Maintain other trx */ trx_id_t other_trx_id; if (trx_id == RF09) { other_trx_id = RF24; } else { other_trx_id = RF09; } if (tal_state[other_trx_id] == TAL_SLEEP) { /* Switch other trx back to sleep again */ uint16_t reg_offset = RF_BASE_ADDR_OFFSET * other_trx_id; #ifdef IQ_RADIO pal_dev_reg_write(RF215_BB, reg_offset + RG_RF09_CMD, RF_SLEEP); pal_dev_reg_write(RF215_RF, reg_offset + RG_RF09_CMD, RF_SLEEP); #else trx_reg_write(reg_offset + RG_RF09_CMD, RF_SLEEP); #endif TAL_RF_IRQ_CLR_ALL(trx_id); } /* Clean TAL and removed any pending tasks */ cleanup_tal(trx_id); /* Configure the transceiver register values. */ trx_config(trx_id); if (set_default_pib) { /* Set the default PIB values */ init_tal_pib(trx_id); /* see 'tal_pib.c' */ calculate_pib_values(trx_id); } else { /* nothing to do - the current TAL PIB attribute values *are used */ } write_all_tal_pib_to_trx(trx_id); /* see 'tal_pib.c' */ config_phy(trx_id); /* Reset TAL variables. */ tal_state[trx_id] = TAL_IDLE; tx_state[trx_id] = TX_IDLE; #ifdef ENABLE_FTN_PLL_CALIBRATION /* Stop FTN timer */ stop_ftn_timer(trx_id); #endif /* ENABLE_FTN_PLL_CALIBRATION */ } /* * Configure interrupt handling. * Install a handler for the transceiver interrupt. */ #ifdef IQ_RADIO trx_irq_init(RF215_BB, bb_irq_handler_cb); trx_irq_init(RF215_RF, rf_irq_handler_cb); pal_trx_irq_en(RF215_BB); /* Enable transceiver main interrupt. */ pal_trx_irq_en(RF215_RF); /* Enable transceiver main interrupt. */ #else trx_irq_init((FUNC_PTR)trx_irq_handler_cb); pal_trx_irq_en(); /* Enable transceiver main interrupt. */ #endif return MAC_SUCCESS; }
/** * @brief Configures the transceiver * * This function is called to configure a certain transceiver (RF09 or RF24) * after trx sleep or reset or power on. * * @param trx_id Transceiver identifier */ void trx_config(trx_id_t trx_id) { uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; #ifdef IQ_RADIO /* LVDS interface */ /* RF part: RF enable, BB disabled, IQIF enabled */ pal_dev_bit_write(RF215_RF, SR_RF_IQIFC1_CHPM, 0x01); /* BB part: RF disable, BB enabled, IQIF enabled */ pal_dev_bit_write(RF215_BB, SR_RF_IQIFC1_CHPM, 0x03); /* Clock Phase I/Q IF Driver at BB */ pal_dev_bit_write(RF215_BB, SR_RF_IQIFC2_CPHADRV, 0); /* Clock Phase I/Q IF Receiver at BB */ pal_dev_bit_write(RF215_BB, SR_RF_IQIFC2_CPHAREC, 1); /* Enable embedded control at RF */ pal_dev_bit_write(RF215_RF, SR_RF_IQIFC0_EEC, 1); #if (BOARD_TYPE == EVAL215_FPGA) pal_dev_bit_write(RF215_RF, SR_RF_IQIFC0_CMV1V2, 1); uint8_t temp = pal_dev_bit_write(RF215_BB, RG_RF_IQIFC1); temp = (temp & 0xF3) | (1 << 2); /* SKEWREC = 0ns */ pal_dev_reg_write(RF215_BB, RG_RF_IQIFC1, temp); #endif /* Configure BB */ /* Setup IRQ mask: in chip mode, the baseband controls the RF's AGC */ pal_dev_reg_write(RF215_BB, reg_offset + RG_BBC0_IRQM, BB_IRQ_ALL_IRQ); pal_dev_reg_write(RF215_BB, reg_offset + RG_RF09_IRQM, RF_IRQ_ALL_IRQ); /* Configure RF */ pal_dev_reg_write(RF215_RF, reg_offset + RG_BBC0_IRQM, BB_IRQ_ALL_IRQ); pal_dev_reg_write(RF215_RF, reg_offset + RG_RF09_IRQM, RF_IRQ_ALL_IRQ); #else /* Configure BB */ /* Setup IRQ mask */ trx_reg_write(reg_offset + RG_BBC0_IRQM, TAL_DEFAULT_BB_IRQ_MASK); /* Configure RF */ trx_reg_write(reg_offset + RG_RF09_IRQM, TAL_DEFAULT_RF_IRQ_MASK); #endif #if (defined IQ_RADIO) && (BOARD_TYPE == EVAL215_FPGA) /* Set clip detector OFF */ uint8_t agcc = pal_dev_reg_read(RF215_RF, reg_offset + RG_RF09_AGCC); agcc |= 0x80; pal_dev_reg_write(RF215_RF, reg_offset + RG_RF09_AGCC, agcc); #endif /* Enable frame filter */ trx_bit_write(reg_offset + SR_BBC0_AFC0_AFEN0, 1); #ifndef BASIC_MODE #if (defined MEASURE_TIME_OF_FLIGHT) && (!defined IQ_RADIO) /* Enable automatic time of flight measurement */ /* bit 3 CAPRXS, bit 2 RSTTXS, bit 0 EN */ uint8_t cnt_cfg = 1 << 0 | 1 << 2 | 1 << 3; trx_reg_write(reg_offset + RG_BBC0_CNTC, cnt_cfg); #endif /* #if (defined MEASURE_TIME_OF_FLIGHT) && (!defined IQ_RADIO) */ #else /* BASIC_MODE */ /* Enable counter for ACK timing: EN | RSTRXS */ uint8_t cntc = 0x01 | 0x02; trx_reg_write(reg_offset + RG_BBC0_CNTC, cntc); #endif #ifndef USE_TXPREP_DURING_BACKOFF /* Keep analog voltage regulator on during TRXOFF */ #ifdef IQ_RADIO pal_dev_bit_write(RF215_RF, reg_offset + SR_RF09_AUXS_AVEN, 1); #else trx_bit_write(reg_offset + SR_RF09_AUXS_AVEN, 1); #endif /* #ifdef IQ_RADIO */ #endif #ifndef BASIC_MODE /* Enable AACK */ trx_reg_write(reg_offset + RG_BBC0_AMCS, AMCS_AACK_MASK); /* Set data pending for ACK frames to 1 for all address units */ trx_reg_write(reg_offset + RG_BBC0_AMAACKPD, 0x0F); #endif #ifdef SUPPORT_MODE_SWITCH /* Use raw mode for mode switch PPDU in the not-inverted manner */ trx_bit_write(reg_offset + SR_BBC0_FSKC4_RAWRBIT, 0); #endif /* Workaround for errata reference #4623 */ if (trx_id == RF09) { #ifdef IQ_MODE pal_dev_reg_write(RF215_RF, 0x129, 0x04); #else trx_reg_write(0x129, 0x04); #endif } }
/* * \brief Write all shadow PIB variables to the transceiver * * This function writes all shadow PIB variables to the transceiver. * It is assumed that the radio does not sleep. */ void write_all_tal_pib_to_trx(void) { uint8_t *ptr_to_reg; ptr_to_reg = (uint8_t *)&tal_pib.PANId; for (uint8_t i = 0; i < 2; i++) { trx_reg_write((RG_PAN_ID_0 + i), *ptr_to_reg); ptr_to_reg++; } ptr_to_reg = (uint8_t *)&tal_pib.IeeeAddress; for (uint8_t i = 0; i < 8; i++) { trx_reg_write((RG_IEEE_ADDR_0 + i), *ptr_to_reg); ptr_to_reg++; } ptr_to_reg = (uint8_t *)&tal_pib.ShortAddress; for (uint8_t i = 0; i < 2; i++) { trx_reg_write((RG_SHORT_ADDR_0 + i), *ptr_to_reg); ptr_to_reg++; } /* Configure TX_ARET; CSMA and CCA */ trx_bit_write(SR_CCA_MODE, tal_pib.CCAMode); #ifdef SW_CONTROLLED_CSMA /* * If receiver is enabled during backoff periods, * CSMA and frame re-transmissions are handled by software. * Setup trx for immediate transmission. */ trx_bit_write(SR_MAX_FRAME_RETRIES, 0); trx_bit_write(SR_MAX_CSMA_RETRIES, 7); #else trx_bit_write(SR_MIN_BE, tal_pib.MinBE); trx_bit_write(SR_MAX_BE, tal_pib.MaxBE); #endif trx_bit_write(SR_AACK_I_AM_COORD, tal_pib.PrivatePanCoordinator); /* set phy parameter */ #ifdef HIGH_DATA_RATE_SUPPORT apply_channel_page_configuration(tal_pib.CurrentPage); #endif trx_bit_write(SR_CHANNEL, tal_pib.CurrentChannel); { uint8_t reg_value; reg_value = convert_phyTransmitPower_to_reg_value( tal_pib.TransmitPower); trx_bit_write(SR_TX_PWR, reg_value); } #ifdef PROMISCUOUS_MODE if (tal_pib.PromiscuousMode) { set_trx_state(CMD_RX_ON); } #endif }
/** * \brief Init the radio * \return Returns success/fail * \retval 0 Success */ int rf233_init(void) { volatile uint8_t regtemp; volatile uint8_t radio_state; /* don't optimize this away, it's important */ PRINTF("RF233: init.\n"); /* init SPI and GPIOs, wake up from sleep/power up. */ spi_init(); // RF233 expects line low for CS, this is default SAM4L behavior //spi_set_chip_select(3); // POL = 0 means idle is low spi_set_chip_select(3); spi_set_polarity(0); // PHASE = 0 means sample leading edge spi_set_phase(0); spi_set_rate(400000); /* reset will put us into TRX_OFF state */ /* reset the radio core */ gpio_enable_output(RST_PIN); gpio_enable_output(SLP_PIN); gpio_clear(RST_PIN); delay_ms(1); gpio_set(RST_PIN); gpio_clear(SLP_PIN); /* be awake from sleep*/ /* Read the PART_NUM register to verify that the radio is * working/responding. Could check in software, I just look at * the bus. If this is working, the first write should be 0x9C x00 * and the return bytes should be 0x00 0x0B. - pal*/ regtemp = trx_reg_read(RF233_REG_PART_NUM); /* before enabling interrupts, make sure we have cleared IRQ status */ regtemp = trx_reg_read(RF233_REG_IRQ_STATUS); PRINTF("RF233: After wake from sleep\n"); radio_state = rf233_status(); PRINTF("RF233: Radio state 0x%04x\n", radio_state); calibrate_filters(); if (radio_state == STATE_P_ON) { trx_reg_write(RF233_REG_TRX_STATE, TRXCMD_TRX_OFF); } /* Assign regtemp to regtemp to avoid compiler warnings */ regtemp = regtemp; // Set up interrupts gpio_interrupt_callback(interrupt_callback, NULL); gpio_enable_input(RADIO_IRQ, PullNone); gpio_clear(RADIO_IRQ); gpio_enable_interrupt(RADIO_IRQ, PullNone, RisingEdge); /* Configure the radio using the default values except these. */ trx_reg_write(RF233_REG_TRX_CTRL_1, RF233_REG_TRX_CTRL_1_CONF); trx_reg_write(RF233_REG_PHY_CC_CCA, RF233_REG_PHY_CC_CCA_CONF); trx_reg_write(RF233_REG_PHY_TX_PWR, RF233_REG_PHY_TX_PWR_CONF); trx_reg_write(RF233_REG_TRX_CTRL_2, RF233_REG_TRX_CTRL_2_CONF); trx_reg_write(RF233_REG_IRQ_MASK, RF233_REG_IRQ_MASK_CONF); trx_reg_write(RF233_REG_XAH_CTRL_1, 0x02); trx_bit_write(SR_MAX_FRAME_RETRIES, 0); trx_bit_write(SR_MAX_CSMA_RETRIES, 0); PRINTF("RF233: Configured transciever.\n"); { uint8_t addr[8]; addr[0] = 0x22; addr[1] = 0x22; addr[2] = 0x22; addr[3] = 0x22; addr[4] = 0x22; addr[5] = 0x22; addr[6] = 0x22; addr[7] = 0x22; SetPanId(IEEE802154_CONF_PANID); SetIEEEAddr(addr); SetShortAddr(0x2222); } rf_generate_random_seed(); for (uint8_t i = 0; i < 8; i++) { regtemp = trx_reg_read(0x24 + i); } /* 11_09_rel */ trx_reg_write(RF233_REG_TRX_RPC, 0xFF); /* Enable RPC feature by default */ PRINTF("RF233: Installed addresses. Turning on radio."); rf233_on(); return 0; }
/** * @brief Starts continuous transmission on current channel * * @param trx_id Identifier of the transceiver * @param tx_mode Transmission mode */ void tfa_continuous_tx_start(trx_id_t trx_id, continuous_tx_mode_t tx_mode) { uint16_t len; if (tal_state[trx_id] != TAL_IDLE) { return; } #ifdef IQ_RADIO if (trx_id == RF09) { /* Check if the other radio is currently in use */ if (trx_state[RF24] == RF_TX) { return; } else { /* Select corresponding baseband core */ pal_dev_bit_write(RF215_BB, SR_RF_IQIFC2_CSELTX, RF09); /* * RF09 * is * selected */ } } else { /* Check if the other radio is currently in use */ if (trx_state[RF09] == RF_TX) { return; } else { /* Select corresponding baseband core */ pal_dev_bit_write(RF215_BB, SR_RF_IQIFC2_CSELTX, RF24); /* * RF24 * is * selected */ } } #endif if (trx_state[trx_id] == RF_RX) { tal_state[trx_id] = TAL_TFA_CW_RX; } else { tal_state[trx_id] = TAL_TFA_CW; } /* Set to TxPREP state */ switch_to_txprep(trx_id); uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; if (tx_mode == CW_MODE) { #ifdef IQ_RADIO /* Disable embedded TX control */ pal_dev_bit_write(RF215_RF, SR_RF_IQIFC0_EEC, 0); #else /* Enable baseband bypass */ trx_bit_write(SR_RF_IQIFC1_CHPM, 1); #endif /* Configure DAC to generate carrier signal */ uint8_t dac_config[2] = {(0x7E | 0x80), (0x3F | 0x80)}; #ifdef IQ_RADIO pal_dev_write(RF215_RF, reg_offset + RG_RF09_TXDACI, dac_config, 2); #else trx_write(reg_offset + RG_RF09_TXDACI, dac_config, 2); #endif /* Trigger Tx start */ #ifdef IQ_RADIO pal_dev_reg_write(RF215_RF, reg_offset + RG_RF09_CMD, RF_TX); #else trx_reg_write(reg_offset + RG_RF09_CMD, RF_TX); #endif trx_state[trx_id] = RF_TX; } else { /* PRBS mode */ /* Enable continuous transmission mode */ trx_bit_write(reg_offset + SR_BBC0_PC_CTX, 1); /* Fill length field */ #ifdef SUPPORT_LEGACY_OQPSK if (tal_pib[trx_id].phy.modulation == LEG_OQPSK) { len = 127; } else #endif { len = 2047; } trx_write(reg_offset + RG_BBC0_TXFLL, (uint8_t *)&len, 2); trx_reg_write(reg_offset + RG_RF09_CMD, RF_TX); trx_state[trx_id] = RF_TX; /* Fill frame buffer */ uint16_t tx_frm_buf_offset = BB_TX_FRM_BUF_OFFSET * trx_id; uint8_t data[10]; for (uint16_t k = 0; k < (len / 10); k++) { for (uint16_t i = 0; i < 10; i++) { data[i] = (uint8_t)rand(); } trx_write(tx_frm_buf_offset + RG_BBC0_FBTXS, data, 10); tx_frm_buf_offset += 10; } uint16_t remaining_bytes = len % 10; for (uint16_t i = 0; i < remaining_bytes; i++) { data[i] = (uint8_t)rand(); } trx_write(tx_frm_buf_offset + RG_BBC0_FBTXS, data, remaining_bytes); } }
void SetPanId(uint16_t panId) { uint8_t *d = (uint8_t *)&panId; trx_reg_write(0x22, d[0]); trx_reg_write(0x23, d[1]); }
/* * \brief Sets a TAL PIB attribute * * This function is called to set the transceiver information base * attributes. * * \param attribute TAL infobase attribute ID * \param value TAL infobase attribute value to be set * * \return MAC_UNSUPPORTED_ATTRIBUTE if the TAL info base attribute is not found * TAL_BUSY if the TAL is not in TAL_IDLE state. An exception is * macBeaconTxTime which can be accepted by TAL even if TAL is not * in TAL_IDLE state. * MAC_SUCCESS if the attempt to set the PIB attribute was successful * TAL_TRX_ASLEEP if trx is in SLEEP mode and access to trx is required */ retval_t tal_pib_set(uint8_t attribute, pib_value_t *value) { /* * Do not allow any changes while ED or TX is done. * We allow changes during RX, but it's on the user's own risk. */ #if (MAC_SCAN_ED_REQUEST_CONFIRM == 1) if (tal_state == TAL_ED_RUNNING) { Assert("TAL is busy" == 0); return TAL_BUSY; } #endif /* (MAC_SCAN_ED_REQUEST_CONFIRM == 1) */ /* * Distinguish between PIBs that need to be changed in trx directly * and those that are simple variable udpates. * Ensure that the transceiver is not in SLEEP. * If it is in SLEEP, change it to TRX_OFF. */ switch (attribute) { case macMaxFrameRetries: /* * The new PIB value is not immediately written to the * transceiver. This is done on a frame-by-frame base. */ tal_pib.MaxFrameRetries = value->pib_value_8bit; break; case macMaxCSMABackoffs: /* * The new PIB value is not immediately written to the * transceiver. This is done on a frame-by-frame base. */ tal_pib.MaxCSMABackoffs = value->pib_value_8bit; break; #ifdef BEACON_SUPPORT case macBattLifeExt: tal_pib.BattLifeExt = value->pib_value_bool; break; case macBeaconOrder: tal_pib.BeaconOrder = value->pib_value_8bit; break; case macSuperframeOrder: tal_pib.SuperFrameOrder = value->pib_value_8bit; break; case macBeaconTxTime: tal_pib.BeaconTxTime = value->pib_value_32bit; break; #endif /* BEACON_SUPPORT */ #ifdef PROMISCUOUS_MODE case macPromiscuousMode: tal_pib.PromiscuousMode = value->pib_value_8bit; if (tal_pib.PromiscuousMode) { tal_trx_wakeup(); /* Check if receive buffer is available or queue is not * full. */ if (NULL == tal_rx_buffer) { set_trx_state(CMD_PLL_ON); tal_rx_on_required = true; } else { set_trx_state(CMD_RX_ON); } } else { set_trx_state(CMD_TRX_OFF); tal_rx_on_required = false; } break; #endif default: /* * Following PIBs require access to trx. * Therefore trx must be at least in TRX_OFF. */ if (tal_trx_status == TRX_SLEEP) { /* While trx is in SLEEP, register cannot be accessed. **/ return TAL_TRX_ASLEEP; } switch (attribute) { case macMinBE: tal_pib.MinBE = value->pib_value_8bit; #ifndef REDUCED_PARAM_CHECK /* * macMinBE must not be larger than macMaxBE or * calculation * of macMaxFrameWaitTotalTime will fail. */ if (tal_pib.MinBE > tal_pib.MaxBE) { tal_pib.MinBE = tal_pib.MaxBE; } #endif /* REDUCED_PARAM_CHECK */ trx_bit_write(SR_MIN_BE, tal_pib.MinBE); break; case macPANId: tal_pib.PANId = value->pib_value_16bit; trx_reg_write(RG_PAN_ID_0, (uint8_t)tal_pib.PANId); trx_reg_write(RG_PAN_ID_1, (uint8_t)(tal_pib.PANId >> 8)); break; case macShortAddress: tal_pib.ShortAddress = value->pib_value_16bit; trx_reg_write(RG_SHORT_ADDR_0, (uint8_t)tal_pib.ShortAddress); trx_reg_write(RG_SHORT_ADDR_1, (uint8_t)(tal_pib.ShortAddress >> 8)); break; case phyCurrentChannel: if (tal_state != TAL_IDLE) { return TAL_BUSY; } if ((uint32_t)TRX_SUPPORTED_CHANNELS & ((uint32_t)0x01 << value->pib_value_8bit)) { tal_trx_status_t previous_trx_status = TRX_OFF; /* * Set trx to "soft" off avoiding that ongoing * transaction (e.g. ACK) are interrupted. */ if (tal_trx_status != TRX_OFF) { previous_trx_status = RX_AACK_ON; /* any * *other * *than * *TRX_OFF * *state **/ do { /* set TRX_OFF until it could be * set; * trx might be busy */ } while (set_trx_state(CMD_TRX_OFF) != TRX_OFF); } tal_pib.CurrentChannel = value->pib_value_8bit; trx_bit_write(SR_CHANNEL, tal_pib.CurrentChannel); /* Re-store previous trx state */ if (previous_trx_status != TRX_OFF) { /* Set to default state */ set_trx_state(CMD_RX_AACK_ON); } } else { return MAC_INVALID_PARAMETER; } break; case phyCurrentPage: #ifdef HIGH_DATA_RATE_SUPPORT if (tal_state != TAL_IDLE) { return TAL_BUSY; } else { uint8_t page; tal_trx_status_t previous_trx_status = TRX_OFF; bool ret_val; /* * Changing the channel, channel page or * modulation * requires that TRX is in TRX_OFF. * Store current trx state and return to default * state * after channel page has been set. */ if (tal_trx_status != TRX_OFF) { previous_trx_status = RX_AACK_ON; /* any * *other * *than * *TRX_OFF * *state **/ do { /* set TRX_OFF until it could be * set; * trx might be busy */ } while (set_trx_state(CMD_TRX_OFF) != TRX_OFF); } page = value->pib_value_8bit; ret_val = apply_channel_page_configuration(page); if (previous_trx_status != TRX_OFF) { /* Set to default state */ set_trx_state(CMD_RX_AACK_ON); } if (ret_val) { tal_pib.CurrentPage = page; } else { return MAC_INVALID_PARAMETER; } } #else if (tal_state != TAL_IDLE) { return TAL_BUSY; } else { uint8_t page; page = value->pib_value_8bit; if (page != 0) { return MAC_INVALID_PARAMETER; } } #endif /* #ifdef HIGH_DATA_RATE_SUPPORT */ break; case macMaxBE: tal_pib.MaxBE = value->pib_value_8bit; #ifndef REDUCED_PARAM_CHECK /* * macMinBE must not be larger than macMaxBE or * calculation * of macMaxFrameWaitTotalTime will fail. */ if (tal_pib.MaxBE < tal_pib.MinBE) { tal_pib.MinBE = tal_pib.MaxBE; } #endif /* REDUCED_PARAM_CHECK */ trx_bit_write(SR_MAX_BE, tal_pib.MaxBE); break; case phyTransmitPower: { uint8_t reg_value; tal_pib.TransmitPower = value->pib_value_8bit; /* Limit tal_pib.TransmitPower to max/min trx values */ tal_pib.TransmitPower = limit_tx_pwr( tal_pib.TransmitPower); reg_value = convert_phyTransmitPower_to_reg_value( tal_pib.TransmitPower); trx_bit_write(SR_TX_PWR, reg_value); } break; case phyCCAMode: tal_pib.CCAMode = value->pib_value_8bit; trx_bit_write(SR_CCA_MODE, tal_pib.CCAMode); break; case macIeeeAddress: { uint8_t *ptr; tal_pib.IeeeAddress = value->pib_value_64bit; ptr = (uint8_t *)&tal_pib.IeeeAddress; for (uint8_t i = 0; i < 8; i++) { trx_reg_write((RG_IEEE_ADDR_0 + i), *ptr); ptr++; } } break; case mac_i_pan_coordinator: tal_pib.PrivatePanCoordinator = value->pib_value_bool; trx_bit_write(SR_AACK_I_AM_COORD, tal_pib.PrivatePanCoordinator); break; case macAckWaitDuration: /* * ATmegaRFA2 does not support changing this value * w.r.t. * compliance operation. * The ACK timing can be reduced to 2 symbols using TFA * function. */ return MAC_UNSUPPORTED_ATTRIBUTE; default: return MAC_UNSUPPORTED_ATTRIBUTE; } break; /* end of 'default' from 'switch (attribute)' */ } return MAC_SUCCESS; } /* tal_pib_set() */
/** * \brief prepare a frame and the radio for immediate transmission * \param payload Pointer to data to copy/send * \param payload_len length of data to copy * \return Returns success/fail, refer to radio.h for explanation */ static int rf212_prepare(const void *payload, unsigned short payload_len) { #if DEBUG_PRINTDATA int i; #endif /* DEBUG_PRINTDATA */ uint8_t templen; uint8_t radio_status; uint8_t data[130]; #if USE_HW_FCS_CHECK /* Add length of the FCS (2 bytes) */ templen = payload_len + 2; #else /* USE_HW_FCS_CHECK */ /* FCS is assumed to already be included in the payload */ templen = payload_len; #endif /* USE_HW_FCS_CHECK */ data[0] = templen; memcpy(&data[1],payload,templen); #if DEBUG_PRINTDATA PRINTF("RF212 prepare (%u/%u): 0x", payload_len, templen); for(i = 0; i < templen; i++) { PRINTF("%02x", *(uint8_t *)(payload + i)); } PRINTF("\n"); #endif /* DEBUG_PRINTDATA */ PRINTF("RF212: prepare %u\n", payload_len); if(payload_len > MAX_PACKET_LEN) { PRINTF("RF212: error, frame too large to tx\n"); return RADIO_TX_ERR; } /* check that the FIFO is clear to access */ radio_status = rf212_status(); #if NULLRDC_CONF_802154_AUTOACK_HW if(radio_status == STATE_BUSY_RX_AACK || radio_status == STATE_BUSY_TX_ARET) { PRINTF("RF212B: TRX buffer unavailable: prep when %s\n", radio_status == STATE_BUSY_RX_AACK ? "rx" : "tx"); #else if(radio_status == STATE_BUSY_RX || radio_status == STATE_BUSY_TX) { PRINTF("RF212B: TRX buffer unavailable: prep when %s\n", radio_status == STATE_BUSY_RX? "rx" : "tx"); #endif return RADIO_TX_ERR; } /* Write packet to TX FIFO. */ PRINTF("RF212 len = %u\n", payload_len); trx_frame_write((uint8_t *)data, templen+1); return RADIO_TX_OK; } /*---------------------------------------------------------------------------*/ /** * \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 */ static int rf212_transmit(unsigned short payload_len) { uint8_t status_now;//,temp; PRINTF("RF212: tx %u\n", payload_len); /* prepare for TX */ status_now = rf212_status(); #if NULLRDC_CONF_802154_AUTOACK_HW if(status_now == STATE_BUSY_RX_AACK || status_now == STATE_BUSY_TX_ARET) { #else if(status_now == STATE_BUSY_RX || status_now == STATE_BUSY_TX) { #endif PRINTF("RF212: collision, was receiving\n"); /* NOTE: to avoid loops */ return RADIO_TX_ERR; // return RADIO_TX_COLLISION; } if(status_now != STATE_PLL_ON) { /* prepare for going to state TX, should take max 80 us */ //RF212_COMMAND(TRXCMD_PLL_ON); trx_reg_write(RF212_REG_TRX_STATE,0x09); do { status_now = trx_bit_read(0x01, 0x1F, 0); } while (status_now == 0x1f); //BUSYWAIT_UNTIL(RF212_STATUS() == STATE_PLL_ON, 1 * RTIMER_SECOND/1000); } if(rf212_status() != STATE_PLL_ON) { /* failed moving into PLL_ON state, gracefully try to recover */ PRINTF("RF212: failed going to PLLON\n"); RF212_COMMAND(TRXCMD_PLL_ON); /* try again */ if(rf212_status() != STATE_PLL_ON) { /* give up and signal big fail (should perhaps reset radio core instead?) */ PRINTF("RF212: graceful recovery (in tx) failed, giving up. State: 0x%02X\n", RF212_STATUS()); return RADIO_TX_ERR; } } /* perform transmission */ ENERGEST_OFF(ENERGEST_TYPE_LISTEN); ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); #if NULLRDC_CONF_802154_AUTOACK_HW RF212_COMMAND(TRXCMD_TX_ARET_ON); #endif RF212_COMMAND(TRXCMD_TX_START); flag_transmit=1; #if !NULLRDC_CONF_802154_AUTOACK_HW BUSYWAIT_UNTIL(RF212_STATUS() == STATE_BUSY_TX, RTIMER_SECOND/2000); BUSYWAIT_UNTIL(RF212_STATUS() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); #if (DATA_RATE==BPSK_20||BPSK_40||OQPSK_SIN_RC_100) BUSYWAIT_UNTIL(RF212_STATUS() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); BUSYWAIT_UNTIL(RF212_STATUS() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); BUSYWAIT_UNTIL(RF212_STATUS() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); #endif #endif ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); ENERGEST_ON(ENERGEST_TYPE_LISTEN); #if !NULLRDC_CONF_802154_AUTOACK_HW if(RF212_STATUS() != STATE_PLL_ON) { /* something has failed */ printf("RF212: radio fatal err after tx\n"); radiocore_hard_recovery(); return RADIO_TX_ERR; } // printf("#RTIMER_SECOND"); RF212_COMMAND(TRXCMD_RX_ON); #else BUSYWAIT_UNTIL(ack_status == 1, 10 * RTIMER_SECOND/1000); if((ack_status)) { // printf("\r\nrf233 sent\r\n "); ack_status=0; // printf("\nACK received"); return RADIO_TX_OK; } else { // printf("\nNOACK received"); return RADIO_TX_NOACK; } #endif PRINTF("RF212: tx ok\n"); return RADIO_TX_OK; } void goto_sleep(void) { port_pin_set_output_level(AT86RFX_SLP_PIN, true); }
/* * \brief Sets transceiver state * * \param trx_cmd needs to be one of the trx commands * * \return current trx state */ tal_trx_status_t set_trx_state(trx_cmd_t trx_cmd) { if (tal_trx_status == TRX_SLEEP) { /* * Since the wake-up procedure relies on the Awake IRQ and * the global interrupts may be disabled at this point of time, * we need to make sure that the global interrupts are enabled * during wake-up procedure. * Once the TRX is awake, the original state of the global * interrupts * will be restored. */ /* Reset wake-up interrupt flag. */ if (CMD_SLEEP == trx_cmd) { return TRX_SLEEP; } tal_awake_end_flag = false; /* Set callback function for the awake interrupt. */ trx_irq_init((FUNC_PTR)trx_irq_awake_handler_cb); /* The pending transceiver interrupts on the microcontroller are * cleared. */ pal_trx_irq_flag_clr(); pal_trx_irq_en(); /* Enable transceiver main interrupt. */ /* Save current state of global interrupts. */ ENTER_CRITICAL_REGION(); /* Force enabling of global interrupts. */ ENABLE_GLOBAL_IRQ(); /* Leave trx sleep mode. */ TRX_SLP_TR_LOW(); /* Poll wake-up interrupt flag until set within ISR. */ while (!tal_awake_end_flag) { } /* Restore original state of global interrupts. */ LEAVE_CRITICAL_REGION(); /* Clear existing interrupts */ trx_reg_read(RG_IRQ_STATUS); /* Re-install default IRQ handler for main interrupt. */ trx_irq_init((FUNC_PTR)trx_irq_handler_cb); /* Re-enable TRX_END interrupt */ trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); #if (ANTENNA_DIVERSITY == 1) /* Enable antenna diversity. */ trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE); #endif #ifdef EXT_RF_FRONT_END_CTRL /* Enable RF front end control */ trx_bit_write(SR_PA_EXT_EN, 1); #endif tal_trx_status = TRX_OFF; if ((trx_cmd == CMD_TRX_OFF) || (trx_cmd == CMD_FORCE_TRX_OFF)) { return TRX_OFF; } } #ifdef ENABLE_DEEP_SLEEP else if (tal_trx_status == TRX_DEEP_SLEEP) { if (CMD_DEEP_SLEEP == trx_cmd) { return TRX_DEEP_SLEEP; } /* Leave trx sleep mode. */ TRX_SLP_TR_LOW(); /* Check if trx has left deep sleep. */ tal_trx_status_t trx_state; do { trx_state = trx_reg_read( RG_TRX_STATUS); } while (trx_state != TRX_OFF); tal_trx_status = TRX_OFF; /* Using deep sleep, the transceiver's registers need to be * restored. */ trx_config(); /* * Write all PIB values to the transceiver * that are needed by the transceiver itself. */ write_all_tal_pib_to_trx(); /* implementation can be found in *'tal_pib.c' */ if ((trx_cmd == CMD_TRX_OFF) || (trx_cmd == CMD_FORCE_TRX_OFF)) { return TRX_OFF; } } #endif switch (trx_cmd) { /* requested state */ case CMD_SLEEP: #ifdef ENABLE_DEEP_SLEEP /* Fall through. */ case CMD_DEEP_SLEEP: #endif trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); #if (ANTENNA_DIVERSITY == 1) /* * Disable antenna diversity: to reduce the power consumption * or * avoid leakage current of an external RF switch during SLEEP. */ trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_DISABLE); #endif #ifdef EXT_RF_FRONT_END_CTRL /* Disable RF front end control */ trx_bit_write(SR_PA_EXT_EN, 0); #endif /* Clear existing interrupts */ trx_reg_read(RG_IRQ_STATUS); /* * Enable Awake_end interrupt. * This is used for save wake-up from sleep later. */ trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); #ifdef ENABLE_DEEP_SLEEP if (trx_cmd == CMD_DEEP_SLEEP) { trx_reg_write(RG_TRX_STATE, CMD_PREP_DEEP_SLEEP); tal_trx_status = TRX_DEEP_SLEEP; } else { /* * Enable Awake_end interrupt. * This is used for save wake-up from sleep later. */ trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); tal_trx_status = TRX_SLEEP; } #else /* * Enable Awake_end interrupt. * This is used for save wake-up from sleep later. */ trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); tal_trx_status = TRX_SLEEP; #endif PAL_WAIT_1_US(); TRX_SLP_TR_HIGH(); pal_timer_delay(TRX_OFF_TO_SLEEP_TIME_CLKM_CYCLES); /* Transceiver register cannot be read during TRX_SLEEP or * DEEP_SLEEP. */ return tal_trx_status; case CMD_TRX_OFF: switch (tal_trx_status) { case TRX_OFF: break; default: trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); PAL_WAIT_1_US(); break; } break; case CMD_FORCE_TRX_OFF: switch (tal_trx_status) { case TRX_OFF: break; default: trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); PAL_WAIT_1_US(); break; } break; case CMD_PLL_ON: switch (tal_trx_status) { case PLL_ON: break; case TRX_OFF: switch_pll_on(); break; case RX_ON: case RX_AACK_ON: case TX_ARET_ON: trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; case CMD_FORCE_PLL_ON: switch (tal_trx_status) { case TRX_OFF: switch_pll_on(); break; case PLL_ON: break; default: trx_reg_write(RG_TRX_STATE, CMD_FORCE_PLL_ON); break; } break; case CMD_RX_ON: switch (tal_trx_status) { case RX_ON: break; case PLL_ON: case RX_AACK_ON: case TX_ARET_ON: trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; case CMD_RX_AACK_ON: switch (tal_trx_status) { case RX_AACK_ON: break; case TX_ARET_ON: case PLL_ON: case RX_ON: trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); /* state change from TRX_OFF to * RX_AACK_ON can be done directly, too **/ trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; case CMD_TX_ARET_ON: switch (tal_trx_status) { case TX_ARET_ON: break; case PLL_ON: case RX_ON: case RX_AACK_ON: trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); /* state change from TRX_OFF to * TX_ARET_ON can be done directly, too **/ trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; default: /* CMD_NOP, CMD_TX_START */ Assert("trx command not handled" == 0); break; } do { tal_trx_status = /* (tal_trx_status_t) */ trx_bit_read( SR_TRX_STATUS); } while (tal_trx_status == STATE_TRANSITION_IN_PROGRESS); return tal_trx_status; } /* set_trx_state() */
void SetShortAddr(uint16_t addr) { uint8_t *d = (uint8_t *)&addr; trx_reg_write(0x20, d[0]); trx_reg_write(0x21, d[1]); }
/** * \brief Configures the transceiver * * This function is called to configure the transceiver after reset. */ static void trx_config(void) { /* Set pin driver strength */ trx_bit_write(SR_PAD_IO_CLKM, PAD_CLKM_2_MA); trx_bit_write(SR_CLKM_SHA_SEL, CLKM_SHA_DISABLE); trx_bit_write(SR_CLKM_CTRL, CLKM_1MHZ); #ifndef SW_CONTROLLED_CSMA /* After we have initialized a proper seed for rand(), * the transceiver's CSMA seed can be initialized. * It needs to be assured that a seed for function rand() * had been generated before. */ /* * Init the SEED value of the CSMA backoff algorithm. */ uint16_t rand_value = (uint16_t)rand(); trx_reg_write(RG_CSMA_SEED_0, (uint8_t)rand_value); trx_bit_write(SR_CSMA_SEED_1, (uint8_t)(rand_value >> 8)); /* * To make sure that the CSMA seed is properly set within the * transceiver, * put the trx to sleep briefly and wake it up again. */ tal_trx_sleep(SLEEP_MODE_1); tal_trx_wakeup(); #endif trx_bit_write(SR_AACK_SET_PD, PD_ACK_BIT_SET_ENABLE); /* ACKs for * data * requests, * indicate * pending data **/ trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_ENABLE); /* Enable * buffer * protection * mode */ trx_bit_write(SR_IRQ_MASK_MODE, IRQ_MASK_MODE_ON); /* Enable poll * mode */ trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); /* The TRX_END * interrupt of the * transceiver is * enabled. */ #if (ANTENNA_DIVERSITY == 1) /* Use antenna diversity */ trx_bit_write(SR_ANT_CTRL, ANTENNA_DEFAULT); trx_bit_write(SR_PDT_THRES, THRES_ANT_DIV_ENABLE); trx_bit_write(SR_ANT_DIV_EN, ANT_DIV_ENABLE); trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE); #elif (DISABLE_TSTAMP_IRQ == 0) #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) /* * Use timestamping. * The timestamping is only required for beaconing networks * or if timestamping is explicitly enabled. */ trx_bit_write(SR_IRQ_2_EXT_EN, TIMESTAMPING_ENABLE); /* Enable * timestamping * output * signal. */ #endif /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */ #endif #ifdef CCA_ED_THRESHOLD /* * Set CCA ED Threshold to other value than standard register due to * board specific loss (see pal_config.h). */ trx_bit_write(SR_CCA_ED_THRES, CCA_ED_THRESHOLD); #endif #ifdef EXT_RF_FRONT_END_CTRL /* Enable RF front end control */ trx_bit_write(SR_PA_EXT_EN, PA_EXT_ENABLE); #endif }
/** * @brief Read Energy Detection Level Now * * forces a reading of the ED level * * range is between -90 and -6 dBm * where -6 is the best * * @return ED level */ int8_t cMxRadio::getEdNow() { trx_reg_write(RG_PHY_ED_LEVEL, 0); // forces a reading return getLastEd(); }
/** * \brief prepare a frame and the radio for immediate transmission * \param payload Pointer to data to copy/send * \param payload_len length of data to copy * \return Returns success/fail, refer to radio.h for explanation */ int rf233_prepare(const void *payload, unsigned short payload_len) { #if DEBUG_PRINTDATA int i; #endif /* DEBUG_PRINTDATA */ uint8_t templen; uint8_t radio_status; uint8_t data[130]; #if USE_HW_FCS_CHECK /* Add length of the FCS (2 bytes) */ templen = payload_len + 2; #else /* USE_HW_FCS_CHECK */ /* FCS is assumed to already be included in the payload */ templen = payload_len; #endif /* USE_HW_FCS_CHECK */ //data = templen; /* for(i = 0; i < templen; i++) { data++; data =(uint8_t *)(payload + i); }*/ //memcpy(data,&templen,1); data[0] = templen; memcpy(&data[1],payload,templen); //data--; #if DEBUG_PRINTDATA PRINTF("RF233 prepare (%u/%u): 0x", payload_len, templen); for(i = 0; i < templen; i++) { PRINTF("%02x", *(uint8_t *)(payload + i)); } PRINTF("\r\n"); #endif /* DEBUG_PRINTDATA */ PRINTF("RF233: prepare %u\r\n", payload_len); if(payload_len > MAX_PACKET_LEN) { PRINTF("RF233: error, frame too large to tx\r\n"); return RADIO_TX_ERR; } /* check that the FIFO is clear to access */ radio_status=rf233_status(); #if NULLRDC_CONF_802154_AUTOACK_HW if(radio_status == STATE_BUSY_RX_AACK || radio_status == STATE_BUSY_TX_ARET) { PRINTF("RF233: TRX buffer unavailable: prep when %s\r\n", radio_status == STATE_BUSY_RX_AACK ? "rx" : "tx"); #else if(radio_status == STATE_BUSY_RX || radio_status == STATE_BUSY_TX) { PRINTF("RF233: TRX buffer unavailable: prep when %s\r\n", radio_status == STATE_BUSY_RX? "rx" : "tx"); #endif return RADIO_TX_ERR; } /* Write packet to TX FIFO. */ PRINTF("RF233 len = %u\r\n", payload_len); trx_frame_write((uint8_t *)data, templen+1); return RADIO_TX_OK; } /*---------------------------------------------------------------------------*/ /** * \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(unsigned short payload_len) { static uint8_t status_now; PRINTF("RF233: tx %u\r\n", payload_len); /* prepare for TX */ status_now = rf233_status(); //status_now = trx_reg_read(RF233_REG_TRX_RPC); #if NULLRDC_CONF_802154_AUTOACK_HW if(status_now == STATE_BUSY_RX_AACK || status_now == STATE_BUSY_TX_ARET) { #else if(status_now == STATE_BUSY_RX || status_now == STATE_BUSY_TX) { #endif PRINTF("RF233: collision, was receiving 0x%02X\r\n",status_now); /* NOTE: to avoid loops */ return RADIO_TX_ERR;; // return RADIO_TX_COLLISION; } if(status_now != STATE_PLL_ON) { /* prepare for going to state TX, should take max 80 us */ //RF233_COMMAND(TRXCMD_PLL_ON); trx_reg_write(RF233_REG_TRX_STATE,0x09); // BUSYWAIT_UNTIL(trx_reg_read(RF233_REG_TRX_STATUS) == STATE_PLL_ON, 1 * RTIMER_SECOND/1000); //delay_ms(10); //status_now = trx_reg_read(RF233_REG_TRX_STATE); do { status_now = trx_bit_read(0x01, 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 PLLON\r\n"); RF233_COMMAND(TRXCMD_PLL_ON); /* try again */ static uint8_t state; state = rf233_status(); if(state != STATE_PLL_ON) { /* give up and signal big fail (should perhaps reset radio core instead?) */ PRINTF("RF233: graceful recovery (in tx) failed, giving up. State: 0x%02X\r\n", rf233_status()); return RADIO_TX_ERR; } } /* perform transmission */ ENERGEST_OFF(ENERGEST_TYPE_LISTEN); ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); #if NULLRDC_CONF_802154_AUTOACK_HW RF233_COMMAND(TRXCMD_TX_ARET_ON); #endif RF233_COMMAND(TRXCMD_TX_START); flag_transmit=1; //delay_ms(5); //printf("RTIMER value %d",RTIMER_NOW()); #if !NULLRDC_CONF_802154_AUTOACK_HW BUSYWAIT_UNTIL(rf233_status() == STATE_BUSY_TX, RTIMER_SECOND/2000); // printf("RTIMER value1 %d",RTIMER_NOW()); // printf("\r\nSTATE_BUSY_TX"); BUSYWAIT_UNTIL(rf233_status() != STATE_BUSY_TX, 10 * RTIMER_SECOND/1000); // printf("RTIMER value2 %d",RTIMER_NOW()); #endif ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); ENERGEST_ON(ENERGEST_TYPE_LISTEN); #if !NULLRDC_CONF_802154_AUTOACK_HW if(rf233_status() != STATE_PLL_ON) { // something has failed PRINTF("RF233: radio fatal err after tx\r\n"); radiocore_hard_recovery(); return RADIO_TX_ERR; } RF233_COMMAND(TRXCMD_RX_ON); #else BUSYWAIT_UNTIL(ack_status == 1, 10 * RTIMER_SECOND/1000); if((ack_status)) { // printf("\r\nrf233 sent\r\n "); ack_status=0; // printf("\nACK received"); return RADIO_TX_OK; } else { // printf("\nNOACK received"); return RADIO_TX_NOACK; } #endif PRINTF("RF233: tx ok\r\n"); return RADIO_TX_OK; } /*---------------------------------------------------------------------------*/ /** * \brief Send data: first prepares, then transmits * \param payload Pointer to data to copy/send * \param payload_len length of data to copy * \return Returns success/fail, refer to radio.h for explanation */ int rf233_send(const void *payload, unsigned short payload_len) { PRINTF("RF233: send %u\r\n", payload_len); if(rf233_prepare(payload, payload_len) == RADIO_TX_ERR) { return RADIO_TX_ERR; } return rf233_transmit(payload_len); } /*---------------------------------------------------------------------------*/ /** * \brief read a received frame out of the radio buffer * \param buf pointer to where to copy received data * \param bufsize Maximum size we can copy into bufsize * \return Returns length of data read (> 0) if successful * \retval -1 Failed, was transmitting so FIFO is invalid * \retval -2 Failed, rx timed out (stuck in rx?) * \retval -3 Failed, too large frame for buffer * \retval -4 Failed, CRC/FCS failed (if USE_HW_FCS_CHECK is true) */ int rf233_read(void *buf, unsigned short bufsize) { // uint8_t radio_state; uint8_t ed; /* frame metadata */ uint8_t frame_len = 0; uint8_t len = 0; int rssi; #if DEBUG_PRINTDATA uint8_t tempreadlen; #endif /* DEBUG_PRINTDATA */ if(pending_frame == 0) { return 0; } pending_frame = 0; /* / * check that data in FIFO is valid * / radio_state = RF233_STATUS(); if(radio_state == STATE_BUSY_TX) { / * data is invalid, bail out * / PRINTF("RF233: read while in BUSY_TX ie invalid, dropping.\n"); return -1; } if(radio_state == STATE_BUSY_RX) { / * still receiving - data is invalid, wait for it to finish * / PRINTF("RF233: read while BUSY_RX, waiting.\n"); BUSYWAIT_UNTIL(RF233_STATUS() != STATE_BUSY_RX, 10 * RTIMER_SECOND/1000); if(RF233_STATUS() == STATE_BUSY_RX) { PRINTF("RF233: timed out, still BUSY_RX, dropping.\n"); return -2; } } */ /* get length of data in FIFO */ trx_frame_read(&frame_len, 1); #if DEBUG_PRINTDATA tempreadlen = frame_len; #endif /* DEBUG_PRINTDATA */ if(frame_len == 1) { frame_len = 0; } len = frame_len; #if USE_HW_FCS_CHECK /* FCS has already been stripped */ len = frame_len - 2; #endif /* USE_HW_FCS_CHECK */ if(frame_len == 0) { return 0; } if(len > bufsize) { /* too large frame for the buffer, drop */ PRINTF("RF233: too large frame for buffer, dropping (%u > %u).\r\n", frame_len, bufsize); flush_buffer(); return -3; } PRINTF("RF233 read %u B\r\n", frame_len); /* read out the data into the buffer, disregarding the length and metadata bytes */ trx_sram_read(1,(uint8_t *)buf, len); #if DEBUG_PRINTDATA { int k; PRINTF("RF233: Read frame (%u/%u): ", tempreadlen, frame_len); for(k = 0; k < frame_len; k++) { PRINTF("%02x", *((uint8_t *)buf + k)); } PRINTF("\r\n"); } #endif /* DEBUG_PRINTDATA */ /* * Energy level during reception, ranges from 0x00 to 0x53 (=83d) with a * resolution of 1dB and accuracy of +/- 5dB. 0xFF means invalid measurement. * 0x00 means <= RSSI(base_val), which is -91dBm (typ). See datasheet 12.7. * Ergo, real RSSI is (ed-91) dBm or less. */ #define RSSI_OFFSET (91) ed = trx_reg_read(RF233_REG_PHY_ED_LEVEL); rssi = (int) ed - RSSI_OFFSET; packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi); flush_buffer(); /* #if USE_HW_FCS_CHECK { uint8_t crc_ok; / * frame metadata * / crc_ok = rf233_arch_read_reg(RF233_REG_PHY_RSSI) & PHY_RSSI_CRC_VALID; if(crc_ok == 0) { / * CRC/FCS fail, drop * / PRINTF("RF233: CRC/FCS fail, dropping.\n"); flush_buffer(); return -4; } } #endif / * USE_HW_FCS_CHECK * /*/ return len; }
/** * \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; /* Ensure control lines have correct levels. */ TRX_RST_HIGH(); TRX_SLP_TR_LOW(); /* Wait typical time of timer TR1. */ pal_timer_delay(P_ON_TO_CLKM_AVAILABLE_TYP_US); #if !(defined FPGA_EMULATION) do { /* Apply reset pulse */ TRX_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); TRX_RST_HIGH(); /* 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 AT86RF212 is connected; omit manufacturer id check **/ } while (trx_reg_read(RG_PART_NUM) != PART_NUM_AT86RF212); #endif /* !defined FPGA_EMULATION */ /* Ensure right CLKM value for external timer clock source, i.e. 1 MHz **/ trx_bit_write(SR_CLKM_CTRL, CLKM_1MHZ); /* Set trx to off mode */ trx_reg_write(RG_TRX_STATE, CMD_FORCE_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 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; return MAC_SUCCESS; }
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; } }
/* * \brief Sends frame * * \param use_csma Flag indicating if CSMA is requested * \param tx_retries Flag indicating if transmission retries are requested * by the MAC layer */ void send_frame(csma_mode_t csma_mode, bool tx_retries) { tal_trx_status_t trx_status; /* Configure tx according to tx_retries */ if (tx_retries) { trx_bit_write(SR_MAX_FRAME_RETRIES, tal_pib.MaxFrameRetries); } else { trx_bit_write(SR_MAX_FRAME_RETRIES, 0); } /* Configure tx according to csma usage */ if ((csma_mode == NO_CSMA_NO_IFS) || (csma_mode == NO_CSMA_WITH_IFS)) { if (tx_retries) { trx_bit_write(SR_MAX_CSMA_RETRIES, tal_pib.MaxCSMABackoffs); trx_reg_write(RG_CSMA_BE, 0x00); } else { trx_bit_write(SR_MAX_CSMA_RETRIES, 7); } } else { trx_reg_write(RG_CSMA_BE, ((tal_pib.MaxBE << 4) | tal_pib.MinBE)); trx_bit_write(SR_MAX_CSMA_RETRIES, tal_pib.MaxCSMABackoffs); } CONF_REG_WRITE(); do { trx_status = set_trx_state(CMD_TX_ARET_ON); } while (trx_status != TX_ARET_ON); /* Handle interframe spacing */ if (csma_mode == NO_CSMA_WITH_IFS) { if (last_frame_length > aMaxSIFSFrameSize) { pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US( macMinLIFSPeriod_def) - IRQ_PROCESSING_DLY_US - PRE_TX_DURATION_US); last_frame_length = 0; } else { pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US( macMinSIFSPeriod_def) - IRQ_PROCESSING_DLY_US - PRE_TX_DURATION_US); last_frame_length = 0; } } else { /* * If no delay is applied after switching to TX_ARET_ON, * a short delay is required that allows that a pending TX_END *IRQ for * ACK transmission gets served. */ pal_timer_delay(TRX_IRQ_DELAY_US); } ENTER_CRITICAL_REGION(); /* prevent from buffer underrun */ /* Toggle the SLP_TR pin triggering transmission. */ TRX_SLP_TR_HIGH(); PAL_WAIT_65_NS(); TRX_SLP_TR_LOW(); /* * Send the frame to the transceiver. * Note: The PhyHeader is the first byte of the frame to * be sent to the transceiver and this contains the frame * length. */ trx_frame_write(tal_frame_to_tx, tal_frame_to_tx[0] - 1); tal_state = TAL_TX_AUTO; LEAVE_CRITICAL_REGION(); }
/* * \brief Sets transceiver state * * \param trx_cmd needs to be one of the trx commands * * \return current trx state */ tal_trx_status_t set_trx_state(trx_cmd_t trx_cmd) { if (tal_trx_status == TRX_SLEEP) { /* * Since the wake-up procedure relies on the Awake IRQ and * the global interrupts may be disabled at this point of time, * we need to make sure that the global interrupts are enabled * during wake-up procedure. * Once the TRX is awake, the original state of the global *interrupts * will be restored. */ /* Reset wake-up interrupt flag. */ if (CMD_SLEEP == trx_cmd) { return TRX_SLEEP; } tal_awake_end_flag = false; /* Set callback function for the awake interrupt. */ pal_trx_irq_init_awake((FUNC_PTR)trx_awake_handler_cb); /* Save current state of global interrupts. */ ENTER_CRITICAL_REGION(); /* Force enabling of global interrupts. */ ENABLE_GLOBAL_IRQ(); /* Leave trx sleep mode. */ TRX_SLP_TR_LOW(); /* Poll wake-up interrupt flag until set within ISR. */ while (!tal_awake_end_flag) { } /* Restore original state of global interrupts. */ LEAVE_CRITICAL_REGION(); /* Clear existing interrupts */ trx_reg_write(RG_IRQ_STATUS, 0xFF); /* Re-enable TRX_END interrupt */ trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); #if (ANTENNA_DIVERSITY == 1) /* Enable antenna diversity. */ trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE); #endif if ((trx_cmd == CMD_TRX_OFF) || (trx_cmd == CMD_FORCE_TRX_OFF)) { tal_trx_status = TRX_OFF; return TRX_OFF; } } switch (trx_cmd) { /* requested state */ case CMD_SLEEP: trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); #if (ANTENNA_DIVERSITY == 1) /* Disable antenna diversity: sets pulls */ trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_DISABLE); #endif { uint16_t rand_value; /* * Init the SEED value of the CSMA backoff algorithm. */ rand_value = (uint16_t)rand(); trx_reg_write(RG_CSMA_SEED_0, (uint8_t)rand_value); trx_bit_write(SR_CSMA_SEED_1, (uint8_t)(rand_value >> 8)); } /* * Clear existing interrupts to have clear interrupt flags * during wake-up. */ trx_reg_write(RG_IRQ_STATUS, 0xFF); /* * Enable Awake_end interrupt. * This is used for save wake-up from sleep later. */ trx_reg_write(RG_IRQ_MASK, TRX_IRQ_AWAKE_ONLY); PAL_WAIT_1_US(); TRX_SLP_TR_HIGH(); pal_timer_delay(TRX_OFF_TO_SLEEP_TIME_CLKM_CYCLES); tal_trx_status = TRX_SLEEP; return TRX_SLEEP; /* transceiver register cannot be read during *TRX_SLEEP */ case CMD_TRX_OFF: switch (tal_trx_status) { case TRX_OFF: break; default: trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); PAL_WAIT_1_US(); break; } break; case CMD_FORCE_TRX_OFF: switch (tal_trx_status) { case TRX_OFF: break; default: trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); PAL_WAIT_1_US(); break; } break; case CMD_PLL_ON: switch (tal_trx_status) { case PLL_ON: break; case TRX_OFF: switch_pll_on(); break; case RX_ON: case RX_AACK_ON: case TX_ARET_ON: trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; case CMD_FORCE_PLL_ON: switch (tal_trx_status) { case TRX_OFF: switch_pll_on(); break; case PLL_ON: break; default: trx_reg_write(RG_TRX_STATE, CMD_FORCE_PLL_ON); break; } break; case CMD_RX_ON: switch (tal_trx_status) { case RX_ON: break; case PLL_ON: case RX_AACK_ON: case TX_ARET_ON: trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; case CMD_RX_AACK_ON: switch (tal_trx_status) { case RX_AACK_ON: break; case TX_ARET_ON: case PLL_ON: trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); /* state change from TRX_OFF to * RX_AACK_ON can be done directly, too */ trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case RX_ON: trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); PAL_WAIT_1_US(); /* check if state change could be applied */ tal_trx_status = (tal_trx_status_t)trx_bit_read( SR_TRX_STATUS); if (tal_trx_status != PLL_ON) { return tal_trx_status; } trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; case CMD_TX_ARET_ON: switch (tal_trx_status) { case TX_ARET_ON: break; case PLL_ON: trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case RX_ON: case RX_AACK_ON: trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); PAL_WAIT_1_US(); /* check if state change could be applied */ tal_trx_status = (tal_trx_status_t)trx_bit_read( SR_TRX_STATUS); if (tal_trx_status != PLL_ON) { return tal_trx_status; } trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); /* state change from TRX_OFF to * TX_ARET_ON can be done directly, too */ trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; default: /* CMD_NOP, CMD_TX_START */ Assert("trx command not handled" == 0); break; } do { tal_trx_status = (tal_trx_status_t)trx_bit_read(SR_TRX_STATUS); } while (tal_trx_status == STATE_TRANSITION_IN_PROGRESS); return tal_trx_status; } /* set_trx_state() */
/** * @brief Starts the timer for the backoff period and enables receiver. * * @param trx_id Transceiver identifier */ static void start_backoff(trx_id_t trx_id) { /* Start backoff timer to trigger CCA */ uint8_t backoff_8; backoff_8 = (uint8_t)(rand() & (((uint16_t)1 << BE[trx_id]) - 1)); if (backoff_8 > 0) { uint8_t timer_id; uint16_t backoff_16; uint32_t backoff_duration_us; backoff_16 = backoff_8 * aUnitBackoffPeriod; backoff_duration_us = (uint32_t)tal_pib[trx_id].SymbolDuration_us * (uint32_t)backoff_16; #ifdef REDUCED_BACKOFF_DURATION backoff_duration_us = REDUCED_BACKOFF_DURATION; #endif if (trx_id == RF09) { timer_id = TAL_T_0; } else { timer_id = TAL_T_1; } retval_t status = pal_timer_start(timer_id, backoff_duration_us, TIMEOUT_RELATIVE, (FUNC_PTR)cca_start, (void *)&timer_cb_parameter[trx_id]); if (status != MAC_SUCCESS) { tx_done_handling(trx_id, status); return; } tx_state[trx_id] = TX_BACKOFF; #ifdef RX_WHILE_BACKOFF /* Keep receiver on during backoff */ if ((trx_default_state[trx_id] == RF_RX) && (tal_pib[trx_id].NumRxFramesDuringBackoff < tal_pib[trx_id].MaxNumRxFramesDuringBackoff)) { if (trx_state[trx_id] != RF_RX) { if (trx_state[trx_id] == RF_TRXOFF) { switch_to_txprep(trx_id); } switch_to_rx(trx_id); } } else #endif { #ifdef USE_TXPREP_DURING_BACKOFF /* Switch to TXPREP during backoff */ if (trx_state[trx_id] != RF_TXPREP) { switch_to_txprep(trx_id); } #else /* Switch to TRXOFF during backoff */ if (trx_state[trx_id] != RF_TRXOFF) { uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; trx_reg_write(reg_offset + RG_RF09_CMD, RF_TRXOFF); trx_state[trx_id] = RF_TRXOFF; } #endif } } else { /* no backoff required */ /* Start CCA immediately - no backoff */ cca_start((void *)&timer_cb_parameter[trx_id]); } }