/* * \brief Handles interrupts issued due to end of transmission * * \param underrun_occured true if under-run has occurred */ void handle_tx_end_irq(bool underrun_occured) { #if ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) if (tal_beacon_transmission) { tal_beacon_transmission = false; if (tal_csma_state == BACKOFF_WAITING_FOR_BEACON) { /* Slotted CSMA has been waiting for a beacon, now it * can continue. */ tal_csma_state = CSMA_HANDLE_BEACON; } } else #endif /* ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) */ { #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) /* * Store tx timestamp to frame_info_t structure. * The timestamping is only required for beaconing networks * or if timestamping is explicitly enabled. */ pal_trx_read_timestamp(&mac_frame_ptr->time_stamp); #endif /* #if (defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP) */ /* Read trac status before enabling RX_AACK_ON. */ if (underrun_occured) { trx_trac_status = TRAC_INVALID; } else { trx_trac_status = (trx_trac_status_t)trx_bit_read( SR_TRAC_STATUS); } #ifdef BEACON_SUPPORT if (tal_csma_state == FRAME_SENDING) { /* Transmission was * issued by slotted CSMA **/ PIN_TX_END(); tal_state = TAL_SLOTTED_CSMA; /* Map status message of transceiver to TAL constants. **/ switch (trx_trac_status) { case TRAC_SUCCESS_DATA_PENDING: PIN_ACK_OK_START(); tal_csma_state = TX_DONE_FRAME_PENDING; break; case TRAC_SUCCESS: PIN_ACK_OK_START(); tal_csma_state = TX_DONE_SUCCESS; break; case TRAC_CHANNEL_ACCESS_FAILURE: PIN_NO_ACK_START(); tal_csma_state = CSMA_ACCESS_FAILURE; break; case TRAC_NO_ACK: PIN_NO_ACK_START(); tal_csma_state = TX_DONE_NO_ACK; break; case TRAC_INVALID: /* Handle this in the same way as * default. */ default: Assert("not handled trac status" == 0); tal_csma_state = CSMA_ACCESS_FAILURE; break; } PIN_ACK_OK_END(); PIN_ACK_WAITING_END(); } else #endif /* BEACON_SUPPORT */ /* Trx has handled the entire transmission incl. CSMA */ { tal_state = TAL_TX_DONE; /* Further handling is done by * tx_done_handling() */ } } /* * After transmission has finished, switch receiver on again. * Check if receive buffer is available. */ if (NULL == tal_rx_buffer) { set_trx_state(CMD_PLL_ON); tal_rx_on_required = true; } else { set_trx_state(CMD_RX_AACK_ON); } }
/* * \brief Handles interrupts issued due to end of transmission */ void handle_tx_end_irq(void) { /* Check if TX_END interrupt, is issued due to automatic ACK * transmission. */ #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 { /* Automatic ACK transmission completed -> No further * processing. */ return; } #if ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) if (tal_beacon_transmission) { tal_beacon_transmission = false; if (tal_csma_state == BACKOFF_WAITING_FOR_BEACON) { /* Slotted CSMA has been waiting for a beacon, now it * can continue. */ tal_csma_state = CSMA_HANDLE_BEACON; } } else #endif /* ((MAC_START_REQUEST_CONFIRM == 1) && (defined BEACON_SUPPORT)) */ { /* Read trac status before enabling RX_AACK_ON. */ trx_trac_status = (trx_trac_status_t)trx_bit_read( SR_TRAC_STATUS); #ifdef BEACON_SUPPORT if (tal_csma_state == FRAME_SENDING) { /* Transmission was * issued by slotted CSMA **/ PIN_TX_END(); tal_state = TAL_SLOTTED_CSMA; /* Map status message of transceiver to TAL constants. **/ switch (trx_trac_status) { case TRAC_SUCCESS_DATA_PENDING: PIN_ACK_OK_START(); tal_csma_state = TX_DONE_FRAME_PENDING; break; case TRAC_SUCCESS: PIN_ACK_OK_START(); tal_csma_state = TX_DONE_SUCCESS; break; case TRAC_CHANNEL_ACCESS_FAILURE: PIN_NO_ACK_START(); tal_csma_state = CSMA_ACCESS_FAILURE; break; case TRAC_NO_ACK: PIN_NO_ACK_START(); tal_csma_state = TX_DONE_NO_ACK; break; case TRAC_INVALID: /* Handle this in the same way as * default. */ default: Assert("not handled trac status" == 0); tal_csma_state = CSMA_ACCESS_FAILURE; break; } PIN_ACK_OK_END(); PIN_ACK_WAITING_END(); } else #endif /* BEACON_SUPPORT */ /* Trx has handled the entire transmission incl. CSMA */ { tal_state = TAL_TX_DONE; /* Further handling is done by * tx_done_handling() */ } } /* * After transmission has finished, switch receiver on again. * Check if receive buffer is available. */ if (NULL == tal_rx_buffer) { set_trx_state(CMD_PLL_ON); tal_rx_on_required = true; } else { set_trx_state(CMD_RX_AACK_ON); } }
/** * \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. */ }