/** * @brief Configures the transceiver * * This function is called to configure the transceiver after reset. */ static void trx_config(void) { /* After we have initialized a proper seed for rand(), * the transceiver's CSMA seed can be initialized. * It needs to be assured that a seed for function rand() * had been generated before. */ /* * Init the SEED value of the CSMA backoff algorithm. */ uint16_t rand_value = (uint16_t)rand(); 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_trx_bit_write(SR_AACK_SET_PD, PD_ACK_BIT_SET_ENABLE); /* ACKs for data requests, indicate pending data */ pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_ENABLE); /* Enable buffer protection mode */ pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); pal_trx_reg_write(0x156, 0xFF); /* RPC feature configuration. */ #if (ANTENNA_DIVERSITY == 1) // Use antenna diversity pal_trx_bit_write(SR_ANT_CTRL, ANTENNA_DEFAULT); pal_trx_bit_write(SR_PDT_THRES, THRES_ANT_DIV_ENABLE); pal_trx_bit_write(SR_ANT_DIV_EN, ANT_DIV_ENABLE); pal_trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE); #endif #ifdef CCA_ED_THRESHOLD /* * Set CCA ED Threshold to other value than standard register due to * board specific loss (see pal_config.h). */ pal_trx_bit_write(SR_CCA_ED_THRES, CCA_ED_THRESHOLD); #endif }
/** * @brief Starts continuous transmission on current channel */ void tfa_continuous_tx_start(continuous_tx_mode_t tx_mode) { uint8_t txcwdata[127]; pal_trx_bit_write(SR_TX_AUTO_CRC_ON, TX_AUTO_CRC_DISABLE); pal_trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); pal_trx_reg_write(0x0176, 0x0F); /*TST_CTRL_DIGI*/ /* Here: use 2MBPS mode for PSD measurements. * Omit the two following lines, if 250k mode is desired for PRBS mode. */ pal_trx_bit_write(SR_OQPSK_DATA_RATE, ALTRATE_2MBPS); pal_trx_reg_write(RG_RX_CTRL, 0xA7); if (tx_mode == CW_MODE) { txcwdata[0] = 1; // length // Step 11 - frame buffer write access txcwdata[1] = 0x00; // f=fch-0.5 MHz; set value to 0xFF for f=fch+0.5MHz pal_trx_frame_write(txcwdata, 2); } else // PRBS mode { txcwdata[0] = 127; // = max length for (uint8_t i = 1; i < 128; i++) { txcwdata[i] = (uint8_t)rand(); } pal_trx_frame_write(txcwdata, 128); } pal_trx_reg_write(RG_PART_NUM, 0x54); pal_trx_reg_write(RG_PART_NUM, 0x46); set_trx_state(CMD_PLL_ON); PAL_SLP_TR_HIGH(); PAL_SLP_TR_LOW(); }
/** * \brief Configures the transceiver * * This function is called to configure the transceiver after reset. */ void trx_config(void) { /* Set pin driver strength */ pal_trx_bit_write(SR_CLKM_SHA_SEL, CLKM_SHA_DISABLE); pal_trx_bit_write(SR_CLKM_CTRL, CLKM_1MHZ); /* * After we have initialized a proper seed for rand(), * the transceiver's CSMA seed can be initialized. * It needs to be assured that a seed for function rand() * had been generated before. */ /* * Init the SEED value of the CSMA backoff algorithm. */ uint16_t rand_value = (uint16_t)rand(); 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)); /* * Since the TAL is supporting 802.15.4-2006, * frames with version number 0 (compatible to 802.15.4-2003) and * with version number 1 (compatible to 802.15.4-2006) are acknowledged. */ pal_trx_bit_write(SR_AACK_FVN_MODE, FRAME_VERSION_01); pal_trx_bit_write(SR_AACK_SET_PD, SET_PD); /* ACKs for data requests, indicate pending data */ pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_ENABLE); /* Enable buffer protection mode */ pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); /* The TRX_END interrupt of the transceiver is enabled. */ pal_trx_reg_write(RG_TRX_RPC, 0xFF); /* RPC feature configuration. */ #if (ANTENNA_DIVERSITY == 1) /* Use antenna diversity */ pal_trx_bit_write(SR_ANT_CTRL, ANTENNA_DEFAULT); pal_trx_bit_write(SR_PDT_THRES, THRES_ANT_DIV_ENABLE); pal_trx_bit_write(SR_ANT_DIV_EN, ANT_DIV_ENABLE); pal_trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE); #endif /* ANTENNA_DIVERSITY */ #if (DISABLE_TSTAMP_IRQ == 0) #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) /* Enable Rx timestamping */ pal_trx_bit_write(SR_IRQ_2_EXT_EN, RX_TIMESTAMPING_ENABLE); /* Enable Tx timestamping */ pal_trx_bit_write(SR_ARET_TX_TS_EN, TX_ARET_TIMESTAMPING_ENABLE); #endif /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */ #endif #ifdef CCA_ED_THRESHOLD /* * Set CCA ED Threshold to other value than standard register due to * board specific loss (see pal_config.h). */ pal_trx_bit_write(SR_CCA_ED_THRES, CCA_ED_THRESHOLD); #endif #ifdef EXT_RF_FRONT_END_CTRL /* Enable RF front end control */ pal_trx_bit_write(SR_PA_EXT_EN, 1); #endif }
/* * \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 pal_trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); // step 7: Enable continuous transmission - step #1 pal_trx_reg_write(0x36, 0x0F); if (tx_mode == CW_MODE) { // step 8: Register access: CW at Fc +/- 0.1 MHz pal_trx_reg_write(RG_TRX_CTRL_2, 0x0A); // 400 kbit mode, step 8 txcwdata[0] = 1; // length txcwdata[1] = 0; // step 9: Frame buffer access pal_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 pal_trx_frame_write(txcwdata, 128); } // step 10: Enable continuous transmission - step #2 pal_trx_reg_write(RG_PART_NUM, 0x54); // step 11: Enable continuous transmission - step #3 pal_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 PAL_SLP_TR_HIGH(); PAL_SLP_TR_LOW(); }
/** * @brief Switches the PLL on */ static void switch_pll_on(void) { uint32_t start_time; uint32_t current_time; /* Check if trx is in TRX_OFF; only from PLL_ON the following procedure is applicable */ if (pal_trx_bit_read(SR_TRX_STATUS) != TRX_OFF) { ASSERT("Switch PLL_ON failed, because trx is not in TRX_OFF" == 0); return; } /* Clear all pending trx interrupts */ pal_trx_reg_read(RG_IRQ_STATUS); /* Get current IRQ mask */ uint8_t trx_irq_mask = pal_trx_reg_read(RG_IRQ_MASK); /* Enable transceiver's PLL lock interrupt */ pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_0_PLL_LOCK); ENTER_TRX_REGION(); // Disable trx interrupt handling /* Switch PLL on */ pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); pal_get_current_time(&start_time); /* Wait for transceiver interrupt: check for IRQ line */ while (PAL_TRX_IRQ_HIGH() == false) { /* Handle errata "potential long PLL settling duration". */ pal_get_current_time(¤t_time); if (pal_sub_time_us(current_time, start_time) > PLL_LOCK_DURATION_MAX_US) { uint8_t reg_value; reg_value = pal_trx_reg_read(RG_PLL_CF); if (reg_value & 0x01) { reg_value &= 0xFE; } else { reg_value |= 0x01; } pal_trx_reg_write(RG_PLL_CF, reg_value); pal_get_current_time(&start_time); } /* Wait until trx line has been raised. */ } /* Clear PLL lock interrupt at trx */ pal_trx_reg_read(RG_IRQ_STATUS); /* Clear MCU's interrupt flag */ pal_trx_irq_flag_clr(); LEAVE_TRX_REGION(); // Enable trx interrupt handling again /* Restore transceiver's interrupt mask. */ pal_trx_reg_write(RG_IRQ_MASK, trx_irq_mask); }
/* * \brief Starts ED Scan * * This function starts an ED Scan for the scan duration specified by the * MAC layer. * * \param scan_duration Specifies the ED scan duration in symbols * * \return MAC_SUCCESS - ED scan duration timer started successfully * TAL_BUSY - TAL is busy servicing the previous request from MAC * TAL_TRX_ASLEEP - Transceiver is currently sleeping * FAILURE otherwise */ retval_t tal_ed_start(uint8_t scan_duration) { /* * Check if the TAL is in idle state. Only in idle state it can * accept and ED request from the MAC. */ if (TAL_IDLE != tal_state) { if (tal_trx_status == TRX_SLEEP) { return TAL_TRX_ASLEEP; } else { Assert("TAL is TAL_BUSY" == 0); return TAL_BUSY; } } /* * Disable the transceiver interrupts to prevent frame reception * while performing ED scan. */ pal_trx_irq_dis(); /* Disable transceiver main interrupt. */ set_trx_state(CMD_FORCE_PLL_ON); pal_trx_reg_read(RG_IRQ_STATUS); /* Clear existing interrupts */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_DISABLE); pal_trx_irq_init((FUNC_PTR)trx_ed_irq_handler_cb); pal_trx_bit_write(SR_IRQ_MASK, TRX_IRQ_CCA_ED_READY); /* enable interrupt */ pal_trx_irq_en(); /* Enable main transceiver interrupt. */ /* Make sure that receiver is switched on. */ if (set_trx_state(CMD_RX_ON) != RX_ON) { /* Restore previous configuration */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb); pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); /* enable TRX_END interrupt */ pal_trx_irq_en(); /* Enable main transceiver interrupt. */ return FAILURE; } // write dummy value to start measurement pal_trx_reg_write(RG_PHY_ED_LEVEL, 0xFF); /* Perform ED in TAL_ED_RUNNING state. */ tal_state = TAL_ED_RUNNING; max_ed_level = 0; // reset max value sampler_counter = CALCULATE_SYMBOL_TIME_SCAN_DURATION(scan_duration) / ED_SAMPLE_DURATION_SYM; return MAC_SUCCESS; }
/** * @brief Generates a 16-bit random number used as initial seed for srand() * * This function generates a 16-bit random number by means of using the * Random Number Generator from the transceiver. * The Random Number Generator generates 2-bit random values. These 2-bit * random values are concatenated to the required 16-bit random seed. * * The generated random 16-bit number is feed into function srand() * as initial seed. * * The transceiver state is initally set to RX_ON. * After the completion of the random seed generation, the * trancseiver is set to TRX_OFF. * * As a prerequisite the preamble detector must not be disabled. * * Also in case the function is called from a different state than TRX_OFF, * additional trx state handling is required, such as reading the original * value and restoring this state after finishing the sequence. * Since in our case the function is called from TRX_OFF, this is not required * here. */ void tal_generate_rand_seed(void) { uint16_t seed = 0; uint8_t cur_random_val = 0; /* RPC could influence the randomness; therefore disable it here. */ uint8_t previous_RPC_value = pal_trx_reg_read(RG_TRX_RPC); pal_trx_reg_write(RG_TRX_RPC, 0xC1); /* * We need to disable TRX IRQs while generating random values in RX_ON, * we do not want to receive frames at this point of time at all. */ ENTER_TRX_REGION(); /* Ensure that PLL has locked and receive mode is reached. */ tal_trx_status_t trx_state; do { trx_state = set_trx_state(CMD_RX_ON); } while (trx_state != RX_ON); /* Ensure that register bit RX_PDT_DIS is set to 0. */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* * The 16-bit random value is generated from various 2-bit random values. */ for (uint8_t i = 0; i < 8; i++) { /* Now we can safely read the 2-bit random number. */ cur_random_val = pal_trx_bit_read(SR_RND_VALUE); seed = seed << 2; seed |= cur_random_val; PAL_WAIT_1_US(); // wait that the random value gets updated } set_trx_state(CMD_FORCE_TRX_OFF); /* * Now we need to clear potential pending TRX IRQs and * enable the TRX IRQs again. */ pal_trx_reg_read(RG_IRQ_STATUS); pal_trx_irq_flag_clr(); LEAVE_TRX_REGION(); /* Set the seed for the random number generator. */ srand(seed); /* Restore RPC settings. */ pal_trx_reg_write(RG_TRX_RPC, previous_RPC_value); }
/** * @brief Write all shadow PIB variables to the transceiver * * This function writes all shadow PIB variables to the transceiver. * It is assumed that the radio does not sleep. */ void write_all_tal_pib_to_trx(void) { uint8_t *ptr_to_reg; ptr_to_reg = (uint8_t *)&tal_pib.PANId; for (uint8_t i = 0; i < 2; i++) { pal_trx_reg_write((RG_PAN_ID_0 + i), *ptr_to_reg); ptr_to_reg++; } ptr_to_reg = (uint8_t *)&tal_pib.IeeeAddress; for (uint8_t i = 0; i < 8; i++) { pal_trx_reg_write((RG_IEEE_ADDR_0 + i), *ptr_to_reg); ptr_to_reg++; } ptr_to_reg = (uint8_t *)&tal_pib.ShortAddress; for (uint8_t i = 0; i < 2; i++) { pal_trx_reg_write((RG_SHORT_ADDR_0 + i), *ptr_to_reg); ptr_to_reg++; } /* configure TX_ARET; CSMA and CCA */ pal_trx_bit_write(SR_CCA_MODE, tal_pib.CCAMode); pal_trx_bit_write(SR_MIN_BE, tal_pib.MinBE); pal_trx_bit_write(SR_AACK_I_AM_COORD, tal_pib.PrivatePanCoordinator); /* set phy parameter */ pal_trx_bit_write(SR_MAX_BE, tal_pib.MaxBE); #ifdef HIGH_DATA_RATE_SUPPORT apply_channel_page_configuration(tal_pib.CurrentPage); #endif pal_trx_bit_write(SR_CHANNEL, tal_pib.CurrentChannel); { uint8_t reg_value; reg_value = convert_phyTransmitPower_to_reg_value(tal_pib.TransmitPower); pal_trx_bit_write(SR_TX_PWR, reg_value); } #ifdef PROMISCUOUS_MODE if (tal_pib.PromiscuousMode) { set_trx_state(CMD_RX_ON); } #endif }
/** * \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 Scan done * * This function updates the max_ed_level and invokes the callback function * tal_ed_end_cb(). * * \param parameter unused callback parameter */ void ed_scan_done(void) { pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb); pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); /* enable TRX_END interrupt */ pal_trx_irq_en(); /* Enable transceiver main interrupt. */ tal_state = TAL_IDLE; // ed scan is done set_trx_state(CMD_RX_AACK_ON); #ifndef TRX_REG_RAW_VALUE /* * Scale ED result. * Clip values to 0xFF if > -35dBm */ if (max_ed_level > CLIP_VALUE_REG) { max_ed_level = 0xFF; } else { max_ed_level = (uint8_t)(((uint16_t)max_ed_level * 0xFF) / CLIP_VALUE_REG); } #endif tal_ed_end_cb(max_ed_level); }
trx_retval_t tal_init(void) { if (trx_init() != TRX_SUCCESS) { return TRX_FAILURE; } /* * Do the reset stuff. * Generate random seed. */ if (internal_tal_reset() != TRX_SUCCESS) { return TRX_FAILURE; } /* Set the default CCA mode. */ pal_trx_bit_write(SR_CCA_MODE, CCA_MODE_DEFAULT); /* Default configuration to perform auto CSMA-CA */ pal_trx_reg_write(RG_CSMA_BE, ((MAXBE_DEFAULT << 4) | MINBE_DEFAULT)); pal_trx_bit_write(SR_MAX_CSMA_RETRIES, MAX_CSMA_BACKOFFS_DEFAULT); /* Set the trx in promiscuous mode to receive all frame with CRC OK */ pal_trx_bit_write(SR_AACK_PROM_MODE, PROM_MODE_ENABLE); /* Configuration to perform auto CRC for transmission */ pal_trx_bit_write(SR_TX_AUTO_CRC_ON, TX_AUTO_CRC_ENABLE); return TRX_SUCCESS; }
/** * \brief Start CCA. * * \param parameter Unused callback parameter */ static void cca_start(void *parameter) { tal_state = TAL_CCA; if (set_trx_state(CMD_PLL_ON) == PLL_ON) { tal_trx_status_t trx_state; /* No interest in receiving frames while doing CCA */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_DISABLE); /* disable frame * reception * indication */ do { trx_state = set_trx_state(CMD_RX_ON); } while (trx_state != RX_ON); /* Setup interrupt handling for CCA IRQ */ pal_trx_irq_init((FUNC_PTR)cca_done_irq_handler); pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_CCA_ED_READY); /* enable *CCA *interrupt **/ /* Start CCA */ pal_trx_bit_write(SR_CCA_REQUEST, CCA_START); } else { /* Channel is busy, i.e. device is receiving */ tal_state = TAL_CSMA_CONTINUE; } /* Keep compiler happy. */ parameter = parameter; }
/** * @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 Scan done * * This function updates the max_ed_level and invokes the callback function * tal_ed_end_cb(). * * @param parameter unused callback parameter */ void ed_scan_done(void) { /* Restore previous configuration */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); tal_state = TAL_IDLE; // ed scan is done set_trx_state(CMD_RX_AACK_ON); #ifndef TRX_REG_RAW_VALUE /* * Scale ED result. * Clip values to 0xFF if > -35dBm */ if (max_ed_level > CLIP_VALUE_REG) { max_ed_level = 0xFF; } else { max_ed_level = (uint8_t)(((uint16_t)max_ed_level * 0xFF) / CLIP_VALUE_REG); } #endif tal_ed_end_cb(max_ed_level); }
/** * @brief ED Scan Interrupt * * This function handles an ED done interrupt from the transceiver. */ static void trx_ed_irq_handler_cb(void) { uint8_t ed_value; /* Read the ED Value. */ ed_value = pal_trx_reg_read(RG_PHY_ED_LEVEL); /* * Update the peak ED value received, if greater than the previously * read ED value. */ if (ed_value > max_ed_level) { max_ed_level = ed_value; } /* Start next ED sampling */ sampler_counter--; if (sampler_counter > 0) { // write dummy value to start measurement pal_trx_reg_write(RG_PHY_ED_LEVEL, 0xFF); } else { tal_state = TAL_ED_DONE; } }
/** * @brief Starts ED Scan * * This function starts an ED Scan for the scan duration specified by the * MAC layer. * * @param scan_duration Specifies the ED scan duration in symbols * * @return MAC_SUCCESS - ED scan duration timer started successfully * TAL_BUSY - TAL is busy servicing the previous request from MAC * TAL_TRX_ASLEEP - Transceiver is currently sleeping * FAILURE otherwise */ retval_t tal_ed_start(uint8_t scan_duration) { /* * Check if the TAL is in idle state. Only in idle state it can * accept and ED request from the MAC. */ if (TAL_IDLE != tal_state) { if (tal_trx_status == TRX_SLEEP) { return TAL_TRX_ASLEEP; } else { ASSERT("TAL is TAL_BUSY" == 0); return TAL_BUSY; } } set_trx_state(CMD_FORCE_PLL_ON); pal_trx_bit_write(SR_RX_PDT_DIS, RX_DISABLE); pal_trx_irq_flag_clr_cca_ed(); pal_trx_irq_init_cca_ed((FUNC_PTR)trx_ed_irq_handler_cb); pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_CCA_ED_READY); /* Make sure that receiver is switched on. */ if (set_trx_state(CMD_RX_ON) != RX_ON) { /* Restore previous configuration */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); return FAILURE; } /* Perform ED in TAL_ED_RUNNING state. */ tal_state = TAL_ED_RUNNING; max_ed_level = 0; // reset max value sampler_counter = CALCULATE_SYMBOL_TIME_SCAN_DURATION(scan_duration) / ED_SAMPLE_DURATION_SYM; // write dummy value to start measurement pal_trx_reg_write(RG_PHY_ED_LEVEL, 0xFF); return MAC_SUCCESS; }
/** * @brief Generates a 16-bit random number used as initial seed for srand() * * This function generates a 16-bit random number by means of using the * Random Number Generator from the transceiver. * The Random Number Generator generates 2-bit random values. These 2-bit * random values are concatenated to the required 16-bit random seed. * * The generated random 16-bit number is feed into function srand() * as initial seed. * * The transceiver state is initally set to RX_ON. * After the completion of the random seed generation, the * trancseiver is set to TRX_OFF. * * As a prerequisite the preamble detector must not be disabled. * * Also in case the function is called from a different state than TRX_OFF, * additional trx state handling is required, such as reading the original * value and restoring this state after finishing the sequence. * Since in our case the function is called from TRX_OFF, this is not required * here. */ void tal_generate_rand_seed(void) { uint16_t seed = 0; uint8_t cur_random_val = 0; /* Ensure that PLL has locked and receive mode is reached. */ tal_trx_status_t trx_state; do { trx_state = set_trx_state(CMD_RX_ON); } while (trx_state != RX_ON); /* Ensure that register bit RX_PDT_DIS is set to 0. */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* * We need to disable TRX IRQs while generating random values in RX_ON, * we do not want to receive frames at this point of time at all. */ pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_NONE); /* * The 16-bit random value is generated from various 2-bit random values. */ for (uint8_t i = 0; i < 8; i++) { /* Now we can safely read the 2-bit random number. */ cur_random_val = pal_trx_bit_read(SR_RND_VALUE); seed = seed << 2; seed |= cur_random_val; PAL_WAIT_1_US(); // wait that the random value gets updated } set_trx_state(CMD_FORCE_TRX_OFF); /* * Now we need to clear potential pending TRX IRQs and * enable the TRX IRQs again. */ pal_trx_reg_write(RG_IRQ_STATUS, 0xFF); pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); /* Set the seed for the random number generator. */ srand(seed); }
/** * @brief Switches the PLL on */ static void switch_pll_on(void) { trx_irq_reason_t irq_status; uint32_t start_time, now; /* 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; } /* use the IRQ status register checking for the actual PLL status */ pal_trx_irq_dis(); pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_PLL_LOCK); /* allow PLL lock IRQ only*/ 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. */ pal_get_current_time(&start_time); while (1) { irq_status = (trx_irq_reason_t)pal_trx_reg_read(RG_IRQ_STATUS); if (irq_status & TRX_IRQ_PLL_LOCK) { break; // PLL is locked now } /* Check if polling needs too much time. */ pal_get_current_time(&now); if (pal_sub_time_us(now, start_time) > (10 * PLL_LOCK_TIME_US)) { /* leave poll loop and throw assertion */ #if (DEBUG > 0) ASSERT("PLL switch failed" == 0); #endif break; } } pal_trx_irq_flag_clr(); pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_TRX_END); /* enable TRX_END interrupt */ pal_trx_irq_en(); }
/* * \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 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 Write all shadow PIB variables to the transceiver * * This function writes all shadow PIB variables to the transceiver. * It is assumed that the radio does not sleep. */ void write_all_tal_pib_to_trx(void) { uint8_t *ptr_to_reg; /* configure RX_AACK */ ptr_to_reg = (uint8_t *)&tal_pib.PANId; for (uint8_t i = 0; i < 2; i++) { pal_trx_reg_write((RG_PAN_ID_0 + i), *ptr_to_reg); ptr_to_reg++; } ptr_to_reg = (uint8_t *)&tal_pib.IeeeAddress; for (uint8_t i = 0; i < 8; i++) { pal_trx_reg_write((RG_IEEE_ADDR_0 + i), *ptr_to_reg); ptr_to_reg++; } ptr_to_reg = (uint8_t *)&tal_pib.ShortAddress; for (uint8_t i = 0; i < 2; i++) { pal_trx_reg_write((RG_SHORT_ADDR_0 + i), *ptr_to_reg); ptr_to_reg++; } /* configure TX_ARET; CSMA and CCA */ { uint8_t reg_value; reg_value = convert_phyTransmitPower_to_reg_value(tal_pib.TransmitPower); pal_trx_bit_write(SR_TX_PWR, reg_value); } pal_trx_bit_write(SR_CCA_MODE, tal_pib.CCAMode); pal_trx_bit_write(SR_CHANNEL, tal_pib.CurrentChannel); pal_trx_bit_write(SR_MIN_BE, tal_pib.MinBE); #ifdef PROMISCUOUS_MODE if (tal_pib.PromiscuousMode) { set_trx_state(CMD_RX_ON); } #endif }
/** * @brief Write all shadow PIB variables to the transceiver * * This function writes all shadow PIB variables to the transceiver. * It is assumed that the radio does not sleep. */ void write_all_tal_pib_to_trx(void) { uint8_t *ptr_to_reg; pal_trx_reg_write(RG_PAN_ID_0, (uint8_t)tal_pib_PANId); pal_trx_reg_write(RG_PAN_ID_1, (uint8_t)(tal_pib_PANId >> 8)); ptr_to_reg = (uint8_t *)&tal_pib_IeeeAddress; for (uint8_t i = 0; i < 8; i++) { pal_trx_reg_write((RG_IEEE_ADDR_0 + i), *ptr_to_reg); ptr_to_reg++; } pal_trx_reg_write(RG_SHORT_ADDR_0, (uint8_t)tal_pib_ShortAddress); pal_trx_reg_write(RG_SHORT_ADDR_1, (uint8_t)(tal_pib_ShortAddress >> 8)); /* configure TX_ARET; CSMA and CCA */ pal_trx_bit_write(SR_CCA_MODE, tal_pib_CCAMode); pal_trx_bit_write(SR_MIN_BE, tal_pib_MinBE); pal_trx_bit_write(SR_AACK_I_AM_COORD, tal_pib_PrivatePanCoordinator); /* set phy parameter */ pal_trx_bit_write(SR_MAX_BE, tal_pib_MaxBE); apply_channel_page_configuration(tal_pib_CurrentPage); { uint8_t reg_value; reg_value = convert_phyTransmitPower_to_reg_value(tal_pib_TransmitPower); pal_trx_reg_write(RG_PHY_TX_PWR, reg_value); } #ifdef PROMISCUOUS_MODE if (tal_pib_PromiscuousMode) { set_trx_state(CMD_RX_ON); } #endif }
/* * \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]; pal_trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); pal_trx_bit_write(SR_TX_AUTO_CRC_ON, TX_AUTO_CRC_DISABLE); pal_trx_reg_write(0x36, 0x0F); /* TST_CTRL_DIGI */ if (tx_mode == CW_MODE) { txcwdata[0] = 1; // step 9 txcwdata[1] = 0; pal_trx_frame_write(txcwdata, 2); // Step 10 pal_trx_reg_write(0x3D, 0x80); /* Configure continuous Tx (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; } } pal_trx_frame_write(txcwdata, 128); pal_trx_reg_write(0x3D, 0x00); /* Configure continuous Tx (2) */ } // set tst pin to high TST_PORT_HIGH(); set_trx_state(CMD_PLL_ON); PAL_SLP_TR_HIGH(); PAL_SLP_TR_LOW(); }
/** * \brief Test the read and write of register on AT86RFx module * * This function will test the read and write functionalities of register * It will first write a known value (state) to register and reads the * register to confirm the same value. * * \param test Current test case. */ static void run_at86rfx_reg_access_test(const struct test_case *test) { bool status; trx_cmd_t value; pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON); value = (trx_cmd_t) pal_trx_reg_read(RG_TRX_STATE); status = (CMD_RX_ON == value) ? true : false; test_assert_true(test, status == true, "Error Read/write AT86RFx register access failed"); }
/** * @brief Subregister write * * @param[in] reg_addr Offset of the register * @param[in] mask Bit mask of the subregister * @param[in] pos Bit position of the subregister * @param[out] new_value Data, which is muxed into the register */ void pal_trx_bit_write(uint8_t reg_addr, uint8_t mask, uint8_t pos, uint8_t new_value) { uint8_t current_reg_value; current_reg_value = pal_trx_reg_read(reg_addr); current_reg_value &= (uint8_t)~(uint32_t)mask; // Implicit casting required to avoid IAR Pa091. new_value <<= pos; new_value &= mask; new_value |= current_reg_value; pal_trx_reg_write(reg_addr, new_value); }
static trx_retval_t trx_init(void) { tal_trx_status_t trx_status; uint8_t poll_counter = 0; /* Ensure control lines have correct levels. */ RST_HIGH(); SLP_TR_LOW(); /* Wait typical time. */ DELAY_US(P_ON_TO_CLKM_AVAILABLE_TYP_US); /* Apply reset pulse */ RST_LOW(); DELAY_US(RST_PULSE_WIDTH_US); 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 TRX_FAILURE; } /* Wait a short time interval. */ DELAY_US(TRX_POLL_WAIT_TIME_US); poll_counter++; /* Check if AT86RF212 is connected; omit manufacturer id check */ } while (pal_trx_reg_read(RG_PART_NUM) != PART_NUM_AT86RF212); /* Set trx to off mode */ pal_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. */ DELAY_US(TRX_POLL_WAIT_TIME_US); trx_status = (tal_trx_status_t) pal_trx_bit_read(SR_TRX_STATUS); /* Wait not more than max attempts for state transition */ if (poll_counter == SLEEP_TO_TRX_OFF_ATTEMPTS) { return TRX_FAILURE; } poll_counter++; } while (trx_status != TRX_OFF); tal_trx_status = TRX_OFF; return TRX_SUCCESS; }
/** * \brief Finalizes the CSMA procedure * * \param status Result of the slotted transmission */ static void tx_done(retval_t status) { #if (_DEBUG_ > 0) switch (tal_state) { case TAL_SLOTTED_CSMA: case TAL_TX_BASIC: break; #if ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) case TAL_TX_BEACON: Assert("unexpected tal_state TAL_TX_BEACON" == 0); return; /* break; */ #endif /* ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) */ default: Assert("unexpected tal_state" == 0); break; } #endif #if (_DEBUG_ > 0) if (pal_is_timer_running(TAL_CSMA_BEACON_LOSS_TIMER)) { Assert("beacon lost timer is still running" == 0); } #endif tal_state = TAL_IDLE; tal_csma_state = CSMA_IDLE; /* * Restore the interrupt handler. * Install a handler for the transceiver interrupt. */ pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb); pal_trx_reg_read(RG_IRQ_STATUS); /* Check if a receive buffer is available. */ if (NULL != tal_rx_buffer) { pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); } else { tal_rx_on_required = true; } pal_trx_irq_en(); /* debug pin to switch on: define ENABLE_DEBUG_PINS, pal_config.h */ PIN_CSMA_END(); tal_tx_frame_done_cb(status, mac_frame_ptr); }
/** * \brief Configures the transceiver * * This function is called to configure the transceiver after reset. */ static void trx_config(void) { /* Set pin driver strength */ pal_trx_reg_write(RG_TRX_CTRL_0, ((CLKM_2mA << 6) | (CLKM_2mA << 4) | CLKM_1MHz)); /* fast * change */ /* * Init the SEED value of the CSMA backoff algorithm. */ uint16_t 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)); /* * To make sure that the CSMA seed is properly set within the *transceiver, * put the trx to sleep briefly and wake it up again. */ tal_trx_sleep(SLEEP_MODE_1); tal_trx_wakeup(); pal_trx_bit_write(SR_AACK_SET_PD, PD_ACK_BIT_SET_ENABLE); /* 1 == frame *pending bit *is always *set to 1 */ pal_trx_bit_write(SR_TX_AUTO_CRC_ON, TX_AUTO_CRC_ENABLE); /* enable auto *crc */ pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_TRX_END); /* enable TRX_END *interrupt */ #ifdef CCA_ED_THRESHOLD /* * Set CCA ED Threshold to other value than standard register due to * board specific loss (see pal_config.h). */ pal_trx_bit_write(SR_CCA_ED_THRES, CCA_ED_THRESHOLD); #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; 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 handling of CCA result. */ void cca_done_handling(void) { set_trx_state(CMD_PLL_ON); /* leave RX_ON */ /* Restore IRQ handling */ pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb); pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* Enable frame reception. **/ /* Check if channel was idle or busy */ if (pal_trx_bit_read(SR_CCA_STATUS) == CCA_STATUS_CHANNEL_IS_IDLE) { tx_frame(); } else { tal_state = TAL_CSMA_CONTINUE; } }