retval_t mac_timers_stop(void) { #if (NUMBER_OF_MAC_TIMERS > 0) #ifdef BEACON_SUPPORT pal_timer_stop(T_Beacon_Tracking_Period); pal_timer_stop(T_Superframe); pal_timer_stop(T_Missed_Beacon); #if (MAC_START_REQUEST_CONFIRM == 1) pal_timer_stop(T_Beacon); pal_timer_stop(T_Beacon_Preparation); #endif /* (MAC_START_REQUEST_CONFIRM == 1) */ #ifdef GTS_SUPPORT pal_timer_stop(T_CAP); #endif /* GTS_SUPPORT */ #endif /* BEACON_SUPPORT / No BEACON_SUPPORT */ #if (MAC_INDIRECT_DATA_BASIC == 1) pal_timer_stop(T_Poll_Wait_Time); #if (MAC_INDIRECT_DATA_FFD == 1) pal_timer_stop(T_Data_Persistence); #endif /* (MAC_INDIRECT_DATA_FFD == 1) */ #endif /* (MAC_INDIRECT_DATA_BASIC == 1) */ #if (MAC_SCAN_SUPPORT == 1) pal_timer_stop(T_Scan_Duration); #endif /* MAC_SCAN_SUPPORT */ #if (MAC_RX_ENABLE_SUPPORT == 1) pal_timer_stop(T_Rx_Enable); #endif /* MAC_RX_ENABLE_SUPPORT */ #endif /* (NUMBER_OF_MAC_TIMERS != 0) */ return MAC_SUCCESS; }
static void tal_timers_stop(void) { #if (NUMBER_OF_TAL_TIMERS > 0) #ifdef BEACON_SUPPORT /* Beacon Support */ #ifdef ENABLE_FTN_PLL_CALIBRATION pal_timer_stop(TAL_CSMA_CCA); pal_timer_stop(TAL_CSMA_BEACON_LOSS_TIMER); pal_timer_stop(TAL_CALIBRATION); #ifdef SW_CONTROLLED_CSMA pal_timer_stop(TAL_T_BOFF); #endif #else pal_timer_stop(TAL_CSMA_CCA); pal_timer_stop(TAL_CSMA_BEACON_LOSS_TIMER); #ifdef SW_CONTROLLED_CSMA pal_timer_stop(TAL_T_BOFF); #endif #endif /* ENABLE_FTN_PLL_CALIBRATION */ #else /* No BEACON_SUPPORT */ #ifdef ENABLE_FTN_PLL_CALIBRATION pal_timer_stop(TAL_CALIBRATION); #ifdef SW_CONTROLLED_CSMA pal_timer_stop(TAL_T_BOFF); #endif #else #ifdef SW_CONTROLLED_CSMA pal_timer_stop(TAL_T_BOFF); #endif #endif /* ENABLE_FTN_PLL_CALIBRATION */ #endif /* BEACON_SUPPORT */ #endif /* (NUMBER_OF_TAL_TIMERS > 0) */ }
/** * @brief Sets the transceiver to sleep * * This function sets the transceiver to sleep state. * * @param mode Defines sleep mode of transceiver SLEEP or PHY_TRX_OFF) * * @return TAL_BUSY - The transceiver is busy in TX or RX * MAC_SUCCESS - The transceiver is put to sleep * TAL_TRX_ASLEEP - The transceiver is already asleep * MAC_INVALID_PARAMETER - The specified sleep mode is not supported */ retval_t tal_trx_sleep(sleep_mode_t mode) { tal_trx_status_t trx_status; /* Current transceiver only supports SLEEP_MODE_1 mode. */ if (SLEEP_MODE_1 != mode) { return MAC_INVALID_PARAMETER; } if (tal_trx_status == TRX_SLEEP) { return TAL_TRX_ASLEEP; } /* Device can be put to sleep only when the TAL is in IDLE state. */ if (TAL_IDLE != tal_state) { return TAL_BUSY; } tal_rx_on_required = false; /* * First set trx to TRX_OFF. * If trx is busy, like ACK transmission, do not interrupt it. */ do { trx_status = set_trx_state(CMD_TRX_OFF); } while (trx_status != TRX_OFF); pal_timer_source_select(TMR_CLK_SRC_DURING_TRX_SLEEP); trx_status = set_trx_state(CMD_SLEEP); #ifdef ENABLE_FTN_PLL_CALIBRATION /* * Stop the calibration timer now. * The timer will be restarted during wake-up. */ pal_timer_stop(TAL_CALIBRATION); #endif /* ENABLE_FTN_PLL_CALIBRATION */ if (trx_status == TRX_SLEEP) { #ifdef STB_ON_SAL #if (SAL_TYPE == AT86RF2xx) stb_restart(); #endif #endif return MAC_SUCCESS; } else { /* State could not be set due to TAL_BUSY state. */ return TAL_BUSY; } }
/** * @brief Processes a data response to an MLME-POLL.request * * This function processes a data response to an MLME-POLL.request. * Our coordinator has responded with a data frame. It is checked * whether any data has been received, and the appropriate * MLME-POLL.confirm message is constructed. */ void mac_process_data_response(void) { uint8_t status; if (FCF_FRAMETYPE_BEACON == mac_parse_data.frame_type) { /* * Node is currently in polling state, so only command or data * frames * are of interest. * This is an unexpected frame type, do nothing. * Note. Ack frames are not uploaded to this point. * All subsequent actions are not to be done now. * Instead the timer will expire and initiate the proper stuff. */ return; } else { /* Stop the MaxFrameResponseTime timer */ pal_timer_stop(T_Poll_Wait_Time); #if (_DEBUG_ > 0) if (pal_is_timer_running(T_Poll_Wait_Time)) { Assert("Frame resp tmr running" == 0); } #endif /* * For received command frames (Association response or * disassociation notification) and for data frames with zero * payload length the potential status for the poll.confirm * message * is supposed to be "No data". */ status = MAC_NO_DATA; if ((FCF_FRAMETYPE_DATA == mac_parse_data.frame_type) && (mac_parse_data.mac_payload_length > 0) ) { /* * For received data frames with non-zero payload length * the potential status for the poll.confirm message is * supposed to be "Success". */ status = MAC_SUCCESS; } } if (MAC_POLL_EXPLICIT == mac_poll_state) { /* * Data is received on explicit poll request, hence generate the * poll confirm using * the buffer which was stored in mac_conf_buf_ptr. */ gen_mlme_poll_conf((buffer_t *)mac_conf_buf_ptr, status); } /* MAC was busy during poll. */ MAKE_MAC_NOT_BUSY(); mac_poll_state = MAC_POLL_IDLE; } /* mac_process_data_response() */
/* * @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 Sets the transceiver to sleep * * This function sets the transceiver to sleep state. * * \param mode Defines sleep mode of transceiver SLEEP or PHY_TRX_OFF) * * \return TAL_BUSY - The transceiver is busy in TX or RX * MAC_SUCCESS - The transceiver is put to sleep * TAL_TRX_ASLEEP - The transceiver is already asleep * MAC_INVALID_PARAMETER - The specified sleep mode is not supported */ retval_t tal_trx_sleep(sleep_mode_t mode) { tal_trx_status_t trx_status; /* Current transceiver only supports SLEEP_MODE_1 mode. */ if (SLEEP_MODE_1 != mode) { return MAC_INVALID_PARAMETER; } if (tal_trx_status == TRX_SLEEP) { return TAL_TRX_ASLEEP; } /* Device can be put to sleep only when the TAL is in IDLE state. */ if (TAL_IDLE != tal_state) { return TAL_BUSY; } tal_rx_on_required = false; /* * First set trx to TRX_OFF. * If trx is busy, like ACK transmission, do not interrupt it. */ do { trx_status = set_trx_state(CMD_TRX_OFF); } while (trx_status != TRX_OFF); #ifndef NO_32KHZ_CRYSTAL /* Do not set to SLEEP to keep clock source for symbol counter alive. */ trx_status = set_trx_state(CMD_SLEEP); #else /* Pretend that trx is in SLEEP - for this function only. */ trx_status = TRX_SLEEP; #endif #ifdef ENABLE_FTN_PLL_CALIBRATION /* * Stop the calibration timer now. * The timer will be restarted during wake-up. */ pal_timer_stop(TAL_CALIBRATION); #endif /* ENABLE_FTN_PLL_CALIBRATION */ if (trx_status == TRX_SLEEP) { #ifdef STB_ON_SAL stb_restart(); #endif return MAC_SUCCESS; } else { /* State could not be set due to TAL_BUSY state. */ return TAL_BUSY; } }
/* * @brief 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 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 Transceiver interrupt handler * * This function handles the transceiver generated interrupts. */ void trx_irq_handler_cb(void) { trx_irq_reason_t trx_irq_cause; trx_irq_cause = (trx_irq_reason_t)trx_reg_read(RG_IRQ_STATUS); #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) #if (ANTENNA_DIVERSITY == 1) || (DISABLE_TSTAMP_IRQ == 1) if (trx_irq_cause & TRX_IRQ_RX_START) { /* * Get timestamp. * * In case Antenna diversity is used or the utilization of * the Timestamp IRQ is disabled, the timestamp needs to be read * now * the "old-fashioned" way. * * The timestamping is generally only done for * beaconing networks or if timestamping is explicitly enabled. */ pal_trx_read_timestamp(&tal_rx_timestamp); } #endif /* #if (ANTENNA_DIVERSITY == 1) || (DISABLE_TSTAMP_IRQ == 1) */ #endif /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */ if (trx_irq_cause & TRX_IRQ_TRX_END) { /* * TRX_END reason depends on if the trx is currently used for * transmission or reception. */ #if ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) if ((tal_state == TAL_TX_AUTO) || tal_beacon_transmission) #else if (tal_state == TAL_TX_AUTO) #endif { /* Get the result and push it to the queue. */ if (trx_irq_cause & TRX_IRQ_TRX_UR) { handle_tx_end_irq(true); /* see tal_tx.c */ } else { handle_tx_end_irq(false); /* see tal_tx.c */ } } else { /* Other tal_state than TAL_TX_... */ /* Handle rx interrupt. */ handle_received_frame_irq(); /* see tal_rx.c */ #if (defined SW_CONTROLLED_CSMA) && (defined RX_WHILE_BACKOFF) if (tal_state == TAL_BACKOFF) { pal_timer_stop(TAL_T_BOFF); tal_state = TAL_CSMA_CONTINUE; } #endif } } #if (ANTENNA_DIVERSITY == 1) else if (trx_irq_cause & TRX_IRQ_RX_START) { /* * The antenna that has been selected automatically for the * current frame * reception is set for the ACK transmission too. */ if (trx_bit_read(SR_ANT_SEL) == ANT_SEL_ANTENNA_0) { trx_bit_write(SR_ANT_CTRL, ANT_CTRL_1); } else { /* antenna 1 is in use */ trx_bit_write(SR_ANT_CTRL, ANT_CTRL_2); } } #endif } /* trx_irq_handler_cb() */
/** * @brief Depending on received frame the appropriate function is called * * @param msg Pointer to the buffer header. */ void mac_process_tal_data_ind(uint8_t *msg) { buffer_t *buf_ptr = (buffer_t *)msg; frame_info_t *frameptr = (frame_info_t *)BMM_BUFFER_POINTER(buf_ptr); bool processed_tal_data_indication = false; mac_parse_data.mpdu_length = frameptr->mpdu[0]; /* First extract LQI since this is already needed in Promiscuous Mode. **/ mac_parse_data.ppdu_link_quality = frameptr->mpdu[mac_parse_data.mpdu_length + LQI_LEN]; #ifdef PROMISCUOUS_MODE if (tal_pib.PromiscuousMode) { /* * In promiscuous mode all received frames are forwarded to the * higher layer or application my means of MCPS_DATA.indication * primitives. */ prom_mode_rx_frame(buf_ptr, frameptr); return; } #endif /* PROMISCUOUS_MODE */ if (!parse_mpdu(frameptr)) { /* Frame parsing failed */ bmm_buffer_free(buf_ptr); return; } /* Check if the MAC is busy processing the previous requests */ if (mac_busy) { /* * If MAC has to process an incoming frame that requires a * response * (i.e. beacon request and data request) then process this * operation * once the MAC has become free. Put the request received back * into the * MAC internal event queue. */ if (FCF_FRAMETYPE_MAC_CMD == mac_parse_data.frame_type) { if (DATAREQUEST == mac_parse_data.mac_command || BEACONREQUEST == mac_parse_data.mac_command) { qmm_queue_append(&tal_mac_q, buf_ptr); return; } } } switch (mac_poll_state) { case MAC_POLL_IDLE: /* * We are in no transient state. * Now are either in a non-transient MAC state or scanning. */ if (MAC_SCAN_IDLE == mac_scan_state) { /* * Continue with handling the "real" non-transient MAC * states now. */ processed_tal_data_indication = process_data_ind_not_transient( buf_ptr, frameptr); } #if (MAC_SCAN_SUPPORT == 1) else { /* Scanning is ongoing. */ processed_tal_data_indication = process_data_ind_scanning(buf_ptr); } #endif /* (MAC_SCAN_SUPPORT == 1) */ break; #if (MAC_INDIRECT_DATA_BASIC == 1) /* * This is the 'wait for data' state after either * explicit poll or implicit poll. */ case MAC_POLL_EXPLICIT: case MAC_POLL_IMPLICIT: /* * Function mac_process_data_response() resets the * MAC poll state. */ mac_process_data_response(); 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(buf_ptr); processed_tal_data_indication = true; break; #endif /* (MAC_ASSOCIATION_INDICATION_RESPONSE == 1) */ #if (MAC_DISASSOCIATION_BASIC_SUPPORT == 1) case DISASSOCIATIONNOTIFICATION: { mac_process_disassociate_notification(buf_ptr); processed_tal_data_indication = true; /* * Device needs to scan for networks again, * go into idle mode and reset variables */ mac_idle_trans(); } break; #endif /* (MAC_DISASSOCIATION_BASIC_SUPPORT == 1) */ case DATAREQUEST: #if (MAC_INDIRECT_DATA_FFD == 1) if (indirect_data_q.size > 0) { mac_process_data_request(buf_ptr); processed_tal_data_indication = true; } else { mac_handle_tx_null_data_frame(); } #endif /* (MAC_INDIRECT_DATA_FFD == 1) */ break; case PANIDCONFLICTNOTIFICAION: break; #if (MAC_ORPHAN_INDICATION_RESPONSE == 1) case ORPHANNOTIFICATION: mac_process_orphan_notification(buf_ptr); processed_tal_data_indication = true; break; #endif /* (MAC_ORPHAN_INDICATION_RESPONSE == 1) */ #if (MAC_START_REQUEST_CONFIRM == 1) case BEACONREQUEST: if (MAC_COORDINATOR == mac_state) { /* * Only a Coordinator can both poll and * AND answer beacon request frames. * PAN Coordinators do not poll; * End devices do not answer beacon * requests. */ mac_process_beacon_request(buf_ptr); processed_tal_data_indication = true; } break; #endif /* (MAC_START_REQUEST_CONFIRM == 1) */ #if (MAC_SYNC_LOSS_INDICATION == 1) case COORDINATORREALIGNMENT: /* * Received coordinator realignment frame for * entire PAN. */ mac_process_coord_realign(buf_ptr); processed_tal_data_indication = true; break; #endif /* (MAC_SYNC_LOSS_INDICATION == 1) */ default: #if (_DEBUG_ > 0) Assert( "Unsupported MAC frame in state MAC_EXPLICIT_POLL or MAC_POLL_IMPLICIT" == 0); #endif break; } } break; /* case FCF_FRAMETYPE_MAC_CMD: */ case FCF_FRAMETYPE_DATA: mac_process_data_frame(buf_ptr); processed_tal_data_indication = true; break; default: break; } break; /* MAC_POLL_EXPLICIT, MAC_POLL_IMPLICIT */ #endif /* (MAC_INDIRECT_DATA_BASIC == 1) */ #if (MAC_ASSOCIATION_REQUEST_CONFIRM == 1) case MAC_AWAIT_ASSOC_RESPONSE: /* * We are either expecting an association reponse frame * or a null data frame. */ if ((FCF_FRAMETYPE_MAC_CMD == mac_parse_data.frame_type) && (ASSOCIATIONRESPONSE == mac_parse_data.mac_command) ) { /* This is the expected association response frame. */ pal_timer_stop(T_Poll_Wait_Time); #if (_DEBUG_ > 0) if (pal_is_timer_running(T_Poll_Wait_Time)) { Assert( "T_Poll_Wait_Time tmr during association running" == 0); } #endif mac_process_associate_response(buf_ptr); processed_tal_data_indication = true; } else if (FCF_FRAMETYPE_DATA == mac_parse_data.frame_type) { mac_process_data_frame(buf_ptr); processed_tal_data_indication = true; } break; /* MAC_AWAIT_ASSOC_RESPONSE */ #endif /* (MAC_ASSOCIATION_REQUEST_CONFIRM == 1) */ default: #if (_DEBUG_ > 0) Assert("Received frame in unsupported MAC poll state" == 0); #endif break; } /* If message is not processed */ if (!processed_tal_data_indication) { bmm_buffer_free(buf_ptr); } } /* mac_process_tal_data_ind() */
/** * @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; }
/** * @brief Continues processing a data indication from the TAL for * scanning states of the MAC (mac_scan_state == MAC_SCAN_IDLE). * * @param b_ptr Pointer to the buffer header. * * @return bool True if frame has been processed, or false otherwise. */ static bool process_data_ind_scanning(buffer_t *b_ptr) { bool processed_in_scanning = false; /* * We are in a scanning process now (mac_scan_state is not * MAC_SCAN_IDLE), * so continue with the specific scanning states. */ switch (mac_scan_state) { #if (MAC_SCAN_ED_REQUEST_CONFIRM == 1) /* Energy Detect scan */ case MAC_SCAN_ED: /* * Ignore all frames received while performing ED measurement, * or while performing CCA. */ b_ptr = b_ptr; /* Keep compiler happy. */ break; #endif /* (MAC_SCAN_ED_REQUEST_CONFIRM == 1) */ #if ((MAC_SCAN_PASSIVE_REQUEST_CONFIRM == 1) || \ (MAC_SCAN_ACTIVE_REQUEST_CONFIRM == 1)) /* Active scan or passive scan */ case MAC_SCAN_ACTIVE: case MAC_SCAN_PASSIVE: if (FCF_FRAMETYPE_BEACON == mac_parse_data.frame_type) { #if (MAC_PAN_ID_CONFLICT_AS_PC == 1) /* PAN-Id conflict detection as PAN-Coordinator. */ if (MAC_PAN_COORD_STARTED == mac_state) { /* Node is currently scanning. */ check_for_pan_id_conflict_as_pc(true); } #endif /* (MAC_PAN_ID_CONFLICT_AS_PC == 1) */ #if (MAC_PAN_ID_CONFLICT_NON_PC == 1) if (mac_pib.mac_AssociatedPANCoord && ((MAC_ASSOCIATED == mac_state) || (MAC_COORDINATOR == mac_state)) ) { check_for_pan_id_conflict_non_pc(true); } #endif /* (MAC_PAN_ID_CONFLICT_NON_PC == 1) */ mac_process_beacon_frame(b_ptr); processed_in_scanning = true; } break; #endif /* ((MAC_SCAN_PASSIVE_REQUEST_CONFIRM == 1) || *(MAC_SCAN_ACTIVE_REQUEST_CONFIRM == 1)) */ #if (MAC_SCAN_ORPHAN_REQUEST_CONFIRM == 1) /* Orphan scan */ case MAC_SCAN_ORPHAN: if (FCF_FRAMETYPE_MAC_CMD == mac_parse_data.frame_type && COORDINATORREALIGNMENT == mac_parse_data.mac_command) { /* * Received coordinator realignment frame in the middle * of * an orphan scan. */ pal_timer_stop(T_Scan_Duration); mac_process_orphan_realign(b_ptr); processed_in_scanning = true; } break; #endif /* (MAC_SCAN_ORPHAN_REQUEST_CONFIRM == 1) */ default: { #if (_DEBUG_ > 0) Assert( "Unexpected TAL data indication while checking mac_scan_state" == 0); #endif } break; } return (processed_in_scanning); }
/** * @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 {
/** * @brief Implements the MLME-SYNC request. * * The MLME-SYNC.request primitive requests to synchronize with the * coordinator by acquiring and, if specified, tracking its beacons. * The MLME-SYNC.request primitive is generated by the next higher layer of a * device on a beacon-enabled PAN and issued to its MLME to synchronize with * the coordinator. * * Enable receiver and search for beacons for at most an interval of * [aBaseSuperframeDuration * ((2 ^ (n))+ 1)] symbols where n is the value of * macBeaconOrder. If a beacon frame containing the current PAN identifier of * the device is not received, the MLME shall repeat this search. Once the * number of missed beacons reaches aMaxLostBeacons, the MLME shall notify * the next higher layer by issuing the MLME-SYNC-LOSS.indication primitive * with a loss reason of BEACON_LOSS. * * @param m Pointer to the MLME sync request parameters. */ void mlme_sync_request(uint8_t *m) { #if (DEBUG > 0) retval_t set_status, set_status_2; #endif mlme_sync_req_t *msr = (mlme_sync_req_t *)BMM_BUFFER_POINTER((buffer_t *)m); /* * Sync is only allowed for nodes that are: * 1) Devices (also before association.) or coordinators * (no PAN coordinators), * 2) Currently NOT polling, and * 3) Currently NOT scanning. */ if ( #if (MAC_START_REQUEST_CONFIRM == 1) (MAC_PAN_COORD_STARTED == mac_state) || #endif /* (MAC_START_REQUEST_CONFIRM == 1) */ (MAC_POLL_IDLE != mac_poll_state) || (MAC_SCAN_IDLE != mac_scan_state) ) { /* Free the buffer allocated for MLME-SYNC-Request */ bmm_buffer_free((buffer_t *)m); mac_sync_loss(MAC_BEACON_LOSS); return; } /* Stop the beacon tracking period timer. */ 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 /* Set MAC Sync state properly. */ if (MAC_IDLE == mac_state) { /* * We try to sync before association. * This is a special sync state that checks beacon frames similar to * MAC_SYNC_TRACKING_BEACON while being associated. * * Before this state can be entered successfully a number of PIB * attributes have to be set properly: * 1) PAN-Id (macPANId) * 2) Coordinator Short or Long address (depending upon which type * of addressing the coordinator is using) * (macCoordShortAddress or mac macCoordExtendedAddress) * * Furthermore it is strongly recommended to set the Beacon order and * Superframe order (macBeaconOrder, macSuperframeOrder). * If these parameters are not set and the node tries to sync with a * network, where it never receives a beacon from, the missed beacon * timer (required for reporting a sync loss condition) will start * with a huge time value (based on a beacon order = 15). * If finally a beacon is received from the desired network, the timer * will be updated. * Nevertheless setting the PIB attributes before sync is safer. */ mac_sync_state = MAC_SYNC_BEFORE_ASSOC; } else { if (msr->TrackBeacon) { mac_sync_state = MAC_SYNC_TRACKING_BEACON; } else { mac_sync_state = MAC_SYNC_ONCE; } } /* Wake up radio first */ mac_trx_wakeup(); #if (DEBUG > 0) set_status = #endif set_tal_pib_internal(phyCurrentPage, (void *)&(msr->ChannelPage)); #if (DEBUG > 0) ASSERT(MAC_SUCCESS == set_status); #endif #if (DEBUG > 0) set_status_2 = #endif set_tal_pib_internal(phyCurrentChannel, (void *)&(msr->LogicalChannel)); #if (DEBUG > 0) ASSERT(MAC_SUCCESS == set_status_2); #endif mac_start_missed_beacon_timer(); /* Start synching by switching ON the receiver. */ tal_rx_enable(PHY_RX_ON); /* Free the buffer allocated by the higher layer */ bmm_buffer_free((buffer_t *)m); }
/** * \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 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 Transceiver interrupt handler * * This function handles the transceiver generated interrupts. */ void trx_irq_handler_cb(void) { trx_irq_reason_t trx_irq_cause; trx_irq_cause = (trx_irq_reason_t)pal_trx_reg_read(RG_IRQ_STATUS); #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) #if (DISABLE_TSTAMP_IRQ == 1) if (trx_irq_cause & TRX_IRQ_2_RX_START) { /* * Get timestamp. * * In case Antenna diversity is used or the utilization of * the Timestamp IRQ is disabled, the timestamp needs to be read *now * the "old-fashioned" way. * * The timestamping is generally only done for * beaconing networks or if timestamping is explicitly enabled. */ pal_trx_read_timestamp(&tal_rx_timestamp); } #endif /* #if (DISABLE_TSTAMP_IRQ == 1) */ #endif /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */ if (trx_irq_cause & TRX_IRQ_3_TRX_END) { /* * TRX_END reason depends on if the trx is currently used for * transmission or reception. */ #if ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) if ((tal_state == TAL_TX_AUTO) || tal_beacon_transmission) #else if (tal_state == TAL_TX_AUTO) #endif { /* Get the result and push it to the queue. */ if (trx_irq_cause & TRX_IRQ_6_TRX_UR) { handle_tx_end_irq(true); /* see tal_tx.c */ } else { handle_tx_end_irq(false); /* see tal_tx.c */ } } else { /* Other tal_state than TAL_TX_... */ /* Handle rx interrupt. */ handle_received_frame_irq(); /* see tal_rx.c */ #if (defined SW_CONTROLLED_CSMA) && (defined RX_WHILE_BACKOFF) if (tal_state == TAL_BACKOFF) { pal_timer_stop(TAL_T_BOFF); tal_state = TAL_CSMA_CONTINUE; } #endif } } #if (_DEBUG_ > 0) /* Other IRQ than TRX_END */ if (trx_irq_cause != TRX_IRQ_3_TRX_END) { /* PLL_LOCK interrupt migth be set, because poll mode is *enabled. */ /* * if (trx_irq_cause & TRX_IRQ_0_PLL_LOCK) * { * Assert("unexpected IRQ: TRX_IRQ_0_PLL_LOCK" == 0); * } */ if (trx_irq_cause & TRX_IRQ_1_PLL_UNLOCK) { Assert("unexpected IRQ: TRX_IRQ_1_PLL_UNLOCK" == 0); } /* RX_START interrupt migth be set, because poll mode is *enabled. */ /* * if (trx_irq_cause & TRX_IRQ_2_RX_START) * { * Assert("unexpected IRQ: TRX_IRQ_2_RX_START" == 0); * } */ if (trx_irq_cause & TRX_IRQ_4_CCA_ED_DONE) { Assert("unexpected IRQ: TRX_IRQ_4_CCA_ED_DONE" == 0); } /* AMI interrupt might set, because poll mode is enabled. */ /* * if (trx_irq_cause & TRX_IRQ_5_AMI) * { * Assert("unexpected IRQ: TRX_IRQ_5_AMI" == 0); * } */ if (trx_irq_cause & TRX_IRQ_6_TRX_UR) { Assert("unexpected IRQ: TRX_IRQ_6_TRX_UR" == 0); } if (trx_irq_cause & TRX_IRQ_7_BAT_LOW) { Assert("unexpected IRQ: TRX_IRQ_7_BAT_LOW" == 0); } } #endif } /* trx_irq_handler_cb() */
/** * \brief State machine handling slotted CSMA */ void slotted_csma_state_handling(void) { switch (tal_csma_state) { case BACKOFF_WAITING_FOR_CCA_TIMER: break; case BACKOFF_WAITING_FOR_BEACON: /* * Do not perform any operation and wait until the next beacon * reception. If several beacons are not received, the beacon * loss * timer expires and stops the entire transaction. */ break; case CSMA_HANDLE_BEACON: /* debug pin to switch on: define ENABLE_DEBUG_PINS, * pal_config.h */ PIN_WAITING_FOR_BEACON_END(); PIN_BEACON_LOSS_TIMER_END(); pal_timer_stop(TAL_CSMA_BEACON_LOSS_TIMER); csma_backoff_calculation(); break; case CSMA_ACCESS_FAILURE: NB++; BE++; /* ensure that BE is no more than macMaxBE */ if (BE > tal_pib.MaxBE) { /* macMaxBE */ BE = tal_pib.MaxBE; /* macMaxBE */ } if (NB > macMaxCSMABackoffs) { /* terminate with channel access failure */ tx_done(MAC_CHANNEL_ACCESS_FAILURE); } else { /* restart backoff */ csma_backoff_calculation(); } break; case NO_BEACON_TRACKING: /* terminate with channel access failure */ tx_done(MAC_CHANNEL_ACCESS_FAILURE); break; case FRAME_SENDING: /* waiting for end of frame transmission */ break; case TX_DONE_SUCCESS: tx_done(MAC_SUCCESS); break; case TX_DONE_FRAME_PENDING: tx_done(TAL_FRAME_PENDING); break; case TX_DONE_NO_ACK: if (number_of_tx_retries < tal_pib.MaxFrameRetries) { number_of_tx_retries++; set_trx_state(CMD_RX_AACK_ON); /* * Start the entire CSMA procedure again, * but do not reset the number of transmission attempts. */ BE++; /* ensure that BE is no more than macMaxBE */ if (BE > tal_pib.MaxBE) { /* macMaxBE */ BE = tal_pib.MaxBE; /* macMaxBE */ } NB = 0; remaining_backoff_periods = (uint8_t)(rand() & ((1 << BE) - 1)); csma_backoff_calculation(); } else { tx_done(MAC_NO_ACK); } PIN_NO_ACK_END(); break; default: Assert("INVALID CSMA status" == 0); break; } } /* csma_ca_state_handling() */
static void tal_timers_stop(void) { #if (NUMBER_OF_TAL_TIMERS > 0) #if ((MAC_SCAN_ED_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) #ifdef ENABLE_FTN_PLL_CALIBRATION pal_timer_stop(TAL_ACK_WAIT_TIMER); pal_timer_stop(TAL_ED_SCAN_DURATION_TIMER); pal_timer_stop(TAL_ED_SAMPLE_TIMER); pal_timer_stop(TAL_CSMA_CCA); pal_timer_stop(TAL_CSMA_BEACON_LOSS_TIMER); pal_timer_stop(TAL_CALIBRATION); #else pal_timer_stop(TAL_ACK_WAIT_TIMER); pal_timer_stop(TAL_ED_SCAN_DURATION_TIMER); pal_timer_stop(TAL_ED_SAMPLE_TIMER); pal_timer_stop(TAL_CSMA_CCA); pal_timer_stop(TAL_CSMA_BEACON_LOSS_TIMER); #endif /* ENABLE_FTN_PLL_CALIBRATION */ #endif /* ED Scan is switched on */ /* No beacon support */ #if ((MAC_SCAN_ED_REQUEST_CONFIRM == 1) && (!defined BEACON_SUPPORT)) #ifdef ENABLE_FTN_PLL_CALIBRATION pal_timer_stop(TAL_ED_SCAN_DURATION_TIMER); pal_timer_stop(TAL_ED_SAMPLE_TIMER); pal_timer_stop(TAL_CALIBRATION); #else pal_timer_stop(TAL_ED_SCAN_DURATION_TIMER); pal_timer_stop(TAL_ED_SAMPLE_TIMER); #endif /* ENABLE_FTN_PLL_CALIBRATION */ #endif /* ED Scan is switched off */ /* Network with beacon support */ #if ((MAC_SCAN_ED_REQUEST_CONFIRM == 0) && (defined BEACON_SUPPORT)) #ifdef ENABLE_FTN_PLL_CALIBRATION pal_timer_stop(TAL_ACK_WAIT_TIMER); pal_timer_stop(TAL_CSMA_CCA); pal_timer_stop(TAL_CSMA_BEACON_LOSS_TIMER); pal_timer_stop(TAL_CALIBRATION); #else pal_timer_stop(TAL_ACK_WAIT_TIMER); pal_timer_stop(TAL_CSMA_CCA); pal_timer_stop(TAL_CSMA_BEACON_LOSS_TIMER); #endif /* ENABLE_FTN_PLL_CALIBRATION */ #endif /* ED Scan is switched off */ /* No beacon support */ #if ((MAC_SCAN_ED_REQUEST_CONFIRM == 0) && (!defined BEACON_SUPPORT)) #ifdef ENABLE_FTN_PLL_CALIBRATION pal_timer_stop(TAL_CALIBRATION); #endif /* ENABLE_FTN_PLL_CALIBRATION */ #endif #endif /* (NUMBER_OF_TAL_TIMERS > 0) */ }