void tal_tx_beacon(frame_info_t *tx_frame) { tal_trx_status_t trx_status; /* Set pointer to actual mpdu to be downloaded to the transceiver. */ uint8_t *tal_beacon_to_tx = tx_frame->mpdu; /* Avoid that the beacon is transmitted while other transmision is * on-going. */ if (tal_state == TAL_TX_AUTO) { Assert( "trying to transmit beacon while ongoing transmission" == 0); return; } /* Send the pre-created beacon frame to the transceiver. */ do { trx_status = set_trx_state(CMD_PLL_ON); #if (_DEBUG_ > 1) if (trx_status != PLL_ON) { Assert("PLL_ON failed for beacon transmission" == 0); } #endif } while (trx_status != PLL_ON); /* \TODO wait for talbeaconTxTime */ pal_trx_irq_dis(); /* 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]) * + 1 extra octet (see datasheet) * - 2 octets FCS */ trx_frame_write(tal_beacon_to_tx, tal_beacon_to_tx[0]); tal_beacon_transmission = true; #ifndef NON_BLOCKING_SPI pal_trx_irq_en(); #endif #ifdef TX_OCTET_COUNTER tal_tx_octet_cnt += PHY_OVERHEAD + LENGTH_FIELD_LEN + tal_beacon_to_tx[0]; #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; TRX_RST_HIGH(); TRX_SLP_TR_LOW(); /* Wait typical time of timer TR1. */ pal_timer_delay(P_ON_TO_CLKM_AVAILABLE_TYP_US); /* Apply reset pulse */ TRX_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); TRX_RST_HIGH(); #if !(defined FPGA_EMULATION) do { /* Wait not more than max. value of TR1. */ if (poll_counter == P_ON_TO_CLKM_ATTEMPTS) { return FAILURE; } /* Wait a short time interval. */ pal_timer_delay(TRX_POLL_WAIT_TIME_US); poll_counter++; /* Check if AT86RF233 is connected; omit manufacturer id check **/ } while (trx_reg_read(RG_PART_NUM) != PART_NUM_AT86RF233); #endif /* !defined FPGA_EMULATION */ /* Verify that TRX_OFF can be written */ trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); /* Verify that the trx has reached TRX_OFF. */ poll_counter = 0; do { /* Wait a short time interval. */ pal_timer_delay(TRX_POLL_WAIT_TIME_US); trx_status = /*(tal_trx_status_t)*/ trx_bit_read(SR_TRX_STATUS); /* Wait not more than max. value of TR15. */ if (poll_counter == P_ON_TO_TRX_OFF_ATTEMPTS) { #if (_DEBUG_ > 0) Assert( "MAX Attempts to switch to TRX_OFF state reached" == 0); #endif return FAILURE; } poll_counter++; } while (trx_status != TRX_OFF); tal_trx_status = TRX_OFF; return MAC_SUCCESS; }
void tal_tx_beacon(frame_info_t *tx_frame) { tal_trx_status_t trx_status; /* Set pointer to actual mpdu to be downloaded to the transceiver. */ uint8_t *tal_beacon_to_tx = tx_frame->mpdu; /* Avoid that the beacon is transmitted while other transmision is *on-going. */ if (tal_state == TAL_TX_AUTO) { Assert( "trying to transmit beacon while ongoing transmission" == 0); return; } /* Send the pre-created beacon frame to the transceiver. */ do { trx_status = set_trx_state(CMD_PLL_ON); #if (_DEBUG_ > 1) if (trx_status != PLL_ON) { Assert("PLL_ON failed for beacon transmission" == 0); } #endif } while (trx_status != PLL_ON); /* \TODO wait for talbeaconTxTime */ 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_beacon_to_tx, tal_beacon_to_tx[0] - 1); tal_beacon_transmission = true; 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) { tal_trx_status_t trx_status; uint8_t poll_counter = 0; sysclk_enable_peripheral_clock(&TRX_CTRL_0); TRX_RST_HIGH(); TRX_SLP_TR_LOW(); pal_timer_delay(P_ON_TO_CLKM_AVAILABLE_TYP_US); /* Apply reset pulse */ TRX_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); TRX_RST_HIGH(); /* Verify that the trx has reached TRX_OFF. */ poll_counter = 0; do { /* Wait a short time interval. */ pal_timer_delay(TRX_POLL_WAIT_TIME_US); trx_status = (tal_trx_status_t)trx_bit_read(SR_TRX_STATUS); /* Wait not more than max. value of TR2. */ if (poll_counter == RESET_TO_TRX_OFF_ATTEMPTS) { #if (_DEBUG_ > 0) Assert( "MAX Attempts to switch to TRX_OFF state reached" == 0); #endif return FAILURE; } poll_counter++; } while (trx_status != TRX_OFF); tal_trx_status = TRX_OFF; #if !defined(FPGA_EMULATION) /* Check if actually running on an ATmegaRFR2 device. */ if (ATMEGARFR2_PART_NUM != trx_reg_read(RG_PART_NUM)) { return FAILURE; } #endif return MAC_SUCCESS; }
/** * \brief Transmits the frame over-the-air */ static void tx_frame(void) { tal_trx_status_t trx_status; /* * Trigger transmission * In case of an ongoing reception, * the incoming frame is handled first within ISR. */ do { trx_status = set_trx_state(CMD_TX_ARET_ON); } while (trx_status != TX_ARET_ON); pal_trx_irq_dis(); /* 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]) * + 1 extra octet (see datasheet) * - 2 octets FCS */ trx_frame_write(tal_frame_to_tx, tal_frame_to_tx[0]); 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 + tal_frame_to_tx[0]; #endif }
/** * \brief Reset transceiver * * \return MAC_SUCCESS if the transceiver state is changed to TRX_OFF * FAILURE otherwise */ static retval_t trx_reset(void) { tal_trx_status_t trx_status; uint8_t poll_counter = 0; /* trx might sleep, so wake it up */ TRX_SLP_TR_LOW(); pal_timer_delay(SLEEP_TO_TRX_OFF_TYP_US); /* Apply reset pulse */ TRX_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); TRX_RST_HIGH(); /* verify that trx has reached TRX_OFF */ do { /* Wait a short time interval. */ pal_timer_delay(TRX_POLL_WAIT_TIME_US); trx_status = (tal_trx_status_t)trx_bit_read(SR_TRX_STATUS); /* Wait not more than max. value of TR2. */ if (poll_counter == SLEEP_TO_TRX_OFF_ATTEMPTS) { #if (_DEBUG_ > 0) Assert( "MAX Attempts to switch to TRX_OFF state reached" == 0); #endif return FAILURE; } poll_counter++; } while (trx_status != TRX_OFF); tal_trx_status = TRX_OFF; #ifdef STB_ON_SAL #if (SAL_TYPE == AT86RF2xx) stb_restart(); #endif #endif return MAC_SUCCESS; }
/* * \brief Starts continuous transmission on current channel * * \param tx_mode Mode of continuous transmission (CW or PRBS) * \param random_content Use random content if true */ void tfa_continuous_tx_start(continuous_tx_mode_t tx_mode, bool random_content) { uint8_t txcwdata[128]; trx_bit_write(SR_TX_AUTO_CRC_ON, TX_AUTO_CRC_DISABLE); trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); trx_reg_write(0x36, 0x0F); /*TST_CTRL_DIGI*/ /* Here: use 2MBPS mode for PSD measurements. * Omit the two following lines, if 250k mode is desired for PRBS mode. **/ trx_reg_write(RG_TRX_CTRL_2, 0x03); trx_reg_write(RG_RX_CTRL, 0xA7); if (tx_mode == CW_MODE) { txcwdata[0] = 1; /* length */ /* Step 12 - frame buffer write access */ txcwdata[1] = 0x00; /* f=fch-0.5 MHz; set value to 0xFF for * f=fch+0.5MHz */ trx_frame_write(txcwdata, 2); } else { /* PRBS mode */ txcwdata[0] = 127; /* = max length */ for (uint8_t i = 1; i < 128; i++) { if (random_content) { txcwdata[i] = (uint8_t)rand(); } else { txcwdata[i] = 0; } } trx_frame_write(txcwdata, 128); } trx_reg_write(RG_PART_NUM, 0x54); trx_reg_write(RG_PART_NUM, 0x46); set_trx_state(CMD_PLL_ON); TRX_SLP_TR_HIGH(); TRX_SLP_TR_LOW(); }
/* * \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 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) { /* * 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() */
/* * \brief Handles interrupts issued due to end of transmission * * \param underrun_occured true if under-run has occurred */ void handle_tx_end_irq(bool underrun_occured) { #if ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) if (tal_beacon_transmission) { tal_beacon_transmission = false; if (tal_csma_state == BACKOFF_WAITING_FOR_BEACON) { /* Slotted CSMA has been waiting for a beacon, now it * can continue. */ tal_csma_state = CSMA_HANDLE_BEACON; } } else #endif /* ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) */ { #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) /* * Store tx timestamp to frame_info_t structure. * The timestamping is only required for beaconing networks * or if timestamping is explicitly enabled. */ #if (DISABLE_TSTAMP_IRQ == 0) /* * The Tx timestamp is stored during the timestamp interrupt * at DIG2. */ mac_frame_ptr->time_stamp = tal_timestamp; #else { uint32_t time_stamp_temp = 0; pal_trx_read_timestamp(&time_stamp_temp); mac_frame_ptr->time_stamp = time_stamp_temp; } #endif #endif /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */ /* Read trac status before enabling RX_AACK_ON. */ if (underrun_occured) { trx_trac_status = TRAC_INVALID; } else { trx_trac_status = /*(trx_trac_status_t)*/ trx_bit_read( SR_TRAC_STATUS); } #ifdef BEACON_SUPPORT if (tal_csma_state == FRAME_SENDING) { /* Transmission was * issued by slotted CSMA **/ PIN_TX_END(); tal_state = TAL_SLOTTED_CSMA; /* Map status message of transceiver to TAL constants. **/ switch (trx_trac_status) { case TRAC_SUCCESS_DATA_PENDING: PIN_ACK_OK_START(); tal_csma_state = TX_DONE_FRAME_PENDING; break; case TRAC_SUCCESS: PIN_ACK_OK_START(); tal_csma_state = TX_DONE_SUCCESS; break; case TRAC_CHANNEL_ACCESS_FAILURE: PIN_NO_ACK_START(); tal_csma_state = CSMA_ACCESS_FAILURE; break; case TRAC_NO_ACK: PIN_NO_ACK_START(); tal_csma_state = TX_DONE_NO_ACK; break; case TRAC_INVALID: /* Handle this in the same way as * default. */ default: Assert("not handled trac status" == 0); tal_csma_state = CSMA_ACCESS_FAILURE; break; } PIN_ACK_OK_END(); PIN_ACK_WAITING_END(); } else #endif /* BEACON_SUPPORT */ /* Trx has handled the entire transmission incl. CSMA */ { if (tal_sw_retry_no_csma_ca && tal_sw_retry_count && TRAC_NO_ACK == trx_trac_status) { tal_trx_status_t trx_status; do { trx_status = set_trx_state( CMD_TX_ARET_ON); } while (trx_status != TX_ARET_ON); /* Toggle the SLP_TR pin triggering *transmission. */ TRX_SLP_TR_HIGH(); PAL_WAIT_65_NS(); TRX_SLP_TR_LOW(); if (--tal_sw_retry_count == 0) { tal_sw_retry_no_csma_ca = false; } } else { tal_state = TAL_TX_DONE; /* Further handling is * done by * tx_done_handling() **/ } } } /* * After transmission has finished, switch receiver on again. * Check if receive buffer is available. */ if (NULL == tal_rx_buffer) { set_trx_state(CMD_PLL_ON); tal_rx_on_required = true; } else { set_trx_state(CMD_RX_AACK_ON); } }
/** * \brief 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; }
/* * \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(); }