/** * \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 */ 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 */ trx_irq_init((FUNC_PTR)cca_done_irq_handler); trx_reg_write(RG_IRQ_MASK, TRX_IRQ_CCA_ED_READY); /* enable * CCA * interrupt **/ /* Start CCA */ 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 Starts the timer for the backoff period and enables receiver. */ static void start_backoff(void) { /* Start backoff timer to trigger CCA */ uint8_t backoff_8; backoff_8 = (uint8_t)rand() & ((1 << BE) - 1); if (backoff_8 > 0) { uint16_t backoff_16; uint32_t backoff_duration_us; backoff_16 = backoff_8 * aUnitBackoffPeriod; backoff_duration_us = TAL_CONVERT_SYMBOLS_TO_US(backoff_16); pal_timer_start(TAL_T_BOFF, backoff_duration_us, TIMEOUT_RELATIVE, (FUNC_PTR)cca_start, NULL); tal_state = TAL_BACKOFF; #ifdef RX_WHILE_BACKOFF /* Switch receiver on during backoff */ if (NULL == tal_rx_buffer) { set_trx_state(CMD_PLL_ON); tal_rx_on_required = true; } else { set_trx_state(CMD_RX_AACK_ON); /* receive while backoff **/ } #else set_trx_state(CMD_PLL_ON); #endif } else { /* Start CCA immediately - no backoff */ cca_start(NULL); } }
/** * @brief Sets the transceiver to sleep * * This function sets the transceiver to sleep state. * * @param mode Defines sleep mode of transceiver SLEEP or PHY_TRX_OFF) * * @return TAL_BUSY - The transceiver is busy in TX or RX * MAC_SUCCESS - The transceiver is put to sleep * TAL_TRX_ASLEEP - The transceiver is already asleep * MAC_INVALID_PARAMETER - The specified sleep mode is not supported */ retval_t tal_trx_sleep(sleep_mode_t mode) { tal_trx_status_t trx_status; /* Current transceiver only supports SLEEP_MODE_1 mode. */ if (SLEEP_MODE_1 != mode) { return MAC_INVALID_PARAMETER; } if (tal_trx_status == TRX_SLEEP) { return TAL_TRX_ASLEEP; } /* Device can be put to sleep only when the TAL is in IDLE state. */ if (TAL_IDLE != tal_state) { return TAL_BUSY; } tal_rx_on_required = false; /* * First set trx to TRX_OFF. * If trx is busy, like ACK transmission, do not interrupt it. */ do { trx_status = set_trx_state(CMD_TRX_OFF); } while (trx_status != TRX_OFF); pal_timer_source_select(TMR_CLK_SRC_DURING_TRX_SLEEP); trx_status = set_trx_state(CMD_SLEEP); #ifdef ENABLE_FTN_PLL_CALIBRATION /* * Stop the calibration timer now. * The timer will be restarted during wake-up. */ pal_timer_stop(TAL_CALIBRATION); #endif /* ENABLE_FTN_PLL_CALIBRATION */ if (trx_status == TRX_SLEEP) { #ifdef STB_ON_SAL #if (SAL_TYPE == AT86RF2xx) stb_restart(); #endif #endif return MAC_SUCCESS; } else { /* State could not be set due to TAL_BUSY state. */ return TAL_BUSY; } }
/* * \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 Sets the transceiver to sleep * * This function sets the transceiver to sleep state. * * \param mode Defines sleep mode of transceiver SLEEP or PHY_TRX_OFF) * * \return TAL_BUSY - The transceiver is busy in TX or RX * MAC_SUCCESS - The transceiver is put to sleep * TAL_TRX_ASLEEP - The transceiver is already asleep * MAC_INVALID_PARAMETER - The specified sleep mode is not supported */ retval_t tal_trx_sleep(sleep_mode_t mode) { tal_trx_status_t trx_status; /* Current transceiver only supports SLEEP_MODE_1 mode. */ if (SLEEP_MODE_1 != mode) { return MAC_INVALID_PARAMETER; } if (tal_trx_status == TRX_SLEEP) { return TAL_TRX_ASLEEP; } /* Device can be put to sleep only when the TAL is in IDLE state. */ if (TAL_IDLE != tal_state) { return TAL_BUSY; } tal_rx_on_required = false; /* * First set trx to TRX_OFF. * If trx is busy, like ACK transmission, do not interrupt it. */ do { trx_status = set_trx_state(CMD_TRX_OFF); } while (trx_status != TRX_OFF); #ifndef NO_32KHZ_CRYSTAL /* Do not set to SLEEP to keep clock source for symbol counter alive. */ trx_status = set_trx_state(CMD_SLEEP); #else /* Pretend that trx is in SLEEP - for this function only. */ trx_status = TRX_SLEEP; #endif #ifdef ENABLE_FTN_PLL_CALIBRATION /* * Stop the calibration timer now. * The timer will be restarted during wake-up. */ pal_timer_stop(TAL_CALIBRATION); #endif /* ENABLE_FTN_PLL_CALIBRATION */ if (trx_status == TRX_SLEEP) { #ifdef STB_ON_SAL stb_restart(); #endif return MAC_SUCCESS; } else { /* State could not be set due to TAL_BUSY state. */ return TAL_BUSY; } }
/* * \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 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 Write all shadow PIB variables to the transceiver * * This function writes all shadow PIB variables to the transceiver. * It is assumed that the radio does not sleep. */ void write_all_tal_pib_to_trx(void) { uint8_t *ptr_to_reg; ptr_to_reg = (uint8_t *)&tal_pib.PANId; for (uint8_t i = 0; i < 2; i++) { trx_reg_write((RG_PAN_ID_0 + i), *ptr_to_reg); ptr_to_reg++; } ptr_to_reg = (uint8_t *)&tal_pib.IeeeAddress; for (uint8_t i = 0; i < 8; i++) { trx_reg_write((RG_IEEE_ADDR_0 + i), *ptr_to_reg); ptr_to_reg++; } ptr_to_reg = (uint8_t *)&tal_pib.ShortAddress; for (uint8_t i = 0; i < 2; i++) { trx_reg_write((RG_SHORT_ADDR_0 + i), *ptr_to_reg); ptr_to_reg++; } /* Configure TX_ARET; CSMA and CCA */ trx_bit_write(SR_CCA_MODE, tal_pib.CCAMode); #ifdef SW_CONTROLLED_CSMA /* * If receiver is enabled during backoff periods, * CSMA and frame re-transmissions are handled by software. * Setup trx for immediate transmission. */ trx_bit_write(SR_MAX_FRAME_RETRIES, 0); trx_bit_write(SR_MAX_CSMA_RETRIES, 7); #else trx_bit_write(SR_MIN_BE, tal_pib.MinBE); trx_bit_write(SR_MAX_BE, tal_pib.MaxBE); #endif trx_bit_write(SR_AACK_I_AM_COORD, tal_pib.PrivatePanCoordinator); /* set phy parameter */ apply_channel_page_configuration(tal_pib.CurrentPage); { uint8_t reg_value; reg_value = convert_phyTransmitPower_to_reg_value( tal_pib.TransmitPower); trx_reg_write(RG_PHY_TX_PWR, reg_value); } #ifdef PROMISCUOUS_MODE if (tal_pib.PromiscuousMode) { set_trx_state(CMD_RX_ON); } #endif }
/* * \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) { trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); trx_irq_init((FUNC_PTR)trx_irq_handler_cb); 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); }
/** * @brief Transceiver interrupt handler * * This function handles the transceiver generated interrupts. */ void trx_irq_handler_cb(void) { trx_irq_reason_t trx_irq_cause; trx_irq_cause = (trx_irq_reason_t)pal_trx_reg_read(RG_IRQ_STATUS); if (trx_irq_cause & TRX_IRQ_TRX_END) { /* * TRX_END reason depends on if the trx is currently used for * transmission or reception. */ if ((tal_state == TAL_TX_AUTO) || (tal_state == TAL_TX_BASIC)) { /* Switch to transceiver's default state: switch receiver on. */ set_trx_state(CMD_RX_AACK_ON); handle_tx_end_irq(); // see tal_tx.c } else /* Other tal_state than TAL_TX_... */ { /* Handle rx done interrupt. */ handle_received_frame_irq(); // see tal_rx.c } } }/* trx_irq_handler_cb() */
static void handle_received_frame_irq(void) { /* Actual frame length of received frame. */ uint8_t phy_frame_len; uint8_t *rx_frame_ptr = at86rfx_rx_buffer; /* Perform FCS check for frame validation */ if (CRC16_NOT_VALID == pal_trx_bit_read(SR_RX_CRC_VALID)) { return; } /* Get frame length from transceiver. */ pal_trx_frame_read(&phy_frame_len, LENGTH_FIELD_LEN); /* Check for valid frame length. */ if (phy_frame_len > PHY_MAX_LENGTH) { return; } /* Frame read from transceiver buffer. */ pal_trx_frame_read(rx_frame_ptr, LENGTH_FIELD_LEN + phy_frame_len); /* Set flag indicating received frame to be handled. */ at86rfx_frame_rx = true; set_trx_state(CMD_RX_ON); }
/* * \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 */ trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); 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); }
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 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 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 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 Sets the transceiver to sleep * * This function sets the transceiver to sleep state. * * @param mode Defines sleep mode of transceiver SLEEP or PHY_TRX_OFF) * * @return TAL_BUSY - The transceiver is busy in TX or RX * MAC_SUCCESS - The transceiver is put to sleep * TAL_TRX_ASLEEP - The transceiver is already asleep * MAC_INVALID_PARAMETER - The specified sleep mode is not supported */ retval_t tal_trx_sleep(sleep_mode_t mode) { tal_trx_status_t trx_status; /* Current transceiver only supports SLEEP_MODE_1 mode. */ if (SLEEP_MODE_1 != mode) { return MAC_INVALID_PARAMETER; } if (tal_trx_status == TRX_SLEEP) { return TAL_TRX_ASLEEP; } /* Device can be put to sleep only when the TAL is in IDLE state. */ if (TAL_IDLE != tal_state) { return TAL_BUSY; } /* * First set trx to TRX_OFF. * If trx is busy, like ACK transmission, do not interrupt it. */ do { trx_status = set_trx_state(CMD_TRX_OFF); } while (trx_status != TRX_OFF); pal_timer_source_select(TMR_CLK_SRC_DURING_TRX_SLEEP); trx_status = set_trx_state(CMD_TRX_SLEEP); if (trx_status == TRX_SLEEP) { return MAC_SUCCESS; } else { /* State could not be set due to TAL_BUSY state. */ return TAL_BUSY; } }
static void handle_tx_end_irq(void) { // Trx has handled the entire transmission incl. CSMA tal_state = TAL_TX_END; // Further handling is done by tx_end_handling() /* * After transmission has finished, switch receiver on again. */ set_trx_state(CMD_RX_ON); }
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 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 Wakes up the transceiver from sleep * * This function awakes the transceiver from sleep state. * * @return TAL_TRX_AWAKE - The transceiver is already awake * MAC_SUCCESS - The transceiver is woken up from sleep * FAILURE - The transceiver did not wake-up from sleep */ retval_t tal_trx_wakeup(void) { tal_trx_status_t trx_status; if (tal_trx_status != TRX_SLEEP) { return TAL_TRX_AWAKE; } #ifdef ENABLE_FTN_PLL_CALIBRATION { retval_t timer_status; /* * Calibration timer has been stopped when going to sleep, * so it needs to be restarted. * All other state changes except via sleep that are ensuring * implicit filter tuning and pll calibration are ignored. * Therefore the calibration timer needs to be restarted for * to those cases. * This is handled in file tal.c. */ /* Start periodic calibration timer.*/ timer_status = pal_timer_start(TAL_CALIBRATION, TAL_CALIBRATION_TIMEOUT_US, TIMEOUT_RELATIVE, (FUNC_PTR)calibration_timer_handler_cb, NULL); if (timer_status != MAC_SUCCESS) { ASSERT("PLL calibration timer start problem" == 0); } } #endif /* ENABLE_FTN_PLL_CALIBRATION */ trx_status = set_trx_state(CMD_TRX_OFF); if (trx_status == TRX_OFF) { pal_timer_source_select(TMR_CLK_SRC_DURING_TRX_AWAKE); return MAC_SUCCESS; } else { return FAILURE; } }
static void generate_rand_seed(void) { uint16_t seed = 0; uint8_t cur_random_val = 0; set_trx_state(CMD_RX_ON); /* * 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(); /* * 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; } 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); CLEAR_TRX_IRQ(); LEAVE_TRX_REGION(); /* Set the seed for the random number generator. */ srand(seed); }
/** * \brief This function is called to initiate the RX_ON test * The transceiver is put into the RX_ON mode and no requests are handled until * this mode is stopped. * On the receptor ,the mode is stopped only on reception of the RX_ON_STOP * command which is sent without ack_req * \param start_stop_param Indicates whether the request is to * Start or Stop the mode */ void rx_on_test(bool start_stop_param) { if(start_stop_param) { if(node_info.main_state != PER_TEST_RECEPTOR) { set_trx_state(CMD_RX_ON); curr_trx_config_params.trx_state = RX_ON ; } /* For receptor the mode is switched on successful transmission of * the confirmation message*/ rx_on_mode = true; } else { set_trx_state(CMD_RX_AACK_ON); curr_trx_config_params.trx_state = RX_AACK_ON ; rx_on_mode = false; } usr_rx_on_confirm(MAC_SUCCESS,start_stop_param); }
void tx_frame_config(void) { tal_trx_status_t trx_status; /* Set trx to PLL_ON state to initiate transmission procedure */ do { trx_status = set_trx_state(CMD_PLL_ON); } while (trx_status != PLL_ON); tal_state = TAL_TX_AUTO; /* Toggle the SLP_TR pin triggering transmission. */ SLP_TR_HIGH(); WAIT_65_NS(); SLP_TR_LOW(); }
/* * \brief handling of CCA result. */ void cca_done_handling(void) { set_trx_state(CMD_PLL_ON); /* leave RX_ON */ /* Restore IRQ handling */ trx_irq_init((FUNC_PTR)trx_irq_handler_cb); trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* Enable frame reception. **/ /* Check if channel was idle or busy */ if (trx_bit_read(SR_CCA_STATUS) == CCA_STATUS_CHANNEL_IS_IDLE) { tx_frame(); } else { tal_state = TAL_CSMA_CONTINUE; } }
/* * \brief Continues CSMA; handles next CSMA retry. */ void csma_continue(void) { NB++; if (NB > tal_pib.MaxCSMABackoffs) { trx_trac_status = TRAC_CHANNEL_ACCESS_FAILURE; tal_state = TAL_TX_DONE; set_trx_state(CMD_RX_AACK_ON); } else { BE++; if (BE > tal_pib.MaxBE) { BE = tal_pib.MaxBE; } /* Start backoff timer to trigger CCA */ start_backoff(); } }
/** * \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. */ 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]) * + 1 extra octet (see datasheet) * - 2 octets FCS */ pal_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 }