/** * @brief Handles incoming frame from transceiver * * @param trx_id Transceiver identifier */ static void handle_incoming_frame(trx_id_t trx_id) { uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; if (is_frame_an_ack(trx_id)) { if (tx_state[trx_id] == TX_WAITING_FOR_ACK) { if (is_ack_valid(trx_id)) { /* Stop ACK timeout timer */ stop_tal_timer(trx_id); /* Re-store frame filter to pass "normal" frames **/ /* Configure frame filter to receive all allowed *frame types */ #ifdef SUPPORT_FRAME_FILTER_CONFIGURATION trx_reg_write(reg_offset + RG_BBC0_AFFTM, tal_pib[trx_id].frame_types); #else trx_reg_write(reg_offset + RG_BBC0_AFFTM, DEFAULT_FRAME_TYPES); #endif tx_done_handling(trx_id, MAC_SUCCESS); } else { /* Continue waiting for incoming ACK */ switch_to_rx(trx_id); } } else { /* No interest in ACKs */ switch_to_rx(trx_id); } return; /* no further processing of ACK frames */ } /* Check if ACK transmission is done by transceiver */ bool ack_transmitting = trx_bit_read(reg_offset + SR_BBC0_AMCS_AACKFT); if (ack_transmitting) { } else { complete_rx_transaction(trx_id); #ifdef RX_WHILE_BACKOFF if (tx_state[trx_id] == TX_DEFER) { csma_start(trx_id); } #endif } }
void tx_msg_char(void) { UDR0 = tx_buffer.buffer[tx_idx]; tx_idx++; if (tx_idx == tx_len) { rx_state = RX_IDLE; tx_state = TX_IDLE; transport_state = RX; switch_to_rx(); } }
/** * @brief Switches receiver on or off * * This function switches the receiver on (PHY_RX_ON) or off (PHY_TRX_OFF). * * @param trx_id Transceiver identifier * @param state New state of receiver * * @return * - @ref TAL_BUSY if the TAL state machine cannot switch receiver on or *off, * - @ref PHY_TRX_OFF if receiver has been switched off, or * - @ref PHY_RX_ON otherwise. * * @ingroup apiTalApi */ uint8_t tal_rx_enable(trx_id_t trx_id, uint8_t state) { uint8_t ret_val; if (tal_state[trx_id] == TAL_SLEEP) { return TAL_TRX_ASLEEP; } /* * Trx can only be enabled if TAL is not busy; * i.e. if TAL is IDLE. */ if (tal_state[trx_id] != TAL_IDLE) { return TAL_BUSY; } if (state == PHY_TRX_OFF) { /* * If the rx needs to be switched off, * we are not interested in a frame that is currently being *received. */ uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; trx_reg_write(reg_offset + RG_RF09_CMD, RF_TRXOFF); #ifdef IQ_RADIO pal_dev_reg_write(RF215_RF, GET_REG_ADDR(RG_RF09_CMD), RF_TRXOFF); #endif #if (defined RF215V1) && ((defined SUPPORT_FSK) || (defined SUPPORT_OQPSK)) stop_rpc(trx_id); #endif trx_state[trx_id] = RF_TRXOFF; tal_buf_shortage[trx_id] = false; ret_val = PHY_TRX_OFF; #ifdef ENABLE_FTN_PLL_CALIBRATION stop_ftn_timer(trx_id); #endif /* ENABLE_FTN_PLL_CALIBRATION */ trx_default_state[trx_id] = RF_TRXOFF; } else { switch_to_txprep(trx_id); switch_to_rx(trx_id); ret_val = PHY_RX_ON; #ifdef ENABLE_FTN_PLL_CALIBRATION start_ftn_timer(trx_id); #endif /* ENABLE_FTN_PLL_CALIBRATION */ trx_default_state[trx_id] = RF_RX; } return ret_val; }
/** * @brief Completes Rx transaction * * @param trx_id Transceiver identifier */ void complete_rx_transaction(trx_id_t trx_id) { /* Get energy of received frame */ uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; uint8_t ed = trx_reg_read(reg_offset + RG_RF09_EDV); uint16_t ed_pos = rx_frm_info[trx_id]->len_no_crc + 1 + tal_pib[trx_id].FCSLen; rx_frm_info[trx_id]->mpdu[ed_pos] = ed; /* PSDU, LQI, ED */ /* Append received frame to incoming_frame_queue and get new rx buffer. **/ qmm_queue_append(&tal_incoming_frame_queue[trx_id], tal_rx_buffer[trx_id]); /* The previous buffer is eaten up and a new buffer is not assigned yet. **/ tal_rx_buffer[trx_id] = bmm_buffer_alloc(LARGE_BUFFER_SIZE); /* Switch to rx again to handle buffer shortage */ switch_to_rx(trx_id); }
/** * @brief Stops CW transmission * * @param trx_id Identifier of the transceiver */ void tfa_continuous_tx_stop(trx_id_t trx_id) { uint16_t reg_offset = BB_BASE_ADDR_OFFSET * trx_id; /* Stop continuous transmission */ trx_bit_write(reg_offset + SR_BBC0_PC_CTX, 0); #ifdef IQ_RADIO /* Allow command via SPI */ pal_dev_bit_write(RF215_RF, SR_RF_IQIFC0_EEC, 0); #endif switch_to_txprep(trx_id); /* Disable carrier transmission - even if it has not been used. */ uint8_t dac_config[2] = {0x00, 0x00}; uint16_t rft_reg_offset = RFT_TST_ADDR_OFFSET * trx_id; #ifdef IQ_RADIO pal_dev_write(RF215_RF, rft_reg_offset + RG_RF09_TXDACI, dac_config, 2); /* Enable embedded TX control again */ pal_dev_bit_write(RF215_RF, SR_RF_IQIFC0_EEC, 1); #else trx_write(rft_reg_offset + RG_RF09_TXDACI, dac_config, 2); /* Disable baseband bypass */ trx_bit_write( SR_RF_IQIFC1_CHPM, 0); #endif /* Restore previous settings */ if (tal_state[trx_id] == TAL_TFA_CW_RX) { tal_state[trx_id] = TAL_IDLE; switch_to_rx(trx_id); } else { tal_state[trx_id] = TAL_IDLE; /* Switch to TRXOFF */ #ifdef IQ_RADIO pal_dev_reg_write(RF215_RF, reg_offset + RG_RF09_CMD, RF_TRXOFF); pal_dev_reg_write(RF215_BB, reg_offset + RG_RF09_CMD, RF_TRXOFF); #else trx_reg_write(reg_offset + RG_RF09_CMD, RF_TRXOFF); #endif trx_state[trx_id] = RF_TRXOFF; } }
/** * @brief Perform a CCA * * This blocking function performs a CCA request. * * @return phy_enum_t PHY_IDLE or PHY_BUSY */ phy_enum_t tfa_cca_perform(trx_id_t trx_id) { phy_enum_t ret; if (tal_state[trx_id] != TAL_IDLE) { ret = PHY_BUSY; } else { rf_cmd_state_t previous_state = trx_state[trx_id]; if (trx_state[trx_id] == RF_TRXOFF) { switch_to_txprep(trx_id); } if (trx_state[trx_id] != RF_RX) { switch_to_rx(trx_id); pal_timer_delay(tal_pib[trx_id].agc_settle_dur); /* * allow * filters * to * settle */ } /* Disable BB */ uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; trx_bit_write(reg_offset + SR_BBC0_PC_BBEN, 0); #ifndef BASIC_MODE /* Enable EDC interrupt */ trx_bit_write(reg_offset + SR_RF09_IRQM_EDC, 1); #endif /* Start single ED measurement; use reg_write - it's the only *subregister */ tal_state[trx_id] = TAL_TFA_CCA; #ifdef IQ_RADIO /* Enable EDC interrupt */ pal_dev_bit_write(RF215_RF, reg_offset + SR_RF09_IRQM_EDC, 1); pal_dev_reg_write(RF215_RF, reg_offset + RG_RF09_EDC, RF_EDSINGLE); #else trx_reg_write(reg_offset + RG_RF09_EDC, RF_EDSINGLE); #endif /* Wait until measurement is completed */ while (TAL_RF_IS_IRQ_SET(trx_id, RF_IRQ_EDC) == false) { } TAL_RF_IRQ_CLR(trx_id, RF_IRQ_EDC); #ifndef BASIC_MODE /* Disable EDC interrupt again */ trx_bit_write(reg_offset + SR_RF09_IRQM_EDC, 0); #endif #ifdef IQ_RADIO pal_dev_bit_write(RF215_RF, reg_offset + SR_RF09_IRQM_EDC, 0); #endif /* Since it is a blocking function, restore TAL state */ tal_state[trx_id] = TAL_IDLE; switch_to_txprep(trx_id); /* Leave Rx mode */ /* Switch BB on again */ trx_bit_write(reg_offset + SR_BBC0_PC_BBEN, 1); /* Capture ED value for current frame / ED scan */ #ifdef IQ_RADIO tal_current_ed_val[trx_id] = pal_dev_reg_read(RF215_RF, reg_offset + RG_RF09_EDV); #else tal_current_ed_val[trx_id] = trx_reg_read( reg_offset + RG_RF09_EDV); #endif if (tal_current_ed_val[trx_id] < tal_pib[trx_id].CCAThreshold) { /* Idle */ ret = PHY_IDLE; } else { /* Busy */ ret = PHY_BUSY; } /* Restore previous trx state */ if (previous_state == RF_RX) { switch_to_rx(trx_id); } else { /* Switch to TRXOFF */ trx_reg_write(reg_offset + RG_RF09_CMD, RF_TRXOFF); #ifdef IQ_RADIO pal_dev_reg_write(RF215_RF, reg_offset + RG_RF09_CMD, RF_TRXOFF); #endif trx_state[trx_id] = RF_TRXOFF; } } return ret; }
/* * @brief The main thread run, receiving and processing messages in an infinite * loop */ static void *run(void *arg) { (void) arg; msg_init_queue(msg_buffer, TRANSCEIVER_MSG_BUFFER_SIZE); while (1) { DEBUG("transceiver: Waiting for next message\n"); msg_t m; msg_receive(&m); /* only makes sense for messages for upper layers */ transceiver_command_t *cmd = (transceiver_command_t *) m.content.ptr; DEBUG("transceiver: Transceiver: Message received, type: %02X\n", m.type); switch (m.type) { case RCV_PKT_CC1020: case RCV_PKT_CC1100: case RCV_PKT_CC2420: case RCV_PKT_MC1322X: case RCV_PKT_NATIVE: case RCV_PKT_AT86RF231: receive_packet(m.type, m.content.value); break; case SND_PKT: response = send_packet(cmd->transceivers, cmd->data); m.content.value = response; msg_reply(&m, &m); break; case GET_CHANNEL: *((int32_t *) cmd->data) = get_channel(cmd->transceivers); msg_reply(&m, &m); break; case SET_CHANNEL: *((int32_t *) cmd->data) = set_channel(cmd->transceivers, cmd->data); msg_reply(&m, &m); break; case GET_ADDRESS: *((radio_address_t *) cmd->data) = get_address(cmd->transceivers); msg_reply(&m, &m); break; case SET_ADDRESS: *((radio_address_t *) cmd->data) = set_address(cmd->transceivers, cmd->data); msg_reply(&m, &m); break; case GET_LONG_ADDR: *((transceiver_eui64_t *) cmd->data) = get_long_addr(cmd->transceivers); msg_reply(&m, &m); break; case SET_LONG_ADDR: *((transceiver_eui64_t *) cmd->data) = set_long_addr(cmd->transceivers, cmd->data); msg_reply(&m, &m); break; case SET_MONITOR: set_monitor(cmd->transceivers, cmd->data); break; case POWERDOWN: powerdown(cmd->transceivers); break; case SWITCH_RX: switch_to_rx(cmd->transceivers); break; case GET_PAN: *((int32_t *) cmd->data) = get_pan(cmd->transceivers); msg_reply(&m, &m); break; case SET_PAN: *((int32_t *) cmd->data) = set_pan(cmd->transceivers, cmd->data); msg_reply(&m, &m); break; #ifdef DBG_IGNORE case DBG_IGN: *((int16_t *) cmd->data) = ignore_add(cmd->transceivers, cmd->data); msg_reply(&m, &m); break; #endif default: DEBUG("transceiver: Unknown message received\n"); break; } } return NULL; }
/** * @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]); } }