/** * @brief Resets TAL state machine and sets the default PIB values if requested * * @param set_default_pib Defines whether PIB values need to be set * to its default values * * @return MAC_SUCCESS if the transceiver state is changed to TRX_OFF * FAILURE otherwise */ retval_t tal_reset(bool set_default_pib) { /* * Do the reset stuff. * Set the default PIBs depending on the given parameter set_default_pib. * Do NOT generate random seed again. */ if (internal_tal_reset(set_default_pib) != MAC_SUCCESS) { return FAILURE; } #if (NUMBER_OF_TAL_TIMERS > 0) /* Clear all running TAL timers. */ { uint8_t timer_id; ENTER_CRITICAL_REGION(); for (timer_id = TAL_FIRST_TIMER_ID; timer_id <= TAL_LAST_TIMER_ID; timer_id++) { pal_timer_stop(timer_id); } LEAVE_CRITICAL_REGION(); } #endif /* Clear TAL Incoming Frame queue and free used buffers. */ while (tal_incoming_frame_queue.size > 0) { buffer_t *frame = qmm_queue_remove(&tal_incoming_frame_queue, NULL); if (NULL != frame) { bmm_buffer_free(frame); } } #ifdef ENABLE_TFA tfa_reset(set_default_pib); #endif /* * Configure interrupt handling. Clear all pending interrupts. * Handlers have been installed in tal_init(), and are never * uninstalled. */ pal_trx_irq_flag_clr_rx_end(); pal_trx_irq_flag_clr_tx_end(); #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) pal_trx_irq_flag_clr_tstamp(); #endif /* (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */ pal_trx_irq_flag_clr_awake(); /* * 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(); #ifdef ENABLE_FTN_PLL_CALIBRATION { /* Handle PLL calibration and filter tuning. */ retval_t timer_status; /* Calibration timer has already been stopped within this function. */ /* 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 */ #ifdef STB_ON_SAL stb_restart(); #endif return MAC_SUCCESS; }
/** * @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 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 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; /* Disable all trx interrupts */ pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_NONE); previous_trx_status = tal_trx_status; if (tal_trx_status == TRX_SLEEP) { set_trx_state(CMD_TRX_OFF); } /* Check if supply voltage is within lower range */ pal_trx_bit_write(SR_BATMON_HR, HIGH_RANGE_DISABLED); 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_NOT_VALID) { /* 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_NOT_VALID) { /* below lower limit */ mv = 0x0000; } range = LOW; } else { /* Higher range */ pal_trx_bit_write(SR_BATMON_HR, HIGH_RANGE_ENABLED); /* 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_VALID) { /* above upper limit */ mv = 0xFFFF; } 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_NOT_VALID) { 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); if (previous_trx_status == TRX_SLEEP) { set_trx_state(CMD_SLEEP); } /* 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 */ pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); return mv; }