/** * DCI handler init */ void drDcihInit( const addr_t dciBuffer, const uint32_t dciBufferLen ){ /* Ensure thread stack is clean */ clearStack( drDcihStack ); /* DCI message buffer */ message = (dciMessage_t*) dciBuffer; /** * Update DCI handler thread so that notifications will be delivered * to DCI handler thread */ if (DRAPI_OK != drUtilsUpdateNotificationThread( DRIVER_THREAD_NO_DCIH )) { drDbgPrintLnf("[Driver DrTemplate] drDcihInit(): Updating notification thread failed"); } /** * Start DCI handler thread. EXH thread becomes local * exception handler of DCIH thread */ if (DRAPI_OK != drApiStartThread( DRIVER_THREAD_NO_DCIH, FUNC_PTR(drDcih), getStackTop(drDcihStack), DCIH_PRIORITY, DRIVER_THREAD_NO_EXCH)) { drDbgPrintLnf("[Driver DrTemplate] drDcihInit(): drApiStartThread failed"); } }
/* * @brief Set the transceiver state to PHY_TRX_OFF * * This actually turns the radio receiver off - i.e. this is the end * of the PHY_RX_ON period. * * @param callback_parameter Callback parameter */ static void mac_t_rx_off_cb(void *callback_parameter) { uint8_t status; /* * Rx is disabled. * This will make sure that the radio will be put to sleep in function * mac_sleep_trans(). */ mac_rx_enabled = false; /* * In case macRxOnWhenIdle is not set, the radio is put to PHY_TRX_OFF * state, until the return status does not match the desired radio state, * i.e. PHY_TRX_OFF */ if (!mac_pib.mac_RxOnWhenIdle) { /* * In case the radio is awake, we need to switch RX off. */ if (RADIO_AWAKE == mac_radio_sleep_state) { status = tal_rx_enable(PHY_TRX_OFF); if (status != PHY_TRX_OFF) { /* * The TAL is still busy and cannot set the TRX to OFF. * In order to get progress this requires another * round of the TAL task being processed. * Therefore the MAC task needs to stopp here and pass * controll back to the TAL. * This is reached by starting the Rx-Enable timer again * for a very short time with the same callback returning * here very soon. */ pal_timer_start(T_Rx_Enable, MIN_TIMEOUT, TIMEOUT_RELATIVE, (FUNC_PTR())mac_t_rx_off_cb, NULL); /* * Return now, since the TAL is still busy, so radio cannot go * to sleep for now. */ return; } else { /* Set radio to sleep if allowed */ mac_sleep_trans(); } } } callback_parameter = callback_parameter; /* Keep compiler happy. */ }
/* * @brief Internal function to handle immediate RX_ON * * This function immediately enables the receiver with the given * RxOnDuration time in symbols from now. * * @param rx_on_duration_symbols Duration in symbols that the reciever is * switched on. */ static void handle_rx_on(uint32_t rx_on_duration_symbols, uint8_t *m) { retval_t timer_status; uint8_t rx_enable_status = mac_rx_enable(); /* * TODO: Once it is possible to restart a timer even if it is * already running, this could be improved by simply calling * function pal_timer_start() without this previous check using * function pal_is_timer_running(). */ if (pal_is_timer_running(T_Rx_Enable)) { /* * Rx-Enable timer is already running, so we need to stopp it first * before it will be started. */ pal_timer_stop(T_Rx_Enable); } /* * Start timer for the Rx On duration of the radio being on * in order to switch it off later again. */ timer_status = pal_timer_start(T_Rx_Enable, TAL_CONVERT_SYMBOLS_TO_US(rx_on_duration_symbols), TIMEOUT_RELATIVE, (FUNC_PTR())mac_t_rx_off_cb, NULL); ASSERT(MAC_SUCCESS == timer_status); /* * Send the confirm immediately depending on the status of * the timer start and the Rx Status */ if (MAC_SUCCESS != timer_status) { gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_INVALID_PARAMETER); /* Do house-keeeping and turn radio off. */ mac_t_rx_off_cb(NULL); } else if (PHY_RX_ON != rx_enable_status) { gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_TX_ACTIVE); } else { gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_SUCCESS); } return; }
/** * @brief PLL calibration and filter tuning timer callback * * @param parameter Unused callback parameter */ void calibration_timer_handler_cb(void *parameter) { retval_t timer_status; handle_ftn_pll_calibration(); /* Restart periodic calibration timer again. */ 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); } parameter = parameter; /* Keep compiler happy. */ }
/** * @brief Implement the MLME-RX-ENABLE.request primitive. * * The MLME-RX-ENABLE.request primitive is generated by the next * higher layer and issued to MAC to enable the receiver for a * fixed duration, at a time relative to the start of the current or * next superframe on a beacon-enabled PAN or immediately on a * nonbeacon-enabled PAN. The receiver is enabled exactly once per * primitive request. * * @param m Pointer to the MLME-RX-ENABLE.request message */ void mlme_rx_enable_request(uint8_t *m) { mlme_rx_enable_req_t *rxe; rxe = (mlme_rx_enable_req_t *)BMM_BUFFER_POINTER((buffer_t *)m); /* If RxOnDuration is zero, the receiver shall be disabled */ if (0 == rxe->RxOnDuration) { /* * Turn the radio off. This is doney by calling the * same function as for the expiration of the Rx on timer. */ mac_t_rx_off_cb(NULL); /* Send the confirm immediately. */ gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_SUCCESS); return; } /* * Reject the request when the MAC is currently in any of the * polling states or scanning. */ if ((MAC_POLL_IDLE != mac_poll_state) || (MAC_SCAN_IDLE != mac_scan_state) ) { /* Send the confirm immediately. */ gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_TX_ACTIVE); return; } #ifdef BEACON_SUPPORT if (NON_BEACON_NWK == tal_pib.BeaconOrder) { handle_rx_on(rxe->RxOnDuration, m); } else { /* We have a beacon-enabled network. */ uint32_t curr_beacon_int_time_symbols = TAL_GET_BEACON_INTERVAL_TIME(tal_pib.BeaconOrder); uint32_t now_time_symbols; uint32_t symbols_since_beacon; uint32_t rx_on_time_symbols; retval_t timer_status; /* * Determine if (RxOnTime + RxOnDuration) is less than the beacon * interval. * According to 7.1.10.1.3: * On a beacon-enabled PAN, the MLME first determines whether * (RxOnTime + RxOnDuration) is less than the beacon interval, defined * by macBeaconOrder. If it is not less, the MLME issues the * MLME-RX-ENABLE.confirm primitive with a status of MAC_INVALID_PARAMETER. */ rx_off_time_symbols = rxe->RxOnTime + rxe->RxOnDuration; if (rx_off_time_symbols >= curr_beacon_int_time_symbols) { /* Send the confirm immediately. */ gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_INVALID_PARAMETER); return; } pal_get_current_time(&now_time_symbols); now_time_symbols = TAL_CONVERT_US_TO_SYMBOLS(now_time_symbols); symbols_since_beacon = tal_sub_time_symbols(now_time_symbols, tal_pib.BeaconTxTime); /* * Actually, MLME-RX-ENABLE.request in a beacon enabled PAN does * only make sense if the MAC is currently tracking beacons, so * that macBeaconTxTime is up to date. If it appears that * the last known macBeaconTxTime does not relate to the * current superframe, reject the request. */ if (symbols_since_beacon > curr_beacon_int_time_symbols) { /* Send the confirm immediately. */ gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_INVALID_PARAMETER); return; } rx_on_time_symbols = tal_add_time_symbols(tal_pib.BeaconTxTime, rxe->RxOnTime); /* Check whether RxOnTime can still be handled in current CAP. */ pal_get_current_time(&now_time_symbols); now_time_symbols = TAL_CONVERT_US_TO_SYMBOLS(now_time_symbols); if (tal_add_time_symbols(rx_on_time_symbols, TAL_CONVERT_US_TO_SYMBOLS(MIN_TIMEOUT)) < now_time_symbols) { /* RxOnTime not possible within this CAP, see whether deferred * handling is allowed or not.. */ if (!(rxe->DeferPermit)) { gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_PAST_TIME); return; } else { /* * The MAC defers until the next superframe and attempts to enable * the receiver in that superframe. */ rx_on_time_symbols = tal_add_time_symbols(rx_on_time_symbols, curr_beacon_int_time_symbols); } } /* * Since the Rx-Enable timer could already be running, * it is stopped first, before it will be started (again). */ pal_timer_stop(T_Rx_Enable); do { /* * Start a timer to turn Rx ON at the time "rxe->RxOnTime" from the start * of the next superframe. * Return value to be checked, because Rx on time could be too short * or in the past already. */ timer_status = pal_timer_start(T_Rx_Enable, TAL_CONVERT_SYMBOLS_TO_US(rx_on_time_symbols), TIMEOUT_ABSOLUTE, (FUNC_PTR())mac_t_rx_on_cb, (void *)m); if (MAC_SUCCESS != timer_status) { rx_on_time_symbols = tal_add_time_symbols(rx_on_time_symbols, curr_beacon_int_time_symbols); } } while (MAC_SUCCESS != timer_status); /* Remember the time to turn off the receiver. */ rx_off_time_symbols = tal_add_time_symbols(rx_on_time_symbols, rxe->RxOnDuration); /* The remaining stuff will be done once the Rx On Timer expires. */ } #else /* No BEACON_SUPPORT */ handle_rx_on(rxe->RxOnDuration, m); #endif /* BEACON_SUPPORT / No BEACON_SUPPORT */ } /* mlme_rx_enable_request() */
/** * @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. * Install a handler for the transceiver interrupt. */ pal_trx_irq_init(trx_irq_handler_cb); /* The pending transceiver interrupts on the microcontroller are cleared. */ pal_trx_irq_flag_clr(); pal_trx_irq_en(); /* Enable transceiver main interrupt. */ #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 */ return MAC_SUCCESS; }