/** * \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); } }
void bc_data_cb_vanet(frame_info_t *transmit_frame) { uint8_t index; index = nwkFindPassiveAck(transmit_frame->NwkFrameHeader->srcAddr, transmit_frame->NwkFrameHeader->sequenceNumber); if (index != 0xFF) { #if 0 if (gNwkPassiveAckTable.table[index].end == false) { NwkState = NWK_MODULE_NONE; pal_timer_start(gNwkPassiveAckTable.table[index].timerID, ((uint32_t) (NWK_BROADCAST_DELIVERY_TIME-(gNwkPassiveAckTable.table[index].reTryTimes+1)*NWK_PASSIVE_ACK_TIMEOUT)), TIMEOUT_RELATIVE, (FUNC_PTR)bc_data_cb_vanet, transmit_frame); gNwkPassiveAckTable.table[index].end = true; return; } #endif gNwkPassiveAckTable.table[index].end = false; gNwkPassiveAckTable.table[index].reTryTimes = 0; nwkFreePassiveAck(transmit_frame->NwkFrameHeader->srcAddr, transmit_frame->NwkFrameHeader->sequenceNumber); if (transmit_frame != NULL) bmm_buffer_free(transmit_frame->buffer_header); //NwkState = NWK_MODULE_NONE;//if为1时原本是释掉的 mac_sleep_trans(); } }
/** * @brief Notify the application of the status of its request to to change the * value of a NIB attribute. * * @param Status nwk status * @param NIBAttribute NIBAttribute * @param NIBAttributeIndex NIBAttributeIndex */ void nlme_set_confirm(nwk_enum_t Status, nib_attribute_t NIBAttribute, uint8_t NIBAttributeIndex) { if (Status != NWK_SUCCESS) { return; } if (NIBAttribute == nwkBaseChannel) { pal_timer_start(T_LED_TIMER, PAIR_WAIT_PERIOD, TIMEOUT_RELATIVE, (FUNC_PTR)led_handling, NULL); pal_led(LED_NWK_SETUP, LED_ON); dev_type_t RecDevTypeList[DEVICE_TYPE_LIST_SIZE]; profile_id_t RecProfileIdList[PROFILE_ID_LIST_SIZE]; RecDevTypeList[0] = SUPPORTED_DEV_TYPE_0; RecProfileIdList[0] = SUPPORTED_PROFILE_ID_0; pbp_rec_pair_request(APP_CAPABILITIES, RecDevTypeList, RecProfileIdList); return; } /* Keep compiler happy */ UNUSED(NIBAttributeIndex); }
/* * @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 helper function to start missed beacon timer */ void mac_start_missed_beacon_timer(void) { uint32_t sync_loss_time; uint8_t timer_status; /* Stop the missed beacon timer. */ pal_timer_stop(T_Missed_Beacon); #if (DEBUG > 0) if (pal_is_timer_running(T_Missed_Beacon)) { ASSERT("Missed BCN tmr running" == 0); } #endif /* Calculate the time allowed for missed beacons. */ if (tal_pib.BeaconOrder < NON_BEACON_NWK) { /* * This the regualar case where we already have a Beacon Order. * In this case the Sync Loss time is a function of the actual * Beacon Order. */ sync_loss_time = TAL_GET_BEACON_INTERVAL_TIME(tal_pib.BeaconOrder); } else { /* * This the "pathological" case where we don NOT have a Beacon Order. * This happens regularly in case of synchronization before association * if the Beacon Order was not set be the network layer or application. * * In this case the Sync Loss time is based on the highest possible * Beacon Order, which is 15 - 1, since 15 means no Beacon network. */ sync_loss_time = TAL_GET_BEACON_INTERVAL_TIME(NON_BEACON_NWK - 1); } sync_loss_time *= aMaxLostBeacons; sync_loss_time = TAL_CONVERT_SYMBOLS_TO_US(sync_loss_time); timer_status = pal_timer_start(T_Missed_Beacon, sync_loss_time, TIMEOUT_RELATIVE, (FUNC_PTR)mac_t_missed_beacons_cb, NULL); if (MAC_SUCCESS != timer_status) { #if (DEBUG > 0) ASSERT(MAC_SUCCESS == timer_status); #endif /* Sync timer could not be started hence report sync-loss */ mac_sync_loss(MAC_BEACON_LOSS); } }
/* * @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 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; } }
/** * @brief starts a timer */ static void start_timer() { uint8_t status = pal_timer_start( TIMER_DATA_FWD, (uint32_t)1000*TIMER_INTERVAL, TIMEOUT_RELATIVE, (void*)data_fwd_cb, NULL); #if(ALERT_ON_ERROR==true) if(status != MAC_SUCCESS) { pal_alert(); } #endif }
void bc_delay_cb(frame_info_t *transmit_frame) { retval_t status; status = tal_tx_frame(nwkBroadDelay[minBroadDelayIndex].transmit_frame, CSMA_UNSLOTTED, true); broadDelayBitmap &= ~(1<<minBroadDelayIndex); nwkBroadDelay[minBroadDelayIndex].transmit_frame = NULL; nwkBroadDelay[minBroadDelayIndex].delayCount = 0xFFFFFFFF; broadDelayCount--; if (MAC_SUCCESS == status) { MAKE_MAC_BUSY(); } else { // NwkState = NwkState; //bmm_buffer_free(nwkBroadDelay[minBroadDelayIndex].transmit_frame->buffer_header);//TODO 要多考虑,如果后面还有数据,需要再启动 mac_sleep_trans(); } if (broadDelayCount > 0) { //bubble_sort_broad(); do { status = pal_timer_start(APP_TIMER_UART_TIMEOUT, nwkBroadDelay[++minBroadDelayIndex].delayCount, TIMEOUT_ABSOLUTE, (FUNC_PTR) bc_delay_cb, NULL); if (MAC_SUCCESS != status) { broadDelayBitmap &= ~(1<<minBroadDelayIndex); nwkBroadDelay[minBroadDelayIndex].transmit_frame = NULL; nwkBroadDelay[minBroadDelayIndex].delayCount = 0xFFFFFFFF; broadDelayCount--; } } while (MAC_SUCCESS != status && nwkBroadDelay[minBroadDelayIndex+1].transmit_frame != NULL); } if (broadDelayCount == 0) minBroadDelayIndex = 0; }
/** * @brief Continue scanning after the completion of frame transmission. * * This functions continues the corresponding scaning depending on status * from the transmission of a beacon request or orphan notification frame. * * @param status Status of transmission */ void mac_scan_send_complete(retval_t status) { retval_t timer_status; mac_pib.mac_DSN++; if (MAC_SUCCESS == status) { uint32_t tmr = 0; if (MAC_SCAN_ACTIVE == mac_scan_state) { tmr = MAC_CALCULATE_SYMBOL_TIME_SCANDURATION( scan_duration); } else { /* * Since this function is only called in active or * orphan scan state, * this case is handling the orphan scan state. */ tmr = mac_pib.mac_ResponseWaitTime; } timer_status = pal_timer_start(T_Scan_Duration, TAL_CONVERT_SYMBOLS_TO_US(tmr), TIMEOUT_RELATIVE, (FUNC_PTR)mac_t_scan_duration_cb, NULL); #if (_DEBUG_ > 0) Assert(MAC_SUCCESS == timer_status); #endif if (MAC_SUCCESS != timer_status) { uint8_t timer_id = T_Scan_Duration; /* * Scan duration timer could not be started, so we call * the timer callback function directly. This will * basically * shorten scanning without having really scanned. */ mac_t_scan_duration_cb((void *)&timer_id); } } else { /* Did not work, continue. */ scan_curr_channel++; scan_proceed(scan_type, (buffer_t *)mac_conf_buf_ptr); } }
/* * \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 Starts the beacon loss timer */ static void start_beacon_loss_timer(void) { uint32_t timer_duration_us; #if (_DEBUG_ > 0) retval_t timer_status; #endif /* debug pin to switch on: define ENABLE_DEBUG_PINS, pal_config.h */ PIN_BEACON_LOSS_TIMER_START(); timer_duration_us = TAL_CONVERT_SYMBOLS_TO_US(TAL_GET_BEACON_INTERVAL_TIME(tal_pib .BeaconOrder)); timer_duration_us *= aMaxLostBeacons; timer_duration_us += CSMA_BEACON_LOSS_GUARD_TIME_US; #if (_DEBUG_ > 0) timer_status = #endif pal_timer_start(TAL_CSMA_BEACON_LOSS_TIMER, timer_duration_us, TIMEOUT_RELATIVE, (FUNC_PTR)beacon_loss_timer_cb, NULL); #if (_DEBUG_ > 0) if (timer_status != MAC_SUCCESS) { if (timer_status == PAL_TMR_INVALID_TIMEOUT) { Assert( "beacon loss timer start failed: PAL_TMR_INVALID_TIMEOUT" == 0); } else if (timer_status == PAL_TMR_ALREADY_RUNNING) { Assert( "beacon loss timer start failed: PAL_TMR_ALREADY_RUNNING" == 0); } else { Assert("beacon loss timer start failed: ?" == 0); } } #endif }
/** * @brief LED handling including timer control . */ static void led_handling(void *callback_parameter) { switch (node_status) { case PUSH_BUTTON_PAIRING: case ALL_IN_ONE_START: pal_timer_start(T_LED_TIMER, PAIR_WAIT_PERIOD, TIMEOUT_RELATIVE, (FUNC_PTR)led_handling, NULL); pal_led(LED_NWK_SETUP, LED_TOGGLE); break; default: pal_timer_stop(T_LED_TIMER); pal_led(LED_DATA, LED_OFF); pal_led(LED_NWK_SETUP, LED_OFF); break; } /* Keep compiler happy */ UNUSED(callback_parameter); }
/** * @brief Starts the timer for the backoff period and enables receiver. * * @param trx_id Transceiver identifier */ static void start_backoff(trx_id_t trx_id) { /* Start backoff timer to trigger CCA */ uint8_t backoff_8; backoff_8 = (uint8_t)(rand() & (((uint16_t)1 << BE[trx_id]) - 1)); if (backoff_8 > 0) { uint8_t timer_id; uint16_t backoff_16; uint32_t backoff_duration_us; backoff_16 = backoff_8 * aUnitBackoffPeriod; backoff_duration_us = (uint32_t)tal_pib[trx_id].SymbolDuration_us * (uint32_t)backoff_16; #ifdef REDUCED_BACKOFF_DURATION backoff_duration_us = REDUCED_BACKOFF_DURATION; #endif if (trx_id == RF09) { timer_id = TAL_T_0; } else { timer_id = TAL_T_1; } retval_t status = pal_timer_start(timer_id, backoff_duration_us, TIMEOUT_RELATIVE, (FUNC_PTR)cca_start, (void *)&timer_cb_parameter[trx_id]); if (status != MAC_SUCCESS) { tx_done_handling(trx_id, status); return; } tx_state[trx_id] = TX_BACKOFF; #ifdef RX_WHILE_BACKOFF /* Keep receiver on during backoff */ if ((trx_default_state[trx_id] == RF_RX) && (tal_pib[trx_id].NumRxFramesDuringBackoff < tal_pib[trx_id].MaxNumRxFramesDuringBackoff)) { if (trx_state[trx_id] != RF_RX) { if (trx_state[trx_id] == RF_TRXOFF) { switch_to_txprep(trx_id); } switch_to_rx(trx_id); } } else #endif { #ifdef USE_TXPREP_DURING_BACKOFF /* Switch to TXPREP during backoff */ if (trx_state[trx_id] != RF_TXPREP) { switch_to_txprep(trx_id); } #else /* Switch to TRXOFF during backoff */ if (trx_state[trx_id] != RF_TRXOFF) { uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; trx_reg_write(reg_offset + RG_RF09_CMD, RF_TRXOFF); trx_state[trx_id] = RF_TRXOFF; } #endif } } else { /* no backoff required */ /* Start CCA immediately - no backoff */ cca_start((void *)&timer_cb_parameter[trx_id]); } }
/** * \brief Calculates backoff duration and handles the start of the CCA */ static void csma_backoff_calculation(void) { uint32_t current_CAP_duration_sym; uint32_t current_CAP_end_sym; uint32_t next_backoff_boundary_us; uint32_t now_time_sym; uint32_t guard_time_before_next_beacon; /* \TODO consider CFP and BLE mode */ current_CAP_duration_sym = TAL_GET_SUPERFRAME_DURATION_TIME( tal_pib.SuperFrameOrder); current_CAP_end_sym = tal_add_time_symbols(tal_pib.BeaconTxTime, current_CAP_duration_sym); /* * Add some guard time to ensure that the transaction is completed * before * the timer fires that is going to track the next beacon. */ guard_time_before_next_beacon = TAL_RADIO_WAKEUP_TIME_SYM << (tal_pib.BeaconOrder + 2); guard_time_before_next_beacon += TAL_CONVERT_US_TO_SYMBOLS( PRE_BEACON_GUARD_TIME_US); current_CAP_end_sym = tal_sub_time_symbols(current_CAP_end_sym, guard_time_before_next_beacon); /* Calculate next backoff period boundary. */ { uint32_t time_since_last_beacon_sym; uint32_t next_backoff_boundary_period; pal_get_current_time(&now_time_sym); now_time_sym = TAL_CONVERT_US_TO_SYMBOLS(now_time_sym); time_since_last_beacon_sym = tal_sub_time_symbols(now_time_sym, tal_pib.BeaconTxTime); next_backoff_boundary_period = time_since_last_beacon_sym / aUnitBackoffPeriod; if ((time_since_last_beacon_sym % aUnitBackoffPeriod) > 0) { next_backoff_boundary_period++; } next_backoff_boundary_us = TAL_CONVERT_SYMBOLS_TO_US( pal_add_time_us(tal_pib.BeaconTxTime, (next_backoff_boundary_period * aUnitBackoffPeriod))); } /* Check if we are still within the CAP. */ if (next_backoff_boundary_us >= TAL_CONVERT_SYMBOLS_TO_US(current_CAP_end_sym)) { /* current CAP is over, wait for next CAP */ tal_csma_state = BACKOFF_WAITING_FOR_BEACON; start_beacon_loss_timer(); } else { /* next backoff boundary is within current CAP */ uint32_t remaining_periods_in_CAP; /* \TODO check if variable * size can be reduced */ /* Check if the remaining backoff time will expire in current * CAP. */ remaining_periods_in_CAP = tal_sub_time_symbols( current_CAP_end_sym, now_time_sym) / aUnitBackoffPeriod; if (remaining_backoff_periods > remaining_periods_in_CAP) { /* * Reduce the backoff peridos by the remaining duration * in * the current CAP and continue in next CAP. */ remaining_backoff_periods -= remaining_periods_in_CAP; tal_csma_state = BACKOFF_WAITING_FOR_BEACON; start_beacon_loss_timer(); } else { /* there are enough backoff periods in current CAP */ uint32_t time_after_transaction_sym; /* \TODO check if * variable size * can be reduced **/ uint32_t transaction_duration_sym; /* \TODO check if * variable size can * be reduced */ /* Add some guard time to wakeup the transceiver. */ transaction_duration_sym = (transaction_duration_periods * aUnitBackoffPeriod) + TAL_CONVERT_US_TO_SYMBOLS( SLEEP_TO_TRX_OFF_TYP_US + CCA_GUARD_DURATION_US); time_after_transaction_sym = tal_add_time_symbols(TAL_CONVERT_US_TO_SYMBOLS( next_backoff_boundary_us), transaction_duration_sym); /* Check if the entire transaction fits into the current * CAP. */ if (time_after_transaction_sym < current_CAP_end_sym) { retval_t timer_status; uint32_t callback_start_time; /* Calculate the time needed to backoff. */ cca_starttime_us = pal_add_time_us( next_backoff_boundary_us, TAL_CONVERT_SYMBOLS_TO_US( remaining_backoff_periods * aUnitBackoffPeriod)); /* * Ensure that wakeup time is available before * CCA. * The required duration depends on the current * trx status. * Assume here the worst case: trx is in SLEEP. */ /* * \TODO depending on the duration that we need * to backoff, * set trx to SLEEP, TRX_OFF or PLL_ON * meanwhile. */ while (pal_sub_time_us(cca_starttime_us, TAL_CONVERT_SYMBOLS_TO_US( now_time_sym)) < (SLEEP_TO_TRX_OFF_TYP_US + CCA_GUARD_DURATION_US)) { cca_starttime_us = pal_add_time_us( cca_starttime_us, TAL_CONVERT_SYMBOLS_TO_US( aUnitBackoffPeriod)); } /* * Start the CCA timer. * Add some time to locate the next backoff * boundary * once CCA timer fires. */ callback_start_time = pal_sub_time_us(cca_starttime_us, (SLEEP_TO_TRX_OFF_TYP_US + CCA_PREPARATION_DURATION_US)); timer_status = pal_timer_start(TAL_CSMA_CCA, callback_start_time, TIMEOUT_ABSOLUTE, (FUNC_PTR)cca_timer_handler_cb, NULL); if (timer_status == MAC_SUCCESS) { tal_csma_state = BACKOFF_WAITING_FOR_CCA_TIMER; } else if (timer_status == PAL_TMR_INVALID_TIMEOUT) { /* Start the CCA immediately. */ cca_timer_handler_cb(NULL); } else { tal_csma_state = CSMA_ACCESS_FAILURE; Assert("CCA timer start problem" == 0); } /* debug pin to switch on: define * ENABLE_DEBUG_PINS, pal_config.h */ PIN_BACKOFF_START(); } else { /* Restart again after next beacon. */ NB = 0; remaining_backoff_periods = (uint8_t)(rand() & ((1 << BE) - 1)); tal_csma_state = BACKOFF_WAITING_FOR_BEACON; start_beacon_loss_timer(); } } } }
/** * @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 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 Interrupt handler for ACK reception * * \param parameter Unused callback parameter */ static void ack_reception_handler_cb(void *parameter) { trx_irq_reason_t trx_irq_cause; if (tal_csma_state == TX_DONE_NO_ACK) { return; /* ack expiration timer has already been fired */ } trx_irq_cause = (trx_irq_reason_t)pal_trx_reg_read(RG_IRQ_STATUS); if (trx_irq_cause & TRX_IRQ_TRX_END) { retval_t timer_status; switch (tal_csma_state) { case FRAME_SENDING_WITH_ACK: set_trx_state(CMD_RX_ON); timer_status = pal_timer_start(TAL_ACK_WAIT_TIMER, TAL_CONVERT_SYMBOLS_TO_US( TAL_ACK_WAIT_DURATION_DEFAULT), TIMEOUT_RELATIVE, (FUNC_PTR)ack_timer_expiry_handler_cb, NULL); if (timer_status == MAC_SUCCESS) { tal_csma_state = WAITING_FOR_ACK; } else if (timer_status == PAL_TMR_ALREADY_RUNNING) { tal_csma_state = WAITING_FOR_ACK; } else { tal_csma_state = TX_DONE_NO_ACK; Assert("timer start failed" == 0); } /* debug pin to switch on: define ENABLE_DEBUG_PINS, *pal_config.h */ PIN_TX_END(); PIN_ACK_WAITING_START(); break; case WAITING_FOR_ACK: { uint8_t ack_frame[ACK_FRAME_LEN + LENGTH_FIELD_LEN]; /* * Read the frame buffer, identify if this is an ACK *frame, * and get the sequence number. * Üpload the frame from the transceiver. */ pal_trx_frame_read(ack_frame, (ACK_FRAME_LEN + LENGTH_FIELD_LEN)); /* Check if the uploaded frame is an ACK frame */ if ((ack_frame[1] & ACK_FRAME) != ACK_FRAME) { /* The received frame is not an ACK frame */ return; } /* check CRC */ if (pal_trx_bit_read(SR_RX_CRC_VALID) != CRC16_VALID) { return; } /* check the sequence number */ if (ack_frame[3] == tal_frame_to_tx[SEQ_NUMBER_POS]) { /* * If we are here, the ACK is valid and matches * the transmitted sequence number. */ pal_timer_stop(TAL_ACK_WAIT_TIMER); #if (_DEBUG_ > 0) if (pal_is_timer_running(TAL_ACK_WAIT_TIMER)) { Assert("Ack timer running" == 0); } #endif /* restore the interrupt handler */ pal_trx_irq_init((FUNC_PTR)trx_irq_handler_cb); pal_trx_irq_en(); if (NULL != tal_rx_buffer) { pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); } else { tal_rx_on_required = true; } /* debug pin to switch on: define *ENABLE_DEBUG_PINS, pal_config.h */ PIN_ACK_OK_START(); if (ack_frame[1] & FCF_FRAME_PENDING) { tal_csma_state = TX_DONE_FRAME_PENDING; } else { tal_csma_state = TX_DONE_SUCCESS; } /* debug pin to switch on: define *ENABLE_DEBUG_PINS, pal_config.h */ PIN_ACK_OK_END(); PIN_ACK_WAITING_END(); } } break; case FRAME_SENDING_NO_ACK: /* Tx is done */ /* debug pin to switch on: define ENABLE_DEBUG_PINS, *pal_config.h */ PIN_TX_END(); tal_csma_state = TX_DONE_SUCCESS; break; default: Assert("unknown tal_csma_state" == 0); break; } } else { /* other interrupt than TRX_END */ /* no interest in any other interrupt */ return; } parameter = parameter; /* Keep compiler happy. */ }
/** * @brief Continue scanning after setting of PIB attributes * * This functions continues scanning once the corresponding PIB * attribute change has been completed depending on the status. * * @param set_status Status of the Request to change the PIB attribute */ void scan_set_complete(retval_t set_status) { switch (mac_scan_state) { #if (MAC_SCAN_ED_REQUEST_CONFIRM == 1) case MAC_SCAN_ED: { if (MAC_SUCCESS == set_status) { MAKE_MAC_BUSY(); tal_ed_start(scan_duration); } else { /* Channel not supported, continue. */ scan_curr_channel++; } } break; #endif /* (MAC_SCAN_ED_REQUEST_CONFIRM == 1) */ #if (MAC_SCAN_ACTIVE_REQUEST_CONFIRM == 1) case MAC_SCAN_ACTIVE: if (MAC_SUCCESS == set_status) { /* * The TAL switches ON the transmitter while sending a * beacon request, hence the MAC can call * send_scan_cmd() to send * the beacon directly */ /* Send an beacon request command */ if (!send_scan_cmd(true)) { uint8_t timer_id = T_Scan_Duration; /* * Beacon request could not be transmitted * since there is no buffer available stop * scanning * we call the function usually called by the * scan * duration timer to pretend scanning has * finished */ mac_t_scan_duration_cb((uint8_t *)&timer_id); } } else { /* Channel not supported, continue. */ scan_curr_channel++; } break; #endif /* (MAC_SCAN_ACTIVE_REQUEST_CONFIRM == 1) */ #if (MAC_SCAN_PASSIVE_REQUEST_CONFIRM == 1) case MAC_SCAN_PASSIVE: { if (MAC_SUCCESS == set_status) { uint8_t status = tal_rx_enable(PHY_RX_ON); if (PHY_RX_ON == status) { retval_t timer_status; uint32_t tmr = MAC_CALCULATE_SYMBOL_TIME_SCANDURATION( scan_duration); timer_status = pal_timer_start(T_Scan_Duration, TAL_CONVERT_SYMBOLS_TO_US( tmr), TIMEOUT_RELATIVE, (FUNC_PTR)mac_t_scan_duration_cb, NULL); #if (_DEBUG_ > 0) Assert(MAC_SUCCESS == timer_status); #endif if (MAC_SUCCESS != timer_status) { uint8_t timer_id = T_Scan_Duration; /* * Scan duration timer could not be * started so we * call the timer callback function * directly this * will basically shorten scanning * without having * really scanned. */ mac_t_scan_duration_cb((void *)&timer_id); } } else { /* Did not work, continue. */ scan_curr_channel++; scan_proceed(MLME_SCAN_TYPE_PASSIVE, (buffer_t *)mac_conf_buf_ptr); } } else { /* Channel not supported, continue. */ scan_curr_channel++; } } break; #endif /* (MAC_SCAN_PASSIVE_REQUEST_CONFIRM == 1) */ #if (MAC_SCAN_ORPHAN_REQUEST_CONFIRM == 1) case MAC_SCAN_ORPHAN: if (MAC_SUCCESS == set_status) { /* Send an orphan notification command */ if (!send_scan_cmd(false)) { uint8_t timer_id = T_Scan_Duration; /* * Orphan notification could not be transmitted * since there * is no buffer available stop scanning * we call the function usually called by the * scan duration * timer to pretend scanning has finished */ mac_t_scan_duration_cb((uint8_t *)&timer_id); } } else { /* Channel not supported, continue. */ scan_curr_channel++; } break; #endif /* (MAC_SCAN_ORPHAN_REQUEST_CONFIRM == 1) */ default: break; } } /* scan_set_complete() */
/** * @brief Processes received beacon frame * * This function processes a received beacon frame. * When the system is scanning it records PAN descriptor information * contained in the beacon. These PAN descriptors will be reported to the * next higher layer via MLME_SCAN.confirm. * Also this routine constructs the MLME_BEACON_NOTIFY.indication. * Additionally when a device is synced with the coordinator, it tracks beacon * frames, checks whether the coordinator does have pending data and will * initiate the transmission of a data request frame. * The routine uses global "parse_data" structure. * The PAN descriptors are stored in the mlme_scan_conf_t structure. * * @param beacon Pointer to the buffer in which the beacon was received * */ void mac_process_beacon_frame(buffer_t *beacon) { bool matchflag; wpan_pandescriptor_t *pand_long_start_p = NULL; wpan_pandescriptor_t pand_long; mlme_scan_conf_t *msc = NULL; #if ((MAC_BEACON_NOTIFY_INDICATION == 1) || \ ((MAC_INDIRECT_DATA_BASIC == 1) && (MAC_SYNC_REQUEST == 1)) \ ) uint8_t numaddrshort; uint8_t numaddrlong; #endif #ifdef BEACON_SUPPORT uint16_t beacon_length; /* * Extract the superframe parameters of the beacon frame only if * scanning is NOT ongoing. */ if (MAC_SCAN_IDLE == mac_scan_state) { #if (MAC_START_REQUEST_CONFIRM == 1) /* Beacon frames are not of interest for a PAN coordinator. */ if (MAC_PAN_COORD_STARTED != mac_state) #endif /* MAC_START_REQUEST_CONFIRM */ { uint8_t superframe_order; uint8_t beacon_order; /* * For a device, the parameters obtained from the beacons are used to * update the PIBs at TAL */ beacon_order = GET_BEACON_ORDER(mac_parse_data.mac_payload_data.beacon_data.superframe_spec); #if (_DEBUG_ > 0) retval_t set_status = #endif set_tal_pib_internal(macBeaconOrder, (void *)&beacon_order); #if (_DEBUG_ > 0) Assert(MAC_SUCCESS == set_status); #endif superframe_order = GET_SUPERFRAME_ORDER(mac_parse_data.mac_payload_data.beacon_data.superframe_spec); #if (_DEBUG_ > 0) set_status = #endif set_tal_pib_internal(macSuperframeOrder, (void *)&superframe_order); #if (_DEBUG_ > 0) Assert(MAC_SUCCESS == set_status); #endif mac_final_cap_slot = GET_FINAL_CAP(mac_parse_data.mac_payload_data.beacon_data.superframe_spec); /* * In a beacon-enabled network with the batterylife extension * enabled, the first backoff slot boundary is computed after the * end of the beacon's IFS */ if ((tal_pib.BeaconOrder < NON_BEACON_NWK) && tal_pib.BattLifeExt) { /* Length given in octets */ beacon_length = mac_parse_data.mpdu_length + PHY_OVERHEAD; /* Convert to symbols */ beacon_length *= SYMBOLS_PER_OCTET; /* Space needed for IFS is added to it */ if (mac_parse_data.mpdu_length <= aMaxSIFSFrameSize) { beacon_length += macMinSIFSPeriod_def; } else { beacon_length += macMinLIFSPeriod_def; } /* Round up to backoff slot boundary */ beacon_length = (beacon_length + aUnitBackoffPeriod - 1) / aUnitBackoffPeriod; beacon_length *= aUnitBackoffPeriod; /* * Slotted CSMA-CA with macBattLifeExt must start within * the first macBattLifeExtPeriods backoff slots of the CAP */ beacon_length += mac_pib.mac_BattLifeExtPeriods * aUnitBackoffPeriod; } } /* (MAC_PAN_COORD_STARTED != mac_state) */ } /* (MAC_SCAN_IDLE == mac_scan_state) */ #endif /* BEACON_SUPPORT */ /* * The following section needs to be done when we are * either scanning (and look for a new PAN descriptor to be returned * as part of the scan confirm message), * or we need to create a beacon notification (in which case we are * interested in any beacon, but omit the generation of scan confirm). */ { uint8_t index; /* * If we are scanning a scan confirm needs to be created. * * According to 802.15.4-2006 this is only done in case the PIB * attribute macAutoRequest is true. Otherwise the PAN descriptor will * NOT be put into the PAN descriptor list of the Scan confirm message. */ if ( ((MAC_SCAN_ACTIVE == mac_scan_state) || (MAC_SCAN_PASSIVE == mac_scan_state)) && mac_pib.mac_AutoRequest ) { /* * mac_conf_buf_ptr points to the buffer allocated for scan * confirmation. */ msc = (mlme_scan_conf_t *)BMM_BUFFER_POINTER( ((buffer_t *)mac_conf_buf_ptr)); /* * The PAN descriptor list is updated with the PANDescriptor of the * received beacon */ pand_long_start_p = (wpan_pandescriptor_t *)&msc->scan_result_list; } /* * The beacon data received from the parse variable is arranged * into a PAN descriptor structure style */ pand_long.CoordAddrSpec.AddrMode = mac_parse_data.src_addr_mode; pand_long.CoordAddrSpec.PANId = mac_parse_data.src_panid; if (FCF_SHORT_ADDR == pand_long.CoordAddrSpec.AddrMode) { /* Initially clear the complete address. */ pand_long.CoordAddrSpec.Addr.long_address = 0; ADDR_COPY_DST_SRC_16(pand_long.CoordAddrSpec.Addr.short_address, mac_parse_data.src_addr.short_address); } else { ADDR_COPY_DST_SRC_64(pand_long.CoordAddrSpec.Addr.long_address, mac_parse_data.src_addr.long_address); } pand_long.LogicalChannel = tal_pib.CurrentChannel; pand_long.ChannelPage = tal_pib.CurrentPage; pand_long.SuperframeSpec = mac_parse_data.mac_payload_data.beacon_data.superframe_spec; pand_long.GTSPermit = mac_parse_data.mac_payload_data.beacon_data.gts_spec >> 7; pand_long.LinkQuality = mac_parse_data.ppdu_link_quality; #ifdef ENABLE_TSTAMP pand_long.TimeStamp = mac_parse_data.time_stamp; #endif /* ENABLE_TSTAMP */ /* * If we are scanning we need to check whether this is a new * PAN descriptor. * * According to 802.15.4-2006 this is only done in case the PIB * attribute macAutoRequest is true. Otherwise the PAN descriptor will * NOT be put into the PAN descriptor list of the Scan confirm message. */ if ( ((MAC_SCAN_ACTIVE == mac_scan_state) || (MAC_SCAN_PASSIVE == mac_scan_state)) && mac_pib.mac_AutoRequest ) { /* * This flag is used to indicate a match of the current (received) PAN * descriptor with one of those present already in the list. */ matchflag = false; /* * The beacon frame PAN descriptor is compared with the PAN descriptors * present in the list and determine if the current PAN * descriptor is to be taken as a valid one. A PAN is considered to be * the same as an existing one, if all, the PAN Id, the coordinator address * mode, the coordinator address, and the Logical Channel are same. */ for (index = 0; index < msc->ResultListSize; index++, pand_long_start_p++) { if ((pand_long.CoordAddrSpec.PANId == pand_long_start_p->CoordAddrSpec.PANId) && (pand_long.CoordAddrSpec.AddrMode == pand_long_start_p->CoordAddrSpec.AddrMode) && (pand_long.LogicalChannel == pand_long_start_p->LogicalChannel) && (pand_long.ChannelPage == pand_long_start_p->ChannelPage) ) { if (pand_long.CoordAddrSpec.AddrMode == WPAN_ADDRMODE_SHORT) { if (pand_long.CoordAddrSpec.Addr.short_address == pand_long_start_p->CoordAddrSpec.Addr.short_address) { /* Beacon with same parameters already received */ matchflag = true; break; } } else { if (pand_long.CoordAddrSpec.Addr.long_address == pand_long_start_p->CoordAddrSpec.Addr.long_address) { /* Beacon with same parameters already received */ matchflag = true; break; } } } } /* * If the PAN descriptor is not in the current list, and there is space * left, it is put into the list */ if ((!matchflag) && (msc->ResultListSize < MAX_PANDESCRIPTORS)) { memcpy(pand_long_start_p, &pand_long, sizeof(pand_long)); msc->ResultListSize++; } } } #if ((MAC_BEACON_NOTIFY_INDICATION == 1) || \ ((MAC_INDIRECT_DATA_BASIC == 1) && (MAC_SYNC_REQUEST == 1)) \ ) /* The short and extended pending addresses are extracted from the beacon */ numaddrshort = NUM_SHORT_PEND_ADDR(mac_parse_data.mac_payload_data.beacon_data.pending_addr_spec); numaddrlong = NUM_LONG_PEND_ADDR(mac_parse_data.mac_payload_data.beacon_data.pending_addr_spec); #endif #if (MAC_BEACON_NOTIFY_INDICATION == 1) /* * In all cases (PAN or device) if the payload is not equal to zero * or macAutoRequest is false, MLME_BEACON_NOTIFY.indication is * generated */ if ((mac_parse_data.mac_payload_data.beacon_data.beacon_payload_len > 0) || (!mac_pib.mac_AutoRequest) ) { mlme_beacon_notify_ind_t *mbni = (mlme_beacon_notify_ind_t *)BMM_BUFFER_POINTER(((buffer_t *)beacon)); /* The beacon notify indication structure is built */ mbni->cmdcode = MLME_BEACON_NOTIFY_INDICATION; mbni->BSN = mac_parse_data.sequence_number; mbni->PANDescriptor = pand_long; mbni->PendAddrSpec = mac_parse_data.mac_payload_data.beacon_data.pending_addr_spec; if ((numaddrshort > 0) || (numaddrlong > 0)) { mbni->AddrList = mac_parse_data.mac_payload_data.beacon_data.pending_addr_list; } mbni->sduLength = mac_parse_data.mac_payload_data.beacon_data.beacon_payload_len; mbni->sdu = mac_parse_data.mac_payload_data.beacon_data.beacon_payload; /* * The beacon notify indication is given to the NHLE and then the buffer * is freed up. */ qmm_queue_append(&mac_nhle_q, (buffer_t *)beacon); } else #endif /* (MAC_BEACON_NOTIFY_INDICATION == 1) */ { /* Payload is not present, hence the buffer is freed here */ bmm_buffer_free(beacon); } /* Handling of ancounced broadcast traffic by the parent. */ #ifdef BEACON_SUPPORT if (MAC_SCAN_IDLE == mac_scan_state) { /* * In case this is a beaconing network, and this node is not scanning, * and the FCF indicates pending data thus indicating broadcast data at * parent, the node needs to be awake until the received broadcast * data has been received. */ if (mac_parse_data.fcf & FCF_FRAME_PENDING) { mac_bc_data_indicated = true; /* * Start timer since the broadcast frame is expected within * macMaxFrameTotalWaitTime symbols. */ if (MAC_POLL_IDLE == mac_poll_state) { /* * If the poll state is not idle, there is already an * indirect transaction ongoing. * Since the T_Poll_Wait_Time is going to be re-used, * this timer can only be started, if we are not in * a polling state other than idle. */ uint32_t response_timer = mac_pib.mac_MaxFrameTotalWaitTime; response_timer = TAL_CONVERT_SYMBOLS_TO_US(response_timer); if (MAC_SUCCESS != pal_timer_start(T_Poll_Wait_Time, response_timer, TIMEOUT_RELATIVE, (FUNC_PTR)mac_t_wait_for_bc_time_cb, NULL)) { mac_t_wait_for_bc_time_cb(NULL); } } else { /* * Any indirect poll operation is ongoing, so the timer will * not be started, i.e. nothing to be done here. * Once this ongoing indirect transaction has finished, this * node will go back to sleep anyway. */ } } else { mac_bc_data_indicated = false; } } /* (MAC_SCAN_IDLE == mac_scan_state) */ #endif /* BEACON_SUPPORT */ /* Handling of presented indirect traffic by the parent for this node. */ #if ((MAC_INDIRECT_DATA_BASIC == 1) && (MAC_SYNC_REQUEST == 1)) if (MAC_SCAN_IDLE == mac_scan_state) { /* * If this node is NOT scanning, and is doing a mlme_sync_request, * then the pending address list of the beacon is examined to see * if the node's parent has data for this node. */ if (mac_pib.mac_AutoRequest) { if (MAC_SYNC_NEVER != mac_sync_state) { uint8_t index; #if (_DEBUG_ > 0) bool status; #endif /* * Short address of the device is compared with the * pending short address in the beacon frame */ /* * PAN-ID and CoordAddress does not have to be checked here, * since the device is already synced with the coordinator, and * only beacon frames passed from data_ind.c (where the first level * filtering is already done) are received. The pending addresses * in the beacon frame are compared with the device address. If a * match is found, it indicates that a data belonging to this * deivce is present with the coordinator and hence a data request * is sent to the coordinator. */ uint16_t cur_short_addr; for (index = 0; index < numaddrshort; index++) { cur_short_addr = convert_byte_array_to_16_bit((mac_parse_data.mac_payload_data.beacon_data.pending_addr_list + index * sizeof(uint16_t))); if (cur_short_addr == tal_pib.ShortAddress) { /* * Device short address matches with one of the address * in the beacon address list. Implicit poll (using the * device short address) is done to get the pending data */ #if (_DEBUG_ > 0) status = #endif mac_build_and_tx_data_req(false, false, 0, NULL, 0); #if (_DEBUG_ > 0) Assert(status == true); #endif return; } } /* * Extended address of the device is compared with * the pending extended address in the beacon frame */ uint64_t cur_long_addr; for (index = 0; index < numaddrlong; index++) { cur_long_addr = convert_byte_array_to_64_bit((mac_parse_data.mac_payload_data.beacon_data.pending_addr_list + numaddrshort * sizeof(uint16_t) + index * sizeof(uint64_t))); if (cur_long_addr == tal_pib.IeeeAddress) { /* * Device extended address matches with one of the * address in the beacon address list. Implicit poll * (using the device extended address) is done to get * the pending data */ #if (_DEBUG_ > 0) status = #endif mac_build_and_tx_data_req(false, true, 0, NULL, 0); #if (_DEBUG_ > 0) Assert(status == true); #endif return; } } } } /* (mac_pib.mac_AutoRequest) */ } /* (MAC_SCAN_IDLE == mac_scan_state) */ #endif /* (MAC_INDIRECT_DATA_BASIC == 1) && (MAC_SYNC_REQUEST == 1)) */ } /* mac_process_beacon_frame() */
/* * \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; } ENTER_CRITICAL_REGION(); tal_timers_stop(); LEAVE_CRITICAL_REGION(); /* 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. */ trx_irq_init((FUNC_PTR)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; }
/** * @brief Continues processing a data indication from the TAL for * non-polling and non-scanning states of the MAC * (mac_poll_state == MAC_POLL_IDLE, mac_scan_state == MAC_SCAN_IDLE). * * @param b_ptr Pointer to the buffer header. * @param f_ptr Pointer to the frame_info_t structure. * * @return bool True if frame has been processed, or false otherwise. */ static bool process_data_ind_not_transient(buffer_t *b_ptr, frame_info_t *f_ptr) { bool processed_in_not_transient = false; /* * We are in MAC_POLL_IDLE and MAC_SCAN_IDLE now, * so continue with the real MAC states. */ switch (mac_state) { #if (MAC_START_REQUEST_CONFIRM == 1) case MAC_PAN_COORD_STARTED: { switch (mac_parse_data.frame_type) { case FCF_FRAMETYPE_MAC_CMD: { switch (mac_parse_data.mac_command) { #if (MAC_ASSOCIATION_INDICATION_RESPONSE == 1) case ASSOCIATIONREQUEST: mac_process_associate_request(b_ptr); processed_in_not_transient = true; break; #endif /* (MAC_ASSOCIATION_INDICATION_RESPONSE == 1) */ #if (MAC_DISASSOCIATION_BASIC_SUPPORT == 1) case DISASSOCIATIONNOTIFICATION: mac_process_disassociate_notification(b_ptr); processed_in_not_transient = true; break; #endif /* (MAC_DISASSOCIATION_BASIC_SUPPORT == 1) */ #if (MAC_INDIRECT_DATA_FFD == 1) case DATAREQUEST: if (indirect_data_q.size > 0) { mac_process_data_request(b_ptr); processed_in_not_transient = true; } else { mac_handle_tx_null_data_frame(); } break; #endif /* (MAC_INDIRECT_DATA_FFD == 1) */ #if (MAC_ORPHAN_INDICATION_RESPONSE == 1) case ORPHANNOTIFICATION: mac_process_orphan_notification(b_ptr); processed_in_not_transient = true; break; #endif /* (MAC_ORPHAN_INDICATION_RESPONSE == 1) */ case BEACONREQUEST: mac_process_beacon_request(b_ptr); processed_in_not_transient = true; break; #if (MAC_PAN_ID_CONFLICT_AS_PC == 1) case PANIDCONFLICTNOTIFICAION: mac_sync_loss(MAC_PAN_ID_CONFLICT); break; #endif /* (MAC_PAN_ID_CONFLICT_AS_PC == 1) */ #ifdef GTS_SUPPORT case GTSREQUEST: mac_process_gts_request(b_ptr); processed_in_not_transient = true; #endif /* GTS_SUPPORT */ default: break; } } break; case FCF_FRAMETYPE_DATA: mac_process_data_frame(b_ptr); processed_in_not_transient = true; break; #if (MAC_PAN_ID_CONFLICT_AS_PC == 1) case FCF_FRAMETYPE_BEACON: /* PAN-Id conflict detection as PAN-Coordinator. */ /* Node is not scanning. */ check_for_pan_id_conflict_as_pc(false); break; #endif /* (MAC_PAN_ID_CONFLICT_AS_PC == 1) */ default: break; } } break; /* MAC_PAN_COORD_STARTED */ #endif /* (MAC_START_REQUEST_CONFIRM == 1) */ case MAC_IDLE: #if (MAC_ASSOCIATION_REQUEST_CONFIRM == 1) case MAC_ASSOCIATED: #endif /* (MAC_ASSOCIATION_REQUEST_CONFIRM == 1) */ #if (MAC_START_REQUEST_CONFIRM == 1) case MAC_COORDINATOR: #endif /* (MAC_START_REQUEST_CONFIRM == 1) */ { /* Is it a Beacon from our parent? */ switch (mac_parse_data.frame_type) { #if (MAC_SYNC_REQUEST == 1) case FCF_FRAMETYPE_BEACON: { uint32_t beacon_tx_time_symb; /* Check for PAN-Id conflict being NOT a PAN * Corodinator. */ #if (MAC_PAN_ID_CONFLICT_NON_PC == 1) if (mac_pib.mac_AssociatedPANCoord && (MAC_IDLE != mac_state)) { check_for_pan_id_conflict_non_pc(false); } #endif /* (MAC_PAN_ID_CONFLICT_NON_PC == 1) */ /* Check if the beacon is received from my * parent. */ if ((mac_parse_data.src_panid == tal_pib.PANId) && (((mac_parse_data.src_addr_mode == FCF_SHORT_ADDR) && (mac_parse_data.src_addr. short_address == mac_pib.mac_CoordShortAddress)) || ((mac_parse_data.src_addr_mode == FCF_LONG_ADDR) && (mac_parse_data.src_addr. long_address == mac_pib.mac_CoordExtendedAddress)))) { beacon_tx_time_symb = TAL_CONVERT_US_TO_SYMBOLS( f_ptr->time_stamp); #if (_DEBUG_ > 0) retval_t set_status = #endif set_tal_pib_internal(macBeaconTxTime, (void *)&beacon_tx_time_symb); #if (_DEBUG_ > 0) Assert(MAC_SUCCESS == set_status); #endif if ((MAC_SYNC_TRACKING_BEACON == mac_sync_state) || (MAC_SYNC_BEFORE_ASSOC == mac_sync_state) ) { uint32_t nxt_bcn_tm; uint32_t beacon_int_symb; /* Process a received beacon. */ mac_process_beacon_frame(b_ptr); /* Initialize beacon tracking * timer. */ { retval_t tmr_start_res = FAILURE; #ifdef BEACON_SUPPORT if (tal_pib.BeaconOrder < NON_BEACON_NWK) { beacon_int_symb = TAL_GET_BEACON_INTERVAL_TIME( tal_pib.BeaconOrder); } else #endif /* BEACON_SUPPORT */ { beacon_int_symb = TAL_GET_BEACON_INTERVAL_TIME( BO_USED_FOR_MAC_PERS_TIME); } pal_timer_stop( T_Beacon_Tracking_Period); #if (_DEBUG_ > 0) if (pal_is_timer_running( T_Beacon_Tracking_Period)) { Assert( "Bcn tmr running" == 0); } #endif do { /* * Calculate the * time for next * beacon * transmission */ beacon_tx_time_symb = tal_add_time_symbols( beacon_tx_time_symb, beacon_int_symb); /* * Take into * account the * time taken by * the radio to * wakeup from * sleep state */ nxt_bcn_tm = tal_sub_time_symbols( beacon_tx_time_symb, TAL_RADIO_WAKEUP_TIME_SYM << ( tal_pib . BeaconOrder + 2)); tmr_start_res = pal_timer_start( T_Beacon_Tracking_Period, TAL_CONVERT_SYMBOLS_TO_US( nxt_bcn_tm), TIMEOUT_ABSOLUTE, ( FUNC_PTR)mac_t_tracking_beacons_cb, NULL); } while (MAC_SUCCESS != tmr_start_res); #ifdef GTS_DEBUG port_pin_toggle_output_level( DEBUG_PIN1); port_pin_set_output_level( DEBUG_PIN2, 0); #endif } /* * Initialize superframe timer * if required only * for devices because * Superframe timer is already * running for * coordinator. */ /* TODO */ if (MAC_ASSOCIATED == mac_state) { mac_superframe_state = MAC_ACTIVE_CAP; /* Check whether the * radio needs to be * woken up. */ mac_trx_wakeup(); /* Set transceiver in rx * mode, otherwise it * may stay in * TRX_OFF). */ tal_rx_enable(PHY_RX_ON); if (tal_pib. SuperFrameOrder < tal_pib . BeaconOrder) { pal_timer_start( T_Superframe, TAL_CONVERT_SYMBOLS_TO_US( TAL_GET_SUPERFRAME_DURATION_TIME( tal_pib . SuperFrameOrder)), TIMEOUT_RELATIVE, ( FUNC_PTR)mac_t_start_inactive_device_cb, NULL); #ifdef GTS_DEBUG port_pin_set_output_level( DEBUG_PIN2, 1); #endif } #ifdef GTS_SUPPORT if (mac_final_cap_slot < FINAL_CAP_SLOT_DEFAULT) { uint32_t gts_tx_time = ( TAL_CONVERT_SYMBOLS_TO_US( TAL_GET_SUPERFRAME_DURATION_TIME( tal_pib . SuperFrameOrder)) >> 4) * ( mac_final_cap_slot + 1); pal_timer_start( T_CAP, gts_tx_time, TIMEOUT_RELATIVE, ( FUNC_PTR)mac_t_gts_cb, NULL); #ifdef GTS_DEBUG port_pin_set_output_level( DEBUG_PIN3, 1); #endif } #endif /* GTS_SUPPORT */ } /* Initialize missed beacon * timer. */ mac_start_missed_beacon_timer(); /* A device that is neither * scanning nor polling shall go * to sleep now. */ if ( (MAC_COORDINATOR != mac_state) && (MAC_SCAN_IDLE == mac_scan_state) && (MAC_POLL_IDLE == mac_poll_state) ) { /* * If the last received * beacon frame from our * parent * has indicated pending * broadbast data, we * need to * stay awake, until the * broadcast data has * been received. */ if (! mac_bc_data_indicated) { /* Set radio to * sleep if * allowed */ mac_sleep_trans(); } } } else if (MAC_SYNC_ONCE == mac_sync_state) { mac_process_beacon_frame(b_ptr); /* Do this after processing the * beacon. */ mac_sync_state = MAC_SYNC_NEVER; /* A device that is neither * scanning nor polling shall go * to sleep now. */ if ( (MAC_COORDINATOR != mac_state) && (MAC_SCAN_IDLE == mac_scan_state) && (MAC_POLL_IDLE == mac_poll_state) ) { /* * If the last received * beacon frame from our * parent * has indicated pending * broadbast data, we * need to * stay awake, until the * broadcast data has * been received. */ if (! mac_bc_data_indicated) { /* Set radio to * sleep if * allowed */ mac_sleep_trans(); } } } else { /* Process the beacon frame */ bmm_buffer_free(b_ptr); } processed_in_not_transient = true; } else {
void bc_data_cb(frame_info_t *transmit_frame) { uint8_t index; index = nwkFindPassiveAck(transmit_frame->NwkFrameHeader->srcAddr, transmit_frame->NwkFrameHeader->sequenceNumber); if (index != 0xFF) { if (gNwkPassiveAckTable.table[index].end == false) { do { if (gNwkPassiveAckTable.table[index].realyNeighborNum >= neighborTable.size) break; while (transmit_frame->AppFrameHeader->frameControl.tries != 0)//以后要用这个NWK_MAX_BROADCAST_RETRIES { transmit_frame->AppFrameHeader->AppPayload[transmit_frame->AppFrameHeader->length] ^= transmit_frame->AppFrameHeader->frameControl.tries; transmit_frame->AppFrameHeader->frameControl.tries--; transmit_frame->AppFrameHeader->AppPayload[transmit_frame->AppFrameHeader->length] ^= transmit_frame->AppFrameHeader->frameControl.tries; //mac_trx_wakeup(); retval_t status = FAILURE; transmit_frame->mpdu[3] = mac_pib.mac_DSN++; /* In Nonbeacon build the frame is sent with unslotted CSMA-CA. */ status = tal_tx_frame(transmit_frame, CSMA_UNSLOTTED, true); if (MAC_SUCCESS == status) { MAKE_MAC_BUSY(); /* Start timer to initiate next broadcast data transmission. */ pal_timer_start(gNwkPassiveAckTable.table[index].timerID, ((uint32_t)NWK_PASSIVE_ACK_TIMEOUT), TIMEOUT_RELATIVE, (FUNC_PTR)bc_data_cb, transmit_frame); gNwkPassiveAckTable.table[index].reTryTimes++; } else { break; } return; } }while(0); NwkState = NWK_MODULE_NONE; pal_timer_start(gNwkPassiveAckTable.table[index].timerID, ((uint32_t) (NWK_BROADCAST_DELIVERY_TIME-(gNwkPassiveAckTable.table[index].reTryTimes+1)*NWK_PASSIVE_ACK_TIMEOUT)), TIMEOUT_RELATIVE, (FUNC_PTR)bc_data_cb, transmit_frame); gNwkPassiveAckTable.table[index].end = true; return; } gNwkPassiveAckTable.table[index].end = false; gNwkPassiveAckTable.table[index].reTryTimes = 0; nwkFreePassiveAck(transmit_frame->NwkFrameHeader->srcAddr, transmit_frame->NwkFrameHeader->sequenceNumber); if (transmit_frame != NULL) bmm_buffer_free(transmit_frame->buffer_header); //NwkState = NWK_MODULE_NONE; mac_sleep_trans(); } }