/** * Function initializing the Timestamp IRQ to get synchronized * as required for ranging. */ void rtb_tstamp_irq_init(void) { pal_trx_irq_dis(); pal_trx_reg_read(RG_IRQ_STATUS); pal_trx_bit_write(SR_ARET_TX_TS_EN, 0x01); pal_trx_bit_write(SR_IRQ_2_EXT_EN, 0x01); //Enable Timestamping over DIG2 on the at86rf233 PORTC.INTFLAGS = PORT_INT1IF_bm; TCC1_CTRLB &= ~TC1_CCAEN_bm; TIMER_SRC_DURING_TRX_AWAKE(); PORTC.INT1MASK = PIN1_bm; //DIG2 over PortC 1 /* Reset register, until time out is triggered is 65535 ms */ TCC1_CNT = 0; PORTC.PIN1CTRL = PORT_ISC1_bm; TCC1_INTFLAGS = TC1_CCAIF_bm; TCC1_INTCTRLB = TC_CCAINTLVL_HI_gc; TCC1_CTRLB |= TC1_CCAEN_bm; }
/** * \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; }
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 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 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 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 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 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 Sets a TFA PIB attribute * * This function is called to set the transceiver information base * attributes. * * @param[in] tfa_pib_attribute TFA infobase attribute ID * @param[in] value TFA infobase attribute value to be set * * @return MAC_UNSUPPORTED_ATTRIBUTE if the TFA info base attribute is not found * TAL_BUSY if the TAL is not in TAL_IDLE state. * MAC_SUCCESS if the attempt to set the PIB attribute was successful */ retval_t tfa_pib_set(tfa_pib_t tfa_pib_attribute, void *value) { switch (tfa_pib_attribute) { case TFA_PIB_RX_SENS: { uint8_t reg_val; tfa_pib_rx_sens = *((int8_t *)value); if (tfa_pib_rx_sens > -49) { reg_val = 0xF; tfa_pib_rx_sens = -49; } else if (tfa_pib_rx_sens <= RSSI_BASE_VAL_DBM) { reg_val = 0x0; tfa_pib_rx_sens = RSSI_BASE_VAL_DBM; } else { reg_val = ((tfa_pib_rx_sens - (RSSI_BASE_VAL_DBM)) / 3) + 1; } pal_trx_bit_write(SR_RX_PDT_LEVEL, reg_val); } break; default: /* Invalid attribute id */ return MAC_UNSUPPORTED_ATTRIBUTE; } 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) { 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); }
/** * @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 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 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 Reset transceiver * * @return MAC_SUCCESS if the transceiver state is changed to TRX_OFF * FAILURE otherwise */ static retval_t trx_reset(void) { tal_trx_status_t trx_status; uint8_t poll_counter = 0; #if (EXTERN_EEPROM_AVAILABLE == 1) uint8_t xtal_trim_value; #endif /* Get trim value for 16 MHz xtal; needs to be done before reset */ #if (EXTERN_EEPROM_AVAILABLE == 1) pal_ps_get(EXTERN_EEPROM, EE_XTAL_TRIM_ADDR, 1, &xtal_trim_value); #endif /* trx might sleep, so wake it up */ PAL_SLP_TR_LOW(); pal_timer_delay(SLEEP_TO_TRX_OFF_TYP_US); /* Apply reset pulse */ PAL_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); PAL_RST_HIGH(); /* verify that trx has reached TRX_OFF */ do { /* Wait a short time interval. */ pal_timer_delay(TRX_POLL_WAIT_TIME_US); trx_status = (tal_trx_status_t)pal_trx_bit_read(SR_TRX_STATUS); /* Wait not more than max. value of TR2. */ if (poll_counter == SLEEP_TO_TRX_OFF_ATTEMPTS) { #if (DEBUG > 0) pal_alert(); #endif return FAILURE; } poll_counter++; } while (trx_status != TRX_OFF); tal_trx_status = TRX_OFF; // Write 16MHz xtal trim value to trx. // It's only necessary if it differs from the reset value. #if (EXTERN_EEPROM_AVAILABLE == 1) if (xtal_trim_value != 0x00) { pal_trx_bit_write(SR_XTAL_TRIM, xtal_trim_value); } #endif return MAC_SUCCESS; }
/** * @brief 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; 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 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 Reset transceiver */ static retval_t trx_reset(void) { tal_trx_status_t trx_status; uint8_t poll_counter = 0; #if (EXTERN_EEPROM_AVAILABLE == 1) uint8_t xtal_trim_value; #endif /* Get trim value for 16 MHz xtal; needs to be done before reset */ #if (EXTERN_EEPROM_AVAILABLE == 1) pal_ps_get(EXTERN_EEPROM, EE_XTAL_TRIM_ADDR, 1, &xtal_trim_value); #endif /* trx might sleep, so wake it up */ PAL_SLP_TR_LOW(); pal_timer_delay(SLEEP_TO_TRX_OFF_US); PAL_RST_LOW(); pal_timer_delay(RST_PULSE_WIDTH_US); PAL_RST_HIGH(); /* verify that trx has reached TRX_OFF */ do { trx_status = (tal_trx_status_t)pal_trx_bit_read(SR_TRX_STATUS); poll_counter++; if (poll_counter > 250) { #if (_DEBUG_ > 0) Assert( "MAX Attempts to switch to TRX_OFF state reached" == 0); #endif return FAILURE; } } while (trx_status != TRX_OFF); tal_trx_status = TRX_OFF; /* Write 16MHz xtal trim value to trx. */ /* It's only necessary if it differs from the reset value. */ #if (EXTERN_EEPROM_AVAILABLE == 1) if (xtal_trim_value != 0x00) { pal_trx_bit_write(SR_XTAL_TRIM, xtal_trim_value); } #endif return MAC_SUCCESS; }
/* * \brief 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; } }
/** * @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 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 Apply channel page configuartion to transceiver * * @param ch_page Channel page * * @return true if changes could be applied else false */ static bool apply_channel_page_configuration(uint8_t ch_page) { /* * Before updating the transceiver a number of TAL PIB attributes need * to be updated depending on the channel page. */ tal_pib.MaxFrameDuration = MAX_FRAME_DURATION; tal_pib.SHRDuration = NO_OF_SYMBOLS_PREAMBLE_SFD; tal_pib.SymbolsPerOctet = SYMBOLS_PER_OCTET; switch (ch_page) { case 0: /* compliant O-QPSK */ pal_trx_bit_write(SR_OQPSK_DATA_RATE, ALTRATE_250_KBPS); // Apply compliant ACK timing pal_trx_bit_write(SR_AACK_ACK_TIME, ACK_TIME_12_SYMBOLS); break; case 2: /* non-compliant OQPSK mode 1 */ pal_trx_bit_write(SR_OQPSK_DATA_RATE, ALTRATE_500_KBPS); // Apply reduced ACK timing pal_trx_bit_write(SR_AACK_ACK_TIME, ACK_TIME_2_SYMBOLS); break; case 16: /* non-compliant OQPSK mode 2 */ pal_trx_bit_write(SR_OQPSK_DATA_RATE, ALTRATE_1_MBPS); // Apply reduced ACK timing pal_trx_bit_write(SR_AACK_ACK_TIME, ACK_TIME_2_SYMBOLS); break; case 17: /* non-compliant OQPSK mode 3 */ pal_trx_bit_write(SR_OQPSK_DATA_RATE, ALTRATE_2_MBPS); // Apply reduced ACK timing pal_trx_bit_write(SR_AACK_ACK_TIME, ACK_TIME_2_SYMBOLS); break; default: return false; } return true; }
/* * \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(); }
static void trx_config(void) { /* Set pin driver strength */ pal_trx_bit_write(SR_PAD_IO_CLKM, PAD_CLKM_2_MA); pal_trx_bit_write(SR_CLKM_SHA_SEL, CLKM_SHA_DISABLE); pal_trx_bit_write(SR_CLKM_CTRL, CLKM_1MHZ); /* ACKs for data requests, indicate pending data */ pal_trx_bit_write(SR_AACK_SET_PD, SET_PD); /* Enable buffer protection mode */ pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_ENABLE); /* Enable poll mode */ pal_trx_bit_write(SR_IRQ_MASK_MODE, IRQ_MASK_MODE_ON); /* The TRX_END interrupt of the transceiver is enabled. */ pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); }
/** * @brief Filter tuning calibration implementation */ static void do_ftn_calibration(void) { pal_trx_bit_write(SR_FTN_START, 1); /* Wait tTR16 (FTN calibration time). */ pal_timer_delay(25); }
/** * @brief Sets transceiver state * * @param trx_cmd needs to be one of the trx commands * * @return current trx state */ tal_trx_status_t set_trx_state(trx_cmd_t trx_cmd) { if (tal_trx_status == TRX_SLEEP) { /* * Since the wake-up procedure relies on the Awake IRQ and * the global interrupts may be disabled at this point of time, * we need to make sure that the global interrupts are enabled * during wake-up procedure. * Once the TRX is awake, the original state of the global interrupts * will be restored. */ /* Reset wake-up interrupt flag. */ tal_awake_end_flag = false; /* Set callback function for the awake interrupt. */ pal_trx_irq_init(trx_irq_awake_handler_cb); /* The pending transceiver interrupts on the microcontroller are cleared. */ pal_trx_irq_flag_clr(); pal_trx_irq_en(); /* Enable transceiver main interrupt. */ /* Save current state of global interrupts. */ ENTER_CRITICAL_REGION(); /* Force enabling of global interrupts. */ ENABLE_GLOBAL_IRQ(); /* Leave trx sleep mode. */ PAL_SLP_TR_LOW(); /* Poll wake-up interrupt flag until set within ISR. */ while (!tal_awake_end_flag); /* Restore original state of global interrupts. */ LEAVE_CRITICAL_REGION(); /* Clear existing interrupts */ pal_trx_reg_read(RG_IRQ_STATUS); /* Re-install default IRQ handler for main interrupt. */ pal_trx_irq_init(trx_irq_handler_cb); /* Re-enable TRX_END interrupt */ pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); #if (ANTENNA_DIVERSITY == 1) /* Enable antenna diversity. */ pal_trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE); #endif #ifdef EXT_RF_FRONT_END_CTRL /* Enable RF front end control */ pal_trx_bit_write(SR_PA_EXT_EN, 1); #endif tal_trx_status = TRX_OFF; if ((trx_cmd == CMD_TRX_OFF) || (trx_cmd == CMD_FORCE_TRX_OFF)) { return TRX_OFF; } } #ifdef ENABLE_DEEP_SLEEP else if (tal_trx_status == TRX_DEEP_SLEEP) { /* Leave trx sleep mode. */ PAL_SLP_TR_LOW(); /* Check if trx has left deep sleep. */ tal_trx_status_t trx_state; do { trx_state = (tal_trx_status_t)pal_trx_reg_read(RG_TRX_STATUS); } while (trx_state != TRX_OFF); tal_trx_status = TRX_OFF; /* Using deep sleep, the transceiver's registers need to be restored. */ trx_config(); /* * Write all PIB values to the transceiver * that are needed by the transceiver itself. */ write_all_tal_pib_to_trx(); /* implementation can be found in 'tal_pib.c' */ if ((trx_cmd == CMD_TRX_OFF) || (trx_cmd == CMD_FORCE_TRX_OFF)) { return TRX_OFF; } } #endif switch (trx_cmd) /* requested state */ { case CMD_SLEEP: #ifdef ENABLE_DEEP_SLEEP /* Fall through. */ case CMD_DEEP_SLEEP: #endif pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); #if (ANTENNA_DIVERSITY == 1) /* * Disable antenna diversity: to reduce the power consumption or * avoid leakage current of an external RF switch during SLEEP. */ pal_trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_DISABLE); #endif #ifdef EXT_RF_FRONT_END_CTRL /* Disable RF front end control */ pal_trx_bit_write(SR_PA_EXT_EN, 0); #endif /* Clear existing interrupts */ pal_trx_reg_read(RG_IRQ_STATUS); /* * Enable Awake_end interrupt. * This is used for save wake-up from sleep later. */ pal_trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); #ifdef ENABLE_DEEP_SLEEP if (trx_cmd == CMD_DEEP_SLEEP) { pal_trx_reg_write(RG_TRX_STATE, CMD_PREP_DEEP_SLEEP); tal_trx_status = TRX_DEEP_SLEEP; } else { /* * Enable Awake_end interrupt. * This is used for save wake-up from sleep later. */ pal_trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); tal_trx_status = TRX_SLEEP; } #else /* * Enable Awake_end interrupt. * This is used for save wake-up from sleep later. */ pal_trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); tal_trx_status = TRX_SLEEP; #endif PAL_WAIT_1_US(); PAL_SLP_TR_HIGH(); pal_timer_delay(TRX_OFF_TO_SLEEP_TIME_CLKM_CYCLES); /* Transceiver register cannot be read during TRX_SLEEP or DEEP_SLEEP. */ return tal_trx_status; case CMD_TRX_OFF: switch (tal_trx_status) { case TRX_OFF: break; default: pal_trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); PAL_WAIT_1_US(); break; } break; case CMD_FORCE_TRX_OFF: switch (tal_trx_status) { case TRX_OFF: break; default: pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); PAL_WAIT_1_US(); break; } break; case CMD_PLL_ON: switch (tal_trx_status) { case PLL_ON: break; case TRX_OFF: switch_pll_on(); break; case RX_ON: case RX_AACK_ON: case TX_ARET_ON: pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: ASSERT("state transition not handled" == 0); break; } break; case CMD_FORCE_PLL_ON: switch (tal_trx_status) { case TRX_OFF: switch_pll_on(); break; case PLL_ON: break; default: pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_PLL_ON); break; } break; case CMD_RX_ON: switch (tal_trx_status) { case RX_ON: break; case PLL_ON: case RX_AACK_ON: case TX_ARET_ON: pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: ASSERT("state transition not handled" == 0); break; } break; case CMD_RX_AACK_ON: switch (tal_trx_status) { case RX_AACK_ON: break; case TX_ARET_ON: case PLL_ON: case RX_ON: pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); // state change from TRX_OFF to RX_AACK_ON can be done directly, too pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: ASSERT("state transition not handled" == 0); break; } break; case CMD_TX_ARET_ON: switch (tal_trx_status) { case TX_ARET_ON: break; case PLL_ON: case RX_ON: case RX_AACK_ON: pal_trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); // state change from TRX_OFF to TX_ARET_ON can be done directly, too pal_trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: ASSERT("state transition not handled" == 0); break; } break; default: /* CMD_NOP, CMD_TX_START */ ASSERT("trx command not handled" == 0); break; } do { tal_trx_status = (tal_trx_status_t)pal_trx_bit_read(SR_TRX_STATUS); } while (tal_trx_status == STATE_TRANSITION_IN_PROGRESS); return tal_trx_status; } /* set_trx_state() */
/* * \brief Handle received frame interrupt * * This function handles transceiver interrupts for received frames and * uploads the frames from the trx. */ void handle_received_frame_irq(void) { uint8_t ed_value; /* Actual frame length of received frame. */ uint8_t phy_frame_len; /* Extended frame length appended by LQI and ED. */ uint8_t ext_frame_length; frame_info_t *receive_frame; uint8_t *frame_ptr; if (tal_rx_buffer == NULL) { Assert("no tal_rx_buffer available" == 0); /* * Although the buffer protection mode is enabled and the receiver has * been switched to PLL_ON, the next incoming frame was faster. * It cannot be handled and is discarded. */ pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_DISABLE); /* Disable buffer protection mode */ pal_timer_delay(2); // Allow pin change to get effective pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_ENABLE); /* Enable buffer protection mode */ return; } receive_frame = (frame_info_t *)BMM_BUFFER_POINTER(tal_rx_buffer); #ifdef PROMISCUOUS_MODE if (tal_pib.PromiscuousMode) { /* Check for valid FCS */ if (pal_trx_bit_read(SR_RX_CRC_VALID) == CRC16_NOT_VALID) { return; } } #endif /* Get ED value; needed to normalize LQI. */ ed_value = pal_trx_reg_read(RG_PHY_ED_LEVEL); /* Get frame length from transceiver. */ phy_frame_len = ext_frame_length = pal_trx_reg_read(RG_TST_RX_LENGTH); /* Check for valid frame length. */ if (phy_frame_len > 127) { return; } /* * The PHY header is also included in the frame (length field), hence the frame length * is incremented. * In addition to that, the LQI and ED value are uploaded, too. */ ext_frame_length += LQI_LEN + ED_VAL_LEN; /* Update payload pointer to store received frame. */ frame_ptr = (uint8_t *)receive_frame + LARGE_BUFFER_SIZE - ext_frame_length; /* * Note: The following code is different from other non-single chip * transceivers, where reading the frame via SPI contains the length field * in the first octet. */ pal_trx_frame_read(frame_ptr, phy_frame_len + LQI_LEN); frame_ptr--; *frame_ptr = phy_frame_len; receive_frame->mpdu = frame_ptr; /* Add ED value at the end of the frame buffer. */ receive_frame->mpdu[phy_frame_len + LQI_LEN + ED_VAL_LEN] = ed_value; #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) /* * Store the timestamp. * The timestamping is only required for beaconing networks * or if timestamping is explicitly enabled. */ receive_frame->time_stamp = tal_rx_timestamp; #endif /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */ /* Append received frame to incoming_frame_queue and get new rx buffer. */ qmm_queue_append(&tal_incoming_frame_queue, tal_rx_buffer); /* The previous buffer is eaten up and a new buffer is not assigned yet. */ tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE); /* Check if receive buffer is available */ if (NULL == tal_rx_buffer) { /* * Turn off the receiver until a buffer is available again. * tal_task() will take care of eventually reactivating it. * Due to ongoing ACK transmission do not force to switch it off. */ /* Do not change the state since buffer protection mode is not re-enabled yet. * Buffer protection will be re-enabled after buffer becomes available */ //set_trx_state(CMD_PLL_ON); tal_rx_on_required = true; } else { /* * Trx returns to RX_AACK_ON automatically, if this was its previous state. * Keep the following as a reminder, if receiver is used with RX_ON instead. */ //pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); /* * Release the protected buffer and set it again for further protection since * the buffer is available */ pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_DISABLE); /* Disable buffer protection mode */ pal_timer_delay(2); // Allow pin change to get effective pal_trx_bit_write(SR_RX_SAFE_MODE, RX_SAFE_MODE_ENABLE); /* Enable buffer protection mode */ } /* * Clear pending TX_END IRQ: The TX_END IRQ is envoked for the transmission * end of an automatically sent ACK frame. This implementation does not use * this feature. */ pal_trx_irq_flag_clr_tx_end(); }
/* * \brief Sets a TAL PIB attribute * * This function is called to set the transceiver information base * attributes. * * \param attribute TAL infobase attribute ID * \param value TAL infobase attribute value to be set * * \return MAC_UNSUPPORTED_ATTRIBUTE if the TAL info base attribute is not found * TAL_BUSY if the TAL is not in TAL_IDLE state. An exception is * macBeaconTxTime which can be accepted by TAL even if TAL is not * in TAL_IDLE state. * MAC_SUCCESS if the attempt to set the PIB attribute was successful * TAL_TRX_ASLEEP if trx is in SLEEP mode and access to trx is required */ retval_t tal_pib_set(uint8_t attribute, pib_value_t *value) { /* * Do not allow any changes while ED or TX is done. * We allow changes during RX, but it's on the user's own risk. */ #if (MAC_SCAN_ED_REQUEST_CONFIRM == 1) if (tal_state == TAL_ED) { Assert("TAL is busy" == 0); return TAL_BUSY; } #endif /* (MAC_SCAN_ED_REQUEST_CONFIRM == 1) */ /* * Distinguish between PIBs that need to be changed in trx directly * and those that are simple variable udpates. * Ensure that the transceiver is not in SLEEP. * If it is in SLEEP, change it to TRX_OFF. * For all other state force TRX_OFF. * Abort any TAL_BUSY state, because the change might have an impact to * ongoing transactions. */ switch (attribute) { case macMaxFrameRetries: /* * The new PIB value is not immediately written to the * transceiver. This is done on a frame-by-frame base. */ tal_pib.MaxFrameRetries = value->pib_value_8bit; break; case macMaxCSMABackoffs: /* * The new PIB value is not immediately written to the * transceiver. This is done on a frame-by-frame base. */ tal_pib.MaxCSMABackoffs = value->pib_value_8bit; break; #ifdef BEACON_SUPPORT case macBattLifeExt: tal_pib.BattLifeExt = value->pib_value_bool; break; case macBeaconOrder: tal_pib.BeaconOrder = value->pib_value_8bit; break; case macSuperframeOrder: tal_pib.SuperFrameOrder = value->pib_value_8bit; break; case macBeaconTxTime: tal_pib.BeaconTxTime = value->pib_value_32bit; break; #endif /* BEACON_SUPPORT */ #ifdef PROMISCUOUS_MODE case macPromiscuousMode: tal_pib.PromiscuousMode = value->pib_value_8bit; if (tal_pib.PromiscuousMode) { tal_trx_wakeup(); /* Check if receive buffer is available or queue is not *full. */ if (NULL == tal_rx_buffer) { set_trx_state(CMD_PLL_ON); tal_rx_on_required = true; } else { set_trx_state(CMD_RX_ON); } } else { set_trx_state(CMD_TRX_OFF); tal_rx_on_required = false; } break; #endif default: /* * Following PIBs require access to trx. * Therefore trx must be at least in TRX_OFF. */ if (tal_trx_status == TRX_SLEEP) { /* While trx is in SLEEP, register cannot be accessed. **/ return TAL_TRX_ASLEEP; } switch (attribute) { case macMinBE: tal_pib.MinBE = value->pib_value_8bit; #ifndef REDUCED_PARAM_CHECK /* * macMinBE must not be larger than macMaxBE or *calculation * of macMaxFrameWaitTotalTime will fail. */ if (tal_pib.MinBE > tal_pib.MaxBE) { tal_pib.MinBE = tal_pib.MaxBE; } #endif /* REDUCED_PARAM_CHECK */ pal_trx_bit_write(SR_MIN_BE, tal_pib.MinBE); break; case macPANId: tal_pib.PANId = value->pib_value_16bit; uint8_t *ptr_pan; ptr_pan = (uint8_t *)&tal_pib.PANId; for (uint8_t i = 0; i < 2; i++) { pal_trx_reg_write((RG_PAN_ID_0 + i), *ptr_pan); ptr_pan++; } break; case macShortAddress: tal_pib.ShortAddress = value->pib_value_16bit; uint8_t *ptr_shrt; ptr_shrt = (uint8_t *)&tal_pib.ShortAddress; for (uint8_t i = 0; i < 2; i++) { pal_trx_reg_write((RG_SHORT_ADDR_0 + i), *ptr_shrt); ptr_shrt++; } break; case phyCurrentChannel: if (tal_state != TAL_IDLE) { return TAL_BUSY; } if ((uint32_t)TRX_SUPPORTED_CHANNELS & ((uint32_t)0x01 << value->pib_value_8bit)) { tal_trx_status_t previous_trx_status = TRX_OFF; /* * Set trx to "soft" off avoiding that ongoing * transaction (e.g. ACK) are interrupted. */ if (tal_trx_status != TRX_OFF) { previous_trx_status = RX_AACK_ON; /* any *other *than *TRX_OFF *state **/ do { /* set TRX_OFF until it could be * set; * trx might be busy */ } while (set_trx_state(CMD_TRX_OFF) != TRX_OFF); } tal_pib.CurrentChannel = value->pib_value_8bit; pal_trx_bit_write(SR_CHANNEL, tal_pib.CurrentChannel); /* Re-store previous trx state */ if (previous_trx_status != TRX_OFF) { /* Set to default state */ set_trx_state(CMD_RX_AACK_ON); } } else { return MAC_INVALID_PARAMETER; } break; case phyCurrentPage: if (tal_state != TAL_IDLE) { return TAL_BUSY; } else { uint8_t page; page = value->pib_value_8bit; if (page != 0) { return MAC_INVALID_PARAMETER; } } break; case macMaxBE: tal_pib.MaxBE = value->pib_value_8bit; #ifndef REDUCED_PARAM_CHECK /* * macMinBE must not be larger than macMaxBE or *calculation * of macMaxFrameWaitTotalTime will fail. */ if (tal_pib.MaxBE < tal_pib.MinBE) { tal_pib.MinBE = tal_pib.MaxBE; } #endif /* REDUCED_PARAM_CHECK */ break; case phyTransmitPower: { uint8_t reg_value; tal_pib.TransmitPower = value->pib_value_8bit; /* Limit tal_pib.TransmitPower to max/min trx values */ tal_pib.TransmitPower = limit_tx_pwr( tal_pib.TransmitPower); reg_value = convert_phyTransmitPower_to_reg_value( tal_pib.TransmitPower); pal_trx_bit_write(SR_TX_PWR, reg_value); } break; case phyCCAMode: tal_pib.CCAMode = value->pib_value_8bit; pal_trx_bit_write(SR_CCA_MODE, tal_pib.CCAMode); break; case macIeeeAddress: { uint8_t *ptr; tal_pib.IeeeAddress = value->pib_value_64bit; ptr = (uint8_t *)&tal_pib.IeeeAddress; for (uint8_t i = 0; i < 8; i++) { pal_trx_reg_write((RG_IEEE_ADDR_0 + i), *ptr); ptr++; } } break; case mac_i_pan_coordinator: tal_pib.PrivatePanCoordinator = value->pib_value_bool; pal_trx_bit_write(SR_I_AM_COORD, tal_pib.PrivatePanCoordinator); break; case macAckWaitDuration: /* AT86RF230B does not support changing this value */ return MAC_UNSUPPORTED_ATTRIBUTE; default: return MAC_UNSUPPORTED_ATTRIBUTE; } break; /* end of 'default' from 'switch (attribute)' */ } return MAC_SUCCESS; } /* tal_pib_set() */
/** * @brief Get the transceiver's supply voltage * * @return mv Milli Volt; 0 if below threshold, 0xFFFF if above threshold */ uint16_t tfa_get_batmon_voltage(void) { tal_trx_status_t previous_trx_status; uint8_t vth_val; uint8_t i; uint16_t mv = 1; // 1 used as indicator flag bool range; previous_trx_status = tal_trx_status; if (tal_trx_status == TRX_SLEEP) { set_trx_state(CMD_TRX_OFF); } /* * Disable all trx interrupts. * This needs to be done AFTER the transceiver has been woken up. */ pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_NONE); /* Check if supply voltage is within lower range */ pal_trx_bit_write(SR_BATMON_HR, BATMON_LOW_RANGE); pal_trx_bit_write(SR_BATMON_VTH, 0x0F); pal_timer_delay(5); /* Wait until Batmon has been settled. */ if (pal_trx_bit_read(SR_BATMON_OK) == BATMON_BELOW_THRES) { /* Lower range */ /* Check if supply voltage is below lower limit */ pal_trx_bit_write(SR_BATMON_VTH, 0); pal_timer_delay(2); /* Wait until Batmon has been settled. */ if (pal_trx_bit_read(SR_BATMON_OK) == BATMON_BELOW_THRES) { /* below lower limit */ mv = SUPPLY_VOLTAGE_BELOW_LOWER_LIMIT; } range = LOW; } else { /* Higher range */ pal_trx_bit_write(SR_BATMON_HR, BATMON_HIGH_RANGE); /* Check if supply voltage is above upper limit */ pal_trx_bit_write(SR_BATMON_VTH, 0x0F); pal_timer_delay(5); /* Wait until Batmon has been settled. */ if (pal_trx_bit_read(SR_BATMON_OK) == BATMON_ABOVE_THRES) { /* above upper limit */ mv = SUPPLY_VOLTAGE_ABOVE_UPPER_LIMIT; } range = HIGH; } /* Scan through the current range for the matching threshold. */ if (mv == 1) { vth_val = 0x0F; for (i = 0; i < 16; i++) { pal_trx_bit_write(SR_BATMON_VTH, i); pal_timer_delay(2); /* Wait until Batmon has been settled. */ if (pal_trx_bit_read(SR_BATMON_OK) == BATMON_BELOW_THRES) { if (i > 0) { vth_val = i - 1; } else { vth_val = i; } break; } } if (range == HIGH) { mv = 2550 + (75 * vth_val); } else { mv = 1700 + (50 * vth_val); } } pal_trx_reg_read(RG_IRQ_STATUS); /* Clear all pending interrupts. */ pal_trx_irq_flag_clr_rx_end(); pal_trx_irq_flag_clr_tx_end(); pal_trx_irq_flag_clr_tstamp(); /* * Enable all trx interrupts. * This needs to be done BEFORE putting the transceiver back to slee. */ pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); if (previous_trx_status == TRX_SLEEP) { set_trx_state(CMD_SLEEP); } return mv; }
/** * @brief Sets a TAL PIB attribute * * This function is called to set the transceiver information base * attributes. * * @param attribute TAL infobase attribute ID * @param value TAL infobase attribute value to be set * * @return MAC_UNSUPPORTED_ATTRIBUTE if the TAL info base attribute is not found * TAL_BUSY if the TAL is not in TAL_IDLE state. An exception is * macBeaconTxTime which can be accepted by TAL even if TAL is not * in TAL_IDLE state. * MAC_SUCCESS if the attempt to set the PIB attribute was successful * TAL_TRX_ASLEEP if trx is in SLEEP mode and access to trx is required */ retval_t tal_pib_set(uint8_t attribute, pib_value_t *value) { /* * Distinguish between PIBs that need to be changed in trx directly * and those that are simple variable udpates. * Ensure that the transceiver is not in SLEEP. * If it is in SLEEP, change it to TRX_OFF. */ switch (attribute) { case macMaxFrameRetries: /* * The new PIB value is not immediately written to the * transceiver. This is done on a frame-by-frame base. */ tal_pib_MaxFrameRetries = value->pib_value_8bit; break; case macMaxCSMABackoffs: /* * The new PIB value is not immediately written to the * transceiver. This is done on a frame-by-frame base. */ tal_pib_MaxCSMABackoffs = value->pib_value_8bit; break; default: /* * Following PIBs require access to trx. * Therefore trx must be at least in TRX_OFF. */ if (tal_trx_status == TRX_SLEEP) { /* While trx is in SLEEP, register cannot be accessed. */ return TAL_TRX_ASLEEP; } switch (attribute) { case macMinBE: tal_pib_MinBE = value->pib_value_8bit; pal_trx_bit_write(SR_MIN_BE, tal_pib_MinBE); break; case macPANId: tal_pib_PANId = value->pib_value_16bit; 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)); break; case macShortAddress: tal_pib_ShortAddress = value->pib_value_16bit; 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)); break; case phyCurrentChannel: if (tal_state != TAL_IDLE) { return TAL_BUSY; } if ((uint32_t)TRX_SUPPORTED_CHANNELS & ((uint32_t)0x01 << value->pib_value_8bit)) { tal_trx_status_t previous_trx_status = TRX_OFF; /* * Set trx to "soft" off avoiding that ongoing * transaction (e.g. ACK) are interrupted. */ if (tal_trx_status != TRX_OFF) { previous_trx_status = RX_AACK_ON; /* any other than TRX_OFF state */ do { /* set TRX_OFF until it could be set; * trx might be busy */ } while (set_trx_state(CMD_TRX_OFF) != TRX_OFF); } tal_pib_CurrentChannel = value->pib_value_8bit; pal_trx_bit_write(SR_CHANNEL, tal_pib_CurrentChannel); /* Re-store previous trx state */ if (previous_trx_status != TRX_OFF) { /* Set to default state */ set_trx_state(CMD_RX_AACK_ON); } } else { return MAC_INVALID_PARAMETER; } break; case phyCurrentPage: #ifdef HIGH_DATA_RATE_SUPPORT if (tal_state != TAL_IDLE) { return TAL_BUSY; } else { uint8_t page; tal_trx_status_t previous_trx_status = TRX_OFF; bool ret_val; /* * Changing the channel, channel page or modulation * requires that TRX is in TRX_OFF. * Store current trx state and return to default state * after channel page has been set. */ if (tal_trx_status != TRX_OFF) { previous_trx_status = RX_AACK_ON; /* any other than TRX_OFF state */ do { /* set TRX_OFF until it could be set; * trx might be busy */ } while (set_trx_state(CMD_TRX_OFF) != TRX_OFF); } page = value->pib_value_8bit; ret_val = apply_channel_page_configuration(page); if (previous_trx_status != TRX_OFF) { /* Set to default state */ set_trx_state(CMD_RX_AACK_ON); } if (ret_val) { tal_pib_CurrentPage = page; } else { return MAC_INVALID_PARAMETER; } } #else if (tal_state != TAL_IDLE) { return TAL_BUSY; } else { uint8_t page; page = value->pib_value_8bit; if (page != 0) { return MAC_INVALID_PARAMETER; } } #endif /* #ifdef HIGH_DATA_RATE_SUPPORT */ break; case macMaxBE: tal_pib_MaxBE = value->pib_value_8bit; pal_trx_bit_write(SR_MAX_BE, tal_pib_MaxBE); break; case phyTransmitPower: { uint8_t reg_value; tal_pib_TransmitPower = value->pib_value_8bit; /* Limit tal_pib_TransmitPower to max/min trx values */ tal_pib_TransmitPower = limit_tx_pwr(tal_pib_TransmitPower); reg_value = convert_phyTransmitPower_to_reg_value(tal_pib_TransmitPower); pal_trx_bit_write(SR_TX_PWR, reg_value); } break; case phyCCAMode: tal_pib_CCAMode = value->pib_value_8bit; pal_trx_bit_write(SR_CCA_MODE, tal_pib_CCAMode); break; case macIeeeAddress: { uint8_t *ptr; tal_pib_IeeeAddress = value->pib_value_64bit; ptr = (uint8_t *)&tal_pib_IeeeAddress; for (uint8_t i = 0; i < 8; i++) { pal_trx_reg_write((RG_IEEE_ADDR_0 + i), *ptr); ptr++; } } break; case mac_i_pan_coordinator: tal_pib_PrivatePanCoordinator = value->pib_value_bool; pal_trx_bit_write(SR_AACK_I_AM_COORD, tal_pib_PrivatePanCoordinator); break; case macAckWaitDuration: /* * ATmega128RFA1 does not support changing this value w.r.t. * compliance operation. * The ACK timing can be reduced to 2 symbols using TFA function. */ return MAC_UNSUPPORTED_ATTRIBUTE; default: return MAC_UNSUPPORTED_ATTRIBUTE; } break; /* end of 'default' from 'switch (attribute)' */ } return MAC_SUCCESS; } /* tal_pib_set() */