/** * @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; PAL_RST_HIGH(); PAL_SLP_TR_LOW(); /* Wait typical time of timer TR1. */ pal_timer_delay(P_ON_TO_CLKM_AVAILABLE_TYP_US); /* Apply reset pulse */ PAL_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); PAL_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 (pal_trx_reg_read(RG_PART_NUM) != PART_NUM_AT86RF233); #endif /* !defined FPGA_EMULATION */ /* Verify that TRX_OFF can be written */ pal_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)pal_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) pal_alert(); #endif return FAILURE; } poll_counter++; } while (trx_status != TRX_OFF); tal_trx_status = TRX_OFF; return MAC_SUCCESS; }
/** * \brief Handles software-controlled CSMA. * * \param csma_mode CSMA Mode; eg. ED or CS * \param retransmit true if frame re-transmission is requested */ static inline void sw_controlled_csma(csma_mode_t csma_mode, bool retransmit) { if (retransmit) { number_of_tx_retries = 0; /* actual number of retries */ } else { /* no further retries */ number_of_tx_retries = tal_pib.MaxFrameRetries; } /* 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); } else { pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US( macMinSIFSPeriod_def) - IRQ_PROCESSING_DLY_US - PRE_TX_DURATION_US); } } if ((csma_mode == NO_CSMA_WITH_IFS) || (csma_mode == NO_CSMA_NO_IFS)) { tx_frame(); } else { csma_start(); } }
/** * @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; #if (EXTERN_EEPROM_AVAILABLE == 1) uint8_t xtal_trim_value; #endif /* Get trim value for 16 MHz xtal; needs to be done before reset */ #if (EXTERN_EEPROM_AVAILABLE == 1) pal_ps_get(EXTERN_EEPROM, EE_XTAL_TRIM_ADDR, 1, &xtal_trim_value); #endif /* trx might sleep, so wake it up */ PAL_SLP_TR_LOW(); pal_timer_delay(SLEEP_TO_TRX_OFF_TYP_US); /* Apply reset pulse */ PAL_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); PAL_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)pal_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) pal_alert(); #endif return FAILURE; } poll_counter++; } while (trx_status != TRX_OFF); tal_trx_status = TRX_OFF; // Write 16MHz xtal trim value to trx. // It's only necessary if it differs from the reset value. #if (EXTERN_EEPROM_AVAILABLE == 1) if (xtal_trim_value != 0x00) { pal_trx_bit_write(SR_XTAL_TRIM, xtal_trim_value); } #endif return MAC_SUCCESS; }
/** * \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; PAL_RST_HIGH(); PAL_SLP_TR_LOW(); pal_timer_delay(P_ON_TO_CLKM_AVAILABLE); /* apply reset pulse */ PAL_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); PAL_RST_HIGH(); /* Verify that TRX_OFF can be written */ do { if (poll_counter == 0xFF) { return FAILURE; } /* Wait a short time interval. */ pal_timer_delay(TRX_POLL_WAIT_TIME_US); poll_counter++; /* Check if AT86RF230 is connected; omit manufacturer id check **/ } while ((pal_trx_reg_read(RG_VERSION_NUM) != AT86RF230_REV_B) || (pal_trx_reg_read(RG_PART_NUM) != AT86RF230)); pal_trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); /* verify that trx has reached TRX_OFF */ poll_counter = 0; do { trx_status = (tal_trx_status_t)pal_trx_bit_read(SR_TRX_STATUS); if (poll_counter == 0xFF) { #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 Reset transceiver */ static retval_t trx_reset(void) { tal_trx_status_t trx_status; uint8_t poll_counter = 0; #if (EXTERN_EEPROM_AVAILABLE == 1) uint8_t xtal_trim_value; #endif /* Get trim value for 16 MHz xtal; needs to be done before reset */ #if (EXTERN_EEPROM_AVAILABLE == 1) pal_ps_get(EXTERN_EEPROM, EE_XTAL_TRIM_ADDR, 1, &xtal_trim_value); #endif /* trx might sleep, so wake it up */ PAL_SLP_TR_LOW(); pal_timer_delay(SLEEP_TO_TRX_OFF_US); PAL_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); PAL_RST_HIGH(); /* verify that trx has reached TRX_OFF */ do { trx_status = (tal_trx_status_t)pal_trx_bit_read(SR_TRX_STATUS); poll_counter++; if (poll_counter > 250) { #if (_DEBUG_ > 0) Assert( "MAX Attempts to switch to TRX_OFF state reached" == 0); #endif return FAILURE; } } while (trx_status != TRX_OFF); tal_trx_status = TRX_OFF; /* Write 16MHz xtal trim value to trx. */ /* It's only necessary if it differs from the reset value. */ #if (EXTERN_EEPROM_AVAILABLE == 1) if (xtal_trim_value != 0x00) { pal_trx_bit_write(SR_XTAL_TRIM, xtal_trim_value); } #endif return MAC_SUCCESS; }
/** * @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. */ PAL_RST_HIGH(); PAL_SLP_TR_LOW(); pal_timer_delay(P_ON_TO_CLKM_AVAILABLE_TYP_US); /* Apply reset pulse */ PAL_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); PAL_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)pal_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) pal_alert(); #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 != pal_trx_reg_read(RG_PART_NUM)) { return FAILURE; } #endif return MAC_SUCCESS; }
/** * \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); PAL_RST_HIGH(); PAL_SLP_TR_LOW(); pal_timer_delay(P_ON_TO_CLKM_AVAILABLE_TYP_US); /* Apply reset pulse */ PAL_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); PAL_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)pal_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 != pal_trx_reg_read(RG_PART_NUM)) { return FAILURE; } #endif return MAC_SUCCESS; }
/** * \brief Switches the PLL on * \ingroup group_tal_state_machine_231 */ 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 (pal_trx_bit_read(SR_TRX_STATUS) != TRX_OFF) { Assert( "Switch PLL_ON failed, because trx is not in TRX_OFF" == 0); return; } pal_trx_reg_read(RG_IRQ_STATUS); /* clear PLL lock bit */ /* Switch PLL on */ pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); /* Check if PLL has been locked. */ do { irq_status = (trx_irq_reason_t)pal_trx_reg_read(RG_IRQ_STATUS); if (irq_status & TRX_IRQ_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 Triggers CCA measurement at transceiver * * @param trx_id Transceiver identifier */ static void trigger_cca_meaurement(trx_id_t trx_id) { /* Trigger CCA measurement */ uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; /* Cancel any ongoing reception and ensure that TXPREP is reached. */ if (trx_state[trx_id] == RF_TRXOFF) { switch_to_txprep(trx_id); } /* Disable BB */ trx_bit_write(reg_offset + SR_BBC0_PC_BBEN, 0); /* Enable IRQ EDC */ trx_bit_write(reg_offset + SR_RF09_IRQM_EDC, 1); /* CCA duration is already set by default; see apply_phy_settings() */ /* Setup and start energy detection */ trx_bit_write(reg_offset + SR_RF09_AGCC_FRZC, 0); /* Ensure AGC is not * hold */ if (trx_state[trx_id] != RF_RX) { trx_reg_write(reg_offset + RG_RF09_CMD, RF_RX); pal_timer_delay(tal_pib[trx_id].agc_settle_dur); /* allow * filters to * settle */ trx_state[trx_id] = RF_RX; } tx_state[trx_id] = TX_CCA; /* Start single ED measurement; use reg_write - it's the only *subregister */ trx_reg_write(reg_offset + RG_RF09_EDC, RF_EDSINGLE); /* Wait for EDC IRQ and handle it within cca_done_handling() */ }
/* * \brief Perform a single ED measurement * * \return ed_value Result of the measurement * If the build switch TRX_REG_RAW_VALUE is defined, the transceiver's * register value is returned. */ uint8_t tfa_ed_sample(void) { uint8_t ed_value; tal_trx_status_t trx_status; /* Make sure that receiver is switched on. */ do { trx_status = set_trx_state(CMD_RX_ON); } while (trx_status != RX_ON); /* * Disable the transceiver interrupts to prevent frame reception * while performing ED scan. */ pal_trx_irq_dis(); /* * Initiate ED operation by writing any value into transceiver register * PHY_ED_LEVEL. */ pal_trx_reg_write(RG_PHY_ED_LEVEL, 0x00); /* * Start timer for reading ED value from the transceiver after * 140 microseconds. */ pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US(ED_SAMPLE_DURATION_SYM + 1)); /* Read the ED Value. */ ed_value = pal_trx_reg_read(RG_PHY_ED_LEVEL); /* Clear IRQ register */ pal_trx_reg_read(RG_IRQ_STATUS); /* Enable reception agian */ pal_trx_irq_flag_clr(); pal_trx_irq_en(); /* Switch receiver off again */ set_trx_state(CMD_TRX_OFF); #ifndef TRX_REG_RAW_VALUE /* * Scale ED result. * Clip values to 0xFF if > -35dBm */ if (ed_value > CLIP_VALUE_REG) { ed_value = 0xFF; } else { ed_value = (uint8_t)(((uint16_t)ed_value * 0xFF) / CLIP_VALUE_REG); } #endif return ed_value; }
/** * \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 */ PAL_SLP_TR_LOW(); pal_timer_delay(SLEEP_TO_TRX_OFF_TYP_US); /* Apply reset pulse */ PAL_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); PAL_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)pal_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 Perform a single ED measurement * * @return ed_value Result of the measurement * If the build switch TRX_REG_RAW_VALUE is defined, the transceiver's * register value is returned. */ uint8_t tfa_ed_sample(void) { trx_irq_reason_t trx_irq_cause; uint8_t ed_value; tal_trx_status_t trx_status; /* Make sure that receiver is switched on. */ do { trx_status = set_trx_state(CMD_RX_ON); } while (trx_status != RX_ON); /* * Disable the transceiver interrupts to prevent frame reception * while performing ED scan. */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_DISABLE); /* Write dummy value to start measurement. */ pal_trx_reg_write(RG_PHY_ED_LEVEL, 0xFF); /* Wait for ED measurement completion. */ pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US(ED_SAMPLE_DURATION_SYM)); do { trx_irq_cause = (trx_irq_reason_t)pal_trx_reg_read(RG_IRQ_STATUS); } while ((trx_irq_cause & TRX_IRQ_CCA_ED_READY) != TRX_IRQ_CCA_ED_READY); /* Read the ED Value. */ ed_value = pal_trx_reg_read(RG_PHY_ED_LEVEL); #ifndef TRX_REG_RAW_VALUE /* * Scale ED result. * Clip values to 0xFF if > -35dBm */ if (ed_value > CLIP_VALUE_REG) { ed_value = 0xFF; } else { ed_value = (uint8_t)(((uint16_t)ed_value * 0xFF) / CLIP_VALUE_REG); } #endif /* Clear IRQ register */ pal_trx_reg_read(RG_IRQ_STATUS); /* Enable reception agian */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* Switch receiver off again */ set_trx_state(CMD_TRX_OFF); return ed_value; }
/** * @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 */ pal_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 */ pal_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 = pal_trx_bit_read(SR_CCA_DONE); } while (cca_done != CCA_COMPLETED); set_trx_state(CMD_TRX_OFF); /* Check if channel was idle or busy. */ if (pal_trx_bit_read(SR_CCA_STATUS) == CCA_CH_IDLE) { cca_status = PHY_IDLE; } else { cca_status = PHY_BUSY; } /* Enable frame reception again. */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); return (phy_enum_t)cca_status; }
/** * @brief This function waits until the adc common mode is settled * * After the ADC clock has been turned on, the common mode voltage in the ADC * need some time to settle. The time it takes equals one dummy conversion. * Instead of doing a dummy conversion this function waits until the common * mode is settled. * * @param adc Pointer to ADC module register section */ void adc_wait_8mhz(ADC_t * adc) { /* Store old prescaler value. */ uint8_t prescaler_val = adc->PRESCALER; /* Set prescaler value to minimum value. */ adc->PRESCALER = ADC_PRESCALER_DIV4_gc; /* Wait 4 * COMMON_MODE_CYCLES for common mode to settle. */ pal_timer_delay(4 * COMMON_MODE_CYCLES); /* Set prescaler to old value*/ adc->PRESCALER = prescaler_val; }
/* * @brief Alert indication * * This Function can be used by any application to indicate an error condition. * The function is blocking and does never return. */ void pal_alert(void) { #if (DEBUG > 0) bool debug_flag = false; #endif ALERT_INIT(); while (1) { pal_timer_delay(0xFFFF); ALERT_INDICATE(); #if (DEBUG > 0) /* Used for debugging purposes only */ if (debug_flag == true) { break; } #endif } }
/** * @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. */ tal_awake_end_flag = false; /* Set callback function for the awake interrupt. */ pal_trx_irq_init(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. */ PAL_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 */ pal_trx_reg_read(RG_IRQ_STATUS); /* Re-install default IRQ handler for main interrupt. */ pal_trx_irq_init(trx_irq_handler_cb); /* Re-enable TRX_END interrupt */ pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); #if (ANTENNA_DIVERSITY == 1) /* Enable antenna diversity. */ pal_trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE); #endif #ifdef EXT_RF_FRONT_END_CTRL /* Enable RF front end control */ pal_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) { /* Leave trx sleep mode. */ PAL_SLP_TR_LOW(); /* Check if trx has left deep sleep. */ tal_trx_status_t trx_state; do { trx_state = (tal_trx_status_t)pal_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 pal_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. */ pal_trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_DISABLE); #endif #ifdef EXT_RF_FRONT_END_CTRL /* Disable RF front end control */ pal_trx_bit_write(SR_PA_EXT_EN, 0); #endif /* Clear existing interrupts */ pal_trx_reg_read(RG_IRQ_STATUS); /* * Enable Awake_end interrupt. * This is used for save wake-up from sleep later. */ pal_trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); #ifdef ENABLE_DEEP_SLEEP if (trx_cmd == CMD_DEEP_SLEEP) { pal_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. */ pal_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. */ pal_trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); tal_trx_status = TRX_SLEEP; #endif PAL_WAIT_1_US(); PAL_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: pal_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: pal_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: pal_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: pal_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: pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); pal_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: pal_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 pal_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: pal_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 pal_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)pal_trx_bit_read(SR_TRX_STATUS); } while (tal_trx_status == STATE_TRANSITION_IN_PROGRESS); return tal_trx_status; } /* set_trx_state() */
/** * @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 Handle received frame interrupt * * This function handles transceiver interrupts for received frames and * uploads the frames from the trx. */ void handle_received_frame_irq(void) { uint8_t ed_value; /* Actual frame length of received frame. */ uint8_t phy_frame_len; /* Extended frame length appended by LQI and ED. */ uint8_t ext_frame_length; frame_info_t *receive_frame; uint8_t *frame_ptr; if (tal_rx_buffer == NULL) { Assert("no tal_rx_buffer available" == 0); /* * Although the buffer protection mode is enabled and the receiver has * been switched to PLL_ON, the next incoming frame was faster. * It cannot be handled and is discarded. */ pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_DISABLE); /* Disable buffer protection mode */ pal_timer_delay(2); // Allow pin change to get effective pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_ENABLE); /* Enable buffer protection mode */ return; } receive_frame = (frame_info_t *)BMM_BUFFER_POINTER(tal_rx_buffer); #ifdef PROMISCUOUS_MODE if (tal_pib.PromiscuousMode) { /* Check for valid FCS */ if (pal_trx_bit_read(SR_RX_CRC_VALID) == CRC16_NOT_VALID) { return; } } #endif /* Get ED value; needed to normalize LQI. */ ed_value = pal_trx_reg_read(RG_PHY_ED_LEVEL); /* Get frame length from transceiver. */ phy_frame_len = ext_frame_length = pal_trx_reg_read(RG_TST_RX_LENGTH); /* Check for valid frame length. */ if (phy_frame_len > 127) { return; } /* * The PHY header is also included in the frame (length field), hence the frame length * is incremented. * In addition to that, the LQI and ED value are uploaded, too. */ ext_frame_length += LQI_LEN + ED_VAL_LEN; /* Update payload pointer to store received frame. */ frame_ptr = (uint8_t *)receive_frame + LARGE_BUFFER_SIZE - ext_frame_length; /* * Note: The following code is different from other non-single chip * transceivers, where reading the frame via SPI contains the length field * in the first octet. */ pal_trx_frame_read(frame_ptr, phy_frame_len + LQI_LEN); frame_ptr--; *frame_ptr = phy_frame_len; receive_frame->mpdu = frame_ptr; /* Add ED value at the end of the frame buffer. */ receive_frame->mpdu[phy_frame_len + LQI_LEN + ED_VAL_LEN] = ed_value; #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) /* * Store the timestamp. * The timestamping is only required for beaconing networks * or if timestamping is explicitly enabled. */ receive_frame->time_stamp = tal_rx_timestamp; #endif /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */ /* Append received frame to incoming_frame_queue and get new rx buffer. */ qmm_queue_append(&tal_incoming_frame_queue, tal_rx_buffer); /* The previous buffer is eaten up and a new buffer is not assigned yet. */ tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE); /* Check if receive buffer is available */ if (NULL == tal_rx_buffer) { /* * Turn off the receiver until a buffer is available again. * tal_task() will take care of eventually reactivating it. * Due to ongoing ACK transmission do not force to switch it off. */ /* Do not change the state since buffer protection mode is not re-enabled yet. * Buffer protection will be re-enabled after buffer becomes available */ //set_trx_state(CMD_PLL_ON); tal_rx_on_required = true; } else { /* * Trx returns to RX_AACK_ON automatically, if this was its previous state. * Keep the following as a reminder, if receiver is used with RX_ON instead. */ //pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); /* * Release the protected buffer and set it again for further protection since * the buffer is available */ pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_DISABLE); /* Disable buffer protection mode */ pal_timer_delay(2); // Allow pin change to get effective pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_ENABLE); /* Enable buffer protection mode */ } /* * Clear pending TX_END IRQ: The TX_END IRQ is envoked for the transmission * end of an automatically sent ACK frame. This implementation does not use * this feature. */ pal_trx_irq_flag_clr_tx_end(); }
/* * \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); } 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. * The actual length of the frame to be downloaded * (parameter two of trx_frame_write) * is * 1 octet frame length octet * + n octets frame (i.e. value of frame_tx[0]) * - 2 octets FCS */ trx_frame_write(tal_frame_to_tx, tal_frame_to_tx[0] - 1); tal_state = TAL_TX_AUTO; LEAVE_CRITICAL_REGION(); }
/** * \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) { volatile tal_trx_status_t test_status; uint8_t poll_counter = 0; /* Wait typical time of timer TR1. */ pal_timer_delay(P_ON_TO_CLKM_AVAILABLE_TYP_US); /* make sure SPI is working properly */ /* while ((tal_trx_status_t)trx_bit_read(SR_TRX_STATUS) != P_ON); */ /* Apply reset pulse. Ensure control lines have correct levels (SEL is * already set in TRX_INIT(). */ TRX_RST_LOW(); TRX_SLP_TR_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); TRX_RST_HIGH(); /* Wait typical time of timer TR13. */ pal_timer_delay(30); test_status = (tal_trx_status_t)trx_bit_read(SR_TRX_STATUS); /* Dummy assignment, to avoid compiler warning */ test_status = test_status; #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 AT86RF212B is connected; omit manufacturer id check **/ } while (trx_reg_read(RG_PART_NUM) != PART_NUM_AT86RF212B); #endif /* !defined FPGA_EMULATION */ /* Set trx to off mode */ trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); /* \todo remove this line?! */ while ((tal_trx_status_t)trx_bit_read(SR_TRX_STATUS) != TRX_OFF) { } #if (_DEBUG_ > 0) tal_trx_status_t trx_status; trx_status = (tal_trx_status_t)trx_bit_read(SR_TRX_STATUS); if (trx_status != TRX_OFF) { return FAILURE; } #endif trx_reg_write(RG_IRQ_MASK, TRX_NO_IRQ); tal_trx_status = TRX_OFF; return MAC_SUCCESS; }
/* * \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 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_US + CCA_PREPARATION_DURATION_US)) < cca_starttime_us); #ifndef RFD if (tal_beacon_transmission) { #if (DEBUG > 0) ASSERT("Ongoing beacon transmission, slotted CSMA busy" == 0); #endif return PHY_BUSY; } #endif // 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, (PLL_LOCK_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 pal_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); pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON); // debug pin to switch on: define ENABLE_DEBUG_PINS, pal_config.h PIN_CCA_START(); /* Start CCA */ pal_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 = pal_trx_bit_read(SR_CCA_DONE); } while (cca_done != CCA_DETECTION_DONE); // between both CCA switch trx to PLL_ON to reduce power consumption pal_trx_reg_write(RG_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 (pal_trx_bit_read(SR_CCA_STATUS) == CCA_STATUS_CHANNEL_IS_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; 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) pal_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. */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); // enable frame reception indication return cca_status; }
/* * \brief TAL task handling * * This function * - Checks and allocates the receive buffer. * - Processes the TAL incoming frame queue. * - Implements the TAL state machine. */ void tal_task(void) { /* Check if the receiver needs to be switched on. */ if (tal_rx_on_required && (tal_state == TAL_IDLE)) { /* Check if a receive buffer has not been available before. */ if (tal_rx_buffer == NULL) { tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE); } /* Check if buffer could be allocated */ if (NULL != tal_rx_buffer) { /* * Note: * This flag needs to be reset BEFORE the received is *switched on. */ tal_rx_on_required = false; /* * Release the protected buffer and set it again for *further protection * since the buffer is available now. */ trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_DISABLE); /* *Disable *buffer *protection *mode **/ pal_timer_delay(2); /* Allow pin change to get effective */ trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_ENABLE); /* *Enable *buffer *protection *mode **/ CONF_REG_WRITE(); #ifdef PROMISCUOUS_MODE if (tal_pib.PromiscuousMode) { set_trx_state(CMD_RX_ON); } else { set_trx_state(CMD_RX_AACK_ON); } #else /* Normal operation */ set_trx_state(CMD_RX_AACK_ON); #endif } } else { /* no free buffer is available; try next time again */ } /* * If the transceiver has received a frame and it has been placed * into the queue of the TAL, the frame needs to be processed further. */ if (tal_incoming_frame_queue.size > 0) { buffer_t *rx_frame; /* Check if there are any pending data in the *incoming_frame_queue. */ rx_frame = qmm_queue_remove(&tal_incoming_frame_queue, NULL); if (NULL != rx_frame) { process_incoming_frame(rx_frame); } } /* Handle the TAL state machines */ switch (tal_state) { case TAL_IDLE: /* Do nothing, but fall through... */ case TAL_TX_AUTO: /* Wait until state is changed to TAL_TX_DONE inside tx end ISR **/ break; case TAL_TX_DONE: tx_done_handling(); /* see tal_tx.c */ break; #ifdef BEACON_SUPPORT case TAL_SLOTTED_CSMA: slotted_csma_state_handling(); /* see tal_slotted_csma.c */ break; #endif /* BEACON_SUPPORT */ #if (MAC_SCAN_ED_REQUEST_CONFIRM == 1) case TAL_ED_RUNNING: /* Do nothing here. Wait until ED is completed. */ break; case TAL_ED_DONE: ed_scan_done(); break; #endif /* (MAC_SCAN_ED_REQUEST_CONFIRM == 1) */ default: Assert("tal_state is not handled" == 0); break; } } /* tal_task() */
/* * \brief Sends frame using trx features to handle CSMA and re-transmissions * * \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)) { trx_bit_write(SR_MAX_CSMA_RETRIES, 7); /* immediate * transmission */ } else { trx_bit_write(SR_MAX_CSMA_RETRIES, tal_pib.MaxCSMABackoffs); } do { trx_status = set_trx_state(CMD_TX_ARET_ON); } while (trx_status != TX_ARET_ON); pal_trx_irq_dis(); /* 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; } } /* 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. * The actual length of the frame to be downloaded * (parameter two of trx_frame_write) * is * 1 octet frame length octet * + n octets frame (i.e. value of frame_tx[0]) * - 2 octets FCS */ trx_frame_write(tal_frame_to_tx, tal_frame_to_tx[0] - 1); tal_state = TAL_TX_AUTO; #ifndef NON_BLOCKING_SPI pal_trx_irq_en(); #endif #ifdef TX_OCTET_COUNTER tal_tx_octet_cnt += PHY_OVERHEAD + LENGTH_FIELD_LEN + frame_tx[0]; #endif }
/** * @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) { uint8_t bit_status; PAL_SLP_TR_LOW(); do { bit_status = pal_trx_bit_read(SR_TRX_STATUS); } while (bit_status != TRX_OFF); if ((trx_cmd == CMD_TRX_OFF) || (trx_cmd == CMD_FORCE_TRX_OFF)) { tal_trx_status = TRX_OFF; return TRX_OFF; } } tal_trx_status = (tal_trx_status_t)pal_trx_bit_read(SR_TRX_STATUS); switch (trx_cmd) /* new state */ { case CMD_TRX_SLEEP: pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); { uint16_t rand_value; /* * Init the SEED value of the CSMA backoff algorithm. */ rand_value = (uint16_t)rand(); pal_trx_reg_write(RG_CSMA_SEED_0, (uint8_t)rand_value); pal_trx_bit_write(SR_CSMA_SEED_1, (uint8_t)(rand_value >> 8)); } PAL_WAIT_1_US(); PAL_SLP_TR_HIGH(); pal_timer_delay(TRX_OFF_TO_SLEEP_TIME); tal_trx_status = TRX_SLEEP; return TRX_SLEEP; /* transceiver register cannot be read during TRX_SLEEP */ //break; // do not use break, since it is unreachable case CMD_TRX_OFF: switch (tal_trx_status) { case TRX_OFF: break; default: pal_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; case TX_ARET_ON: pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); PAL_SLP_TR_HIGH(); pal_timer_delay(2); PAL_SLP_TR_LOW(); break; default: pal_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: pal_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: /* software state */ switch (tal_trx_status) { case RX_ON: case BUSY_RX: case RX_AACK_ON: case BUSY_RX_AACK: ENTER_TRX_REGION(); pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); // clear trx irq in case a frame is received meanwhile pal_trx_reg_read(RG_IRQ_STATUS); pal_trx_irq_flag_clr(); LEAVE_TRX_REGION(); PAL_WAIT_1_US(); break; case BUSY_TX: ENTER_TRX_REGION(); pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); LEAVE_TRX_REGION(); PAL_WAIT_1_US(); break; case BUSY_TX_ARET: ENTER_TRX_REGION(); pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); PAL_SLP_TR_LOW(); pal_timer_delay(SLP_TR_TOGGLE_US); PAL_SLP_TR_HIGH(); pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); LEAVE_TRX_REGION(); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); break; case PLL_ON: break; default: ASSERT("state transition not handled" == 0); break; } break; case CMD_RX_ON: switch (tal_trx_status) { case RX_ON: break; case PLL_ON: pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case RX_AACK_ON: case TX_ARET_ON: pal_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)pal_trx_bit_read(SR_TRX_STATUS); if (tal_trx_status != PLL_ON) { return tal_trx_status; } pal_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 PLL_ON: pal_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 pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case TX_ARET_ON: case RX_ON: pal_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)pal_trx_bit_read(SR_TRX_STATUS); if (tal_trx_status != PLL_ON) { return tal_trx_status; } pal_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: pal_trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case RX_ON: case RX_AACK_ON: pal_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)pal_trx_bit_read(SR_TRX_STATUS); if (tal_trx_status != PLL_ON) { return tal_trx_status; } pal_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 pal_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)pal_trx_bit_read(SR_TRX_STATUS); } while (tal_trx_status == STATE_TRANSITION_IN_PROGRESS); return tal_trx_status; } /* set_trx_state() */
/** * \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; }
/** * @brief Filter tuning calibration implementation */ static void do_ftn_calibration(void) { pal_trx_bit_write(SR_FTN_START, 1); /* Wait tTR16 (FTN calibration time). */ pal_timer_delay(25); }
/* * \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. */ pal_trx_irq_dis(); /* 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); /* * Enable all trx interrupts. * This needs to be done BEFORE putting the transceiver back to slee. */ pal_trx_irq_en(); if (previous_trx_status == TRX_SLEEP) { set_trx_state(CMD_SLEEP); } return mv; }
/** * \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 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; #ifdef BEACON_SUPPORT /* Handle frame transmission in slotted CSMA via basic mode */ if (tal_csma_state != CSMA_IDLE) { do { trx_status = set_trx_state(CMD_PLL_ON); } while (trx_status != PLL_ON); tal_state = TAL_TX_BASIC; } else #endif { /* Configure tx according to tx_retries */ if (tx_retries) { pal_trx_bit_write(SR_MAX_FRAME_RETRIES, tal_pib.MaxFrameRetries); } else { pal_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)) { /* * RF230B does not support "no" CSMA mode, * therefore use shortest CSMA mode: CCA w/o backoff */ pal_trx_bit_write(SR_MIN_BE, 0x00); pal_trx_bit_write(SR_MAX_CSMA_RETRIES, 0); } else { pal_trx_bit_write(SR_MIN_BE, tal_pib.MinBE); pal_trx_bit_write(SR_MAX_CSMA_RETRIES, tal_pib.MaxCSMABackoffs); /* * Handle interframe spacing * Reduce IFS duration, since RF230B does CCA */ if (csma_mode == NO_CSMA_WITH_IFS) { if (last_frame_length > aMaxSIFSFrameSize) { pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US( macMinLIFSPeriod_def - CCA_DURATION_SYM) - IRQ_PROCESSING_DLY_US - PRE_TX_DURATION_US); } else { /* * No delay required, since processing *delay and CCA_DURATION_SYM * delay the handling enough. */ } } } do { trx_status = set_trx_state(CMD_TX_ARET_ON); } while (trx_status != TX_ARET_ON); tal_state = TAL_TX_AUTO; } pal_trx_irq_dis(); /* Toggle the SLP_TR pin triggering transmission. */ PAL_SLP_TR_HIGH(); PAL_WAIT_65_NS(); PAL_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. * The actual length of the frame to be downloaded * (parameter two of pal_trx_frame_write) * is * 1 octet frame length octet * + n octets frame (i.e. value of frame_tx[0]) * - 2 octets FCS */ pal_trx_frame_write(tal_frame_to_tx, tal_frame_to_tx[0] - 1); #ifndef NON_BLOCKING_SPI pal_trx_irq_en(); #endif }