/* * \brief Starts ED Scan * * This function starts an ED Scan for the scan duration specified by the * MAC layer. * * \param scan_duration Specifies the ED scan duration in symbols * * \return MAC_SUCCESS - ED scan duration timer started successfully * TAL_BUSY - TAL is busy servicing the previous request from MAC * TAL_TRX_ASLEEP - Transceiver is currently sleeping * FAILURE otherwise */ retval_t tal_ed_start(uint8_t scan_duration) { /* * Check if the TAL is in idle state. Only in idle state it can * accept and ED request from the MAC. */ if (TAL_IDLE != tal_state) { if (tal_trx_status == TRX_SLEEP) { return TAL_TRX_ASLEEP; } else { Assert("TAL is TAL_BUSY" == 0); return TAL_BUSY; } } /* * Disable the transceiver interrupts to prevent frame reception * while performing ED scan. */ pal_trx_irq_dis(); /* Disable transceiver main interrupt. */ set_trx_state(CMD_FORCE_PLL_ON); trx_reg_read(RG_IRQ_STATUS); /* Clear existing interrupts */ trx_bit_write(SR_RX_PDT_DIS, RX_DISABLE); trx_irq_init((FUNC_PTR)trx_ed_irq_handler_cb); trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); /* Enable * interrupt */ pal_trx_irq_en(); /* Enable main transceiver interrupt. */ /* Make sure that receiver is switched on. */ if (set_trx_state(CMD_RX_ON) != RX_ON) { /* Restore previous configuration */ trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); trx_irq_init((FUNC_PTR)trx_irq_handler_cb); trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); /* enable * TRX_END * interrupt */ pal_trx_irq_en(); /* Enable main transceiver interrupt. */ return FAILURE; } /* write dummy value to start measurement */ trx_reg_write(RG_PHY_ED_LEVEL, 0xFF); /* Perform ED in TAL_ED_RUNNING state. */ tal_state = TAL_ED_RUNNING; max_ed_level = 0; /* reset max value */ sampler_counter = CALCULATE_SYMBOL_TIME_SCAN_DURATION(scan_duration) / ED_SAMPLE_DURATION_SYM; return MAC_SUCCESS; }
/* * \brief Scan done * * This function updates the max_ed_level and invokes the callback function * tal_ed_end_cb(). * * \param parameter unused callback parameter */ void ed_scan_done(void) { trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); trx_irq_init((FUNC_PTR)trx_irq_handler_cb); trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); /* enable TRX_END * interrupt */ pal_trx_irq_en(); /* Enable transceiver main interrupt. */ tal_state = TAL_IDLE; /* ed scan is done */ set_trx_state(CMD_RX_AACK_ON); #ifndef TRX_REG_RAW_VALUE /* * Scale ED result. * Clip values to 0xFF if > -35dBm */ if (max_ed_level > CLIP_VALUE_REG) { max_ed_level = 0xFF; } else { max_ed_level = (uint8_t)(((uint16_t)max_ed_level * 0xFF) / CLIP_VALUE_REG); } #endif tal_ed_end_cb(max_ed_level); }
/** * \brief Start CCA. * * \param parameter Unused callback parameter */ static void cca_start(void *parameter) { tal_state = TAL_CCA; if (set_trx_state(CMD_PLL_ON) == PLL_ON) { tal_trx_status_t trx_state; /* No interest in receiving frames while doing CCA */ trx_bit_write(SR_RX_PDT_DIS, RX_DISABLE); /* disable frame * reception * indication */ do { trx_state = set_trx_state(CMD_RX_ON); } while (trx_state != RX_ON); /* Setup interrupt handling for CCA IRQ */ trx_irq_init((FUNC_PTR)cca_done_irq_handler); trx_reg_write(RG_IRQ_MASK, TRX_IRQ_CCA_ED_READY); /* enable * CCA * interrupt **/ /* Start CCA */ trx_bit_write(SR_CCA_REQUEST, CCA_START); } else { /* Channel is busy, i.e. device is receiving */ tal_state = TAL_CSMA_CONTINUE; } /* Keep compiler happy. */ parameter = parameter; }
/** * \brief Init the radio * \return Returns success/fail * \retval 0 Success */ static int rf212_init(void) { volatile uint8_t regtemp; uint8_t radio_state; /* don't optimize this away, it's important */ //uint8_t temp; PRINTF("RF212: init.\n"); /* init SPI and GPIOs, wake up from sleep/power up. */ //rf212_arch_init(); trx_spi_init(); /* reset will put us into TRX_OFF state */ /* reset the radio core */ port_pin_set_output_level(AT86RFX_RST_PIN, false); delay_cycles_ms(1); port_pin_set_output_level(AT86RFX_RST_PIN, true); port_pin_set_output_level(AT86RFX_SLP_PIN, false); /*wakeup from sleep*/ /* before enabling interrupts, make sure we have cleared IRQ status */ regtemp = trx_reg_read(RF212_REG_IRQ_STATUS); printf("After wake from sleep\n"); radio_state = rf212_status(); printf("After arch read reg: state 0x%04x\n", radio_state); /* Assign regtemp to regtemp to avoid compiler warnings */ regtemp = regtemp; if(radio_state == STATE_P_ON) { trx_reg_write(RF212_REG_TRX_STATE, TRXCMD_TRX_OFF); } trx_irq_init((FUNC_PTR)rf212_interrupt_poll); ENABLE_TRX_IRQ(); system_interrupt_enable_global(); /* Configure the radio using the default values except these. */ trx_reg_write(RF212_REG_TRX_CTRL_1, RF212_REG_TRX_CTRL_1_CONF); trx_reg_write(RF212_REG_PHY_CC_CCA, RF212_REG_PHY_CC_CCA_CONF); trx_reg_write(RF212_REG_PHY_TX_PWR_CONF, RF212_REG_PHY_TX_PWR_CONF); //temp = rf212_arch_read_reg(RF212_REG_TRX_CTRL_2); trx_reg_write(RF212_REG_TRX_CTRL_2, RF212_REG_TRX_CTRL_2_CONF); trx_reg_write(RF212_REG_IRQ_MASK, RF212_REG_IRQ_MASK_CONF); #if HW_CSMA_FRAME_RETRIES trx_bit_write(SR_MAX_FRAME_RETRIES, 3); trx_bit_write(SR_MAX_CSMA_RETRIES, 4); #else trx_bit_write(SR_MAX_FRAME_RETRIES, 0); trx_bit_write(SR_MAX_CSMA_RETRIES, 7); #endif SetPanId(IEEE802154_CONF_PANID); rf_generate_random_seed(); /* start the radio process */ process_start(&rf212_radio_process, NULL); return 0; }
/* * \brief handling of CCA result. */ void cca_done_handling(void) { set_trx_state(CMD_PLL_ON); /* leave RX_ON */ /* Restore IRQ handling */ trx_irq_init((FUNC_PTR)trx_irq_handler_cb); trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* Enable frame reception. **/ /* Check if channel was idle or busy */ if (trx_bit_read(SR_CCA_STATUS) == CCA_STATUS_CHANNEL_IS_IDLE) { tx_frame(); } else { tal_state = TAL_CSMA_CONTINUE; } }
/* * \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 Initializes the TAL * * This function is called to initialize the TAL. The transceiver is * initialized, the TAL PIBs are set to their default values, and the TAL state * machine is set to TAL_IDLE state. * * \return MAC_SUCCESS if the transceiver state is changed to TRX_OFF and the * current device part number and version number are correct; * FAILURE otherwise */ retval_t tal_init(void) { /* Init the PAL and by this means also the transceiver interface */ if (pal_init() != MAC_SUCCESS) { return FAILURE; } if (trx_init() != MAC_SUCCESS) { return FAILURE; } if (tal_timer_init() != MAC_SUCCESS) { return FAILURE; } #ifdef ENABLE_STACK_NVM pal_ps_get(INTERN_EEPROM, EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress); #endif /* * Do the reset stuff. * Set the default PIBs. * Generate random seed. */ if (internal_tal_reset(true) != MAC_SUCCESS) { return FAILURE; } #ifndef DISABLE_IEEE_ADDR_CHECK /* Check if a valid IEEE address is available. */ /* * This while loop is on purpose, since just in the * rare case that such an address is randomly * generated again, we must repeat this. */ uint64_t invalid_ieee_address; memset((uint8_t *)&invalid_ieee_address, 0xFF, sizeof(invalid_ieee_address)); while ((tal_pib.IeeeAddress == 0x0000000000000000) || (tal_pib.IeeeAddress == invalid_ieee_address)) { /* * In case no valid IEEE address is available, a random * IEEE address will be generated to be able to run the * applications for demonstration purposes. * In production code this can be omitted. */ /* * The proper seed for function rand() has already been * generated * in function tal_generate_rand_seed(). */ uint8_t *ptr_pib = (uint8_t *)&tal_pib.IeeeAddress; for (uint8_t i = 0; i < 8; i++) { *ptr_pib++ = (uint8_t)rand(); /* * Note: * Even if casting the 16 bit rand value back to 8 bit, * and running the loop 8 timers (instead of only 4 * times) * may look cumbersome, it turns out that the code gets * smaller using 8-bit here. * And timing is not an issue at this place... */ } } #endif /* #ifndef DISABLE_IEEE_ADDR_CHECK */ #ifdef ENABLE_STACK_NVM pal_ps_set(EE_IEEE_ADDR, 8, &tal_pib.IeeeAddress); #endif /* * Configure interrupt handling. * Install a handler for the main transceiver interrupt. */ trx_irq_init((FUNC_PTR)trx_irq_handler_cb); pal_trx_irq_en(); /* Enable main transceiver interrupt. */ #if ((defined BEACON_SUPPORT) || (defined ENABLE_TSTAMP)) && \ (DISABLE_TSTAMP_IRQ == 0) /* Configure time stamp interrupt. * The timestamping is only required for * - beaconing networks or if timestamping is explicitly enabled, * - and if the time stamp interrupt is not explicitly disabled. */ pal_trx_irq_init_tstamp((FUNC_PTR)trx_irq_timestamp_handler_cb); pal_trx_irq_en_tstamp(); /* Enable timestamp interrupt. */ #endif /* Initialize the buffer management module and get a buffer to store * reveived frames. */ bmm_buffer_init(); tal_rx_buffer = bmm_buffer_alloc(LARGE_BUFFER_SIZE); /* Init incoming frame queue */ #ifdef ENABLE_QUEUE_CAPACITY qmm_queue_init(&tal_incoming_frame_queue, TAL_INCOMING_FRAME_QUEUE_CAPACITY); #else qmm_queue_init(&tal_incoming_frame_queue); #endif /* ENABLE_QUEUE_CAPACITY */ #ifdef ENABLE_TFA tfa_init(); #endif return MAC_SUCCESS; } /* tal_init() */
/* * \brief Sets transceiver state * * \param trx_cmd needs to be one of the trx commands * * \return current trx state */ tal_trx_status_t set_trx_state(trx_cmd_t trx_cmd) { if (tal_trx_status == TRX_SLEEP) { /* * Since the wake-up procedure relies on the Awake IRQ and * the global interrupts may be disabled at this point of time, * we need to make sure that the global interrupts are enabled * during wake-up procedure. * Once the TRX is awake, the original state of the global * interrupts * will be restored. */ /* Reset wake-up interrupt flag. */ if (CMD_SLEEP == trx_cmd) { return TRX_SLEEP; } tal_awake_end_flag = false; /* Set callback function for the awake interrupt. */ trx_irq_init((FUNC_PTR)trx_irq_awake_handler_cb); /* The pending transceiver interrupts on the microcontroller are * cleared. */ pal_trx_irq_flag_clr(); pal_trx_irq_en(); /* Enable transceiver main interrupt. */ /* Save current state of global interrupts. */ ENTER_CRITICAL_REGION(); /* Force enabling of global interrupts. */ ENABLE_GLOBAL_IRQ(); /* Leave trx sleep mode. */ TRX_SLP_TR_LOW(); /* Poll wake-up interrupt flag until set within ISR. */ while (!tal_awake_end_flag) { } /* Restore original state of global interrupts. */ LEAVE_CRITICAL_REGION(); /* Clear existing interrupts */ trx_reg_read(RG_IRQ_STATUS); /* Re-install default IRQ handler for main interrupt. */ trx_irq_init((FUNC_PTR)trx_irq_handler_cb); /* Re-enable TRX_END interrupt */ trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); #if (ANTENNA_DIVERSITY == 1) /* Enable antenna diversity. */ trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE); #endif if ((trx_cmd == CMD_TRX_OFF) || (trx_cmd == CMD_FORCE_TRX_OFF)) { tal_trx_status = TRX_OFF; return TRX_OFF; } } switch (trx_cmd) { /* requested state */ case CMD_SLEEP: trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); #if (ANTENNA_DIVERSITY == 1) /* Disable antenna diversity: sets pulls */ trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_DISABLE); #endif #ifndef SW_CONTROLLED_CSMA { uint16_t rand_value; /* * Init the SEED value of the CSMA backoff algorithm. */ rand_value = (uint16_t)rand(); trx_reg_write(RG_CSMA_SEED_0, (uint8_t)rand_value); trx_bit_write(SR_CSMA_SEED_1, (uint8_t)(rand_value >> 8)); } #endif /* Clear existing interrupts */ trx_reg_read(RG_IRQ_STATUS); /* * Enable Awake_end interrupt. * This is used for save wake-up from sleep later. */ trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); PAL_WAIT_1_US(); TRX_SLP_TR_HIGH(); pal_timer_delay(TRX_OFF_TO_SLEEP_TIME_CLKM_CYCLES); tal_trx_status = TRX_SLEEP; return TRX_SLEEP; /* transceiver register cannot be read during * TRX_SLEEP */ case CMD_TRX_OFF: switch (tal_trx_status) { case TRX_OFF: break; default: trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); PAL_WAIT_1_US(); break; } break; case CMD_FORCE_TRX_OFF: switch (tal_trx_status) { case TRX_OFF: break; default: trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); PAL_WAIT_1_US(); break; } break; case CMD_PLL_ON: switch (tal_trx_status) { case PLL_ON: break; case TRX_OFF: switch_pll_on(); break; case RX_ON: case RX_AACK_ON: case TX_ARET_ON: trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; case CMD_FORCE_PLL_ON: switch (tal_trx_status) { case TRX_OFF: switch_pll_on(); break; case PLL_ON: break; default: trx_reg_write(RG_TRX_STATE, CMD_FORCE_PLL_ON); break; } break; case CMD_RX_ON: switch (tal_trx_status) { case RX_ON: break; case PLL_ON: case RX_AACK_ON: case TX_ARET_ON: trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; case CMD_RX_AACK_ON: switch (tal_trx_status) { case RX_AACK_ON: break; case TX_ARET_ON: case PLL_ON: trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); /* state change from TRX_OFF to * RX_AACK_ON can be done directly, too **/ trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case RX_ON: trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); PAL_WAIT_1_US(); /* check if state change could be applied */ tal_trx_status = (tal_trx_status_t)trx_bit_read( SR_TRX_STATUS); if (tal_trx_status != PLL_ON) { return tal_trx_status; } trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; case CMD_TX_ARET_ON: switch (tal_trx_status) { case TX_ARET_ON: break; case PLL_ON: trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case RX_ON: case RX_AACK_ON: trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); PAL_WAIT_1_US(); /* check if state change could be applied */ tal_trx_status = (tal_trx_status_t)trx_bit_read( SR_TRX_STATUS); if (tal_trx_status != PLL_ON) { return tal_trx_status; } trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); /* state change from TRX_OFF to * TX_ARET_ON can be done directly, too **/ trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; default: /* CMD_NOP, CMD_TX_START */ Assert("trx command not handled" == 0); break; } do { tal_trx_status = (tal_trx_status_t)trx_bit_read( SR_TRX_STATUS); } while (tal_trx_status == STATE_TRANSITION_IN_PROGRESS); return tal_trx_status; } /* set_trx_state() */
/* * \brief Sets transceiver state * * \param trx_cmd needs to be one of the trx commands * * \return current trx state */ tal_trx_status_t set_trx_state(trx_cmd_t trx_cmd) { if (tal_trx_status == TRX_SLEEP) { /* * Since the wake-up procedure relies on the Awake IRQ and * the global interrupts may be disabled at this point of time, * we need to make sure that the global interrupts are enabled * during wake-up procedure. * Once the TRX is awake, the original state of the global * interrupts * will be restored. */ /* Reset wake-up interrupt flag. */ if (CMD_SLEEP == trx_cmd) { return TRX_SLEEP; } tal_awake_end_flag = false; /* Set callback function for the awake interrupt. */ trx_irq_init((FUNC_PTR)trx_irq_awake_handler_cb); /* The pending transceiver interrupts on the microcontroller are * cleared. */ pal_trx_irq_flag_clr(); pal_trx_irq_en(); /* Enable transceiver main interrupt. */ /* Save current state of global interrupts. */ ENTER_CRITICAL_REGION(); /* Force enabling of global interrupts. */ ENABLE_GLOBAL_IRQ(); /* Leave trx sleep mode. */ TRX_SLP_TR_LOW(); /* Poll wake-up interrupt flag until set within ISR. */ while (!tal_awake_end_flag) { } /* Restore original state of global interrupts. */ LEAVE_CRITICAL_REGION(); /* Clear existing interrupts */ trx_reg_read(RG_IRQ_STATUS); /* Re-install default IRQ handler for main interrupt. */ trx_irq_init((FUNC_PTR)trx_irq_handler_cb); /* Re-enable TRX_END interrupt */ trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); #if (ANTENNA_DIVERSITY == 1) /* Enable antenna diversity. */ trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE); #endif #ifdef EXT_RF_FRONT_END_CTRL /* Enable RF front end control */ trx_bit_write(SR_PA_EXT_EN, 1); #endif tal_trx_status = TRX_OFF; if ((trx_cmd == CMD_TRX_OFF) || (trx_cmd == CMD_FORCE_TRX_OFF)) { return TRX_OFF; } } #ifdef ENABLE_DEEP_SLEEP else if (tal_trx_status == TRX_DEEP_SLEEP) { if (CMD_DEEP_SLEEP == trx_cmd) { return TRX_DEEP_SLEEP; } /* Leave trx sleep mode. */ TRX_SLP_TR_LOW(); /* Check if trx has left deep sleep. */ tal_trx_status_t trx_state; do { trx_state = trx_reg_read( RG_TRX_STATUS); } while (trx_state != TRX_OFF); tal_trx_status = TRX_OFF; /* Using deep sleep, the transceiver's registers need to be * restored. */ trx_config(); /* * Write all PIB values to the transceiver * that are needed by the transceiver itself. */ write_all_tal_pib_to_trx(); /* implementation can be found in *'tal_pib.c' */ if ((trx_cmd == CMD_TRX_OFF) || (trx_cmd == CMD_FORCE_TRX_OFF)) { return TRX_OFF; } } #endif switch (trx_cmd) { /* requested state */ case CMD_SLEEP: #ifdef ENABLE_DEEP_SLEEP /* Fall through. */ case CMD_DEEP_SLEEP: #endif trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); #if (ANTENNA_DIVERSITY == 1) /* * Disable antenna diversity: to reduce the power consumption * or * avoid leakage current of an external RF switch during SLEEP. */ trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_DISABLE); #endif #ifdef EXT_RF_FRONT_END_CTRL /* Disable RF front end control */ trx_bit_write(SR_PA_EXT_EN, 0); #endif /* Clear existing interrupts */ trx_reg_read(RG_IRQ_STATUS); /* * Enable Awake_end interrupt. * This is used for save wake-up from sleep later. */ trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); #ifdef ENABLE_DEEP_SLEEP if (trx_cmd == CMD_DEEP_SLEEP) { trx_reg_write(RG_TRX_STATE, CMD_PREP_DEEP_SLEEP); tal_trx_status = TRX_DEEP_SLEEP; } else { /* * Enable Awake_end interrupt. * This is used for save wake-up from sleep later. */ trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); tal_trx_status = TRX_SLEEP; } #else /* * Enable Awake_end interrupt. * This is used for save wake-up from sleep later. */ trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); tal_trx_status = TRX_SLEEP; #endif PAL_WAIT_1_US(); TRX_SLP_TR_HIGH(); pal_timer_delay(TRX_OFF_TO_SLEEP_TIME_CLKM_CYCLES); /* Transceiver register cannot be read during TRX_SLEEP or * DEEP_SLEEP. */ return tal_trx_status; case CMD_TRX_OFF: switch (tal_trx_status) { case TRX_OFF: break; default: trx_reg_write(RG_TRX_STATE, CMD_TRX_OFF); PAL_WAIT_1_US(); break; } break; case CMD_FORCE_TRX_OFF: switch (tal_trx_status) { case TRX_OFF: break; default: trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); PAL_WAIT_1_US(); break; } break; case CMD_PLL_ON: switch (tal_trx_status) { case PLL_ON: break; case TRX_OFF: switch_pll_on(); break; case RX_ON: case RX_AACK_ON: case TX_ARET_ON: trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; case CMD_FORCE_PLL_ON: switch (tal_trx_status) { case TRX_OFF: switch_pll_on(); break; case PLL_ON: break; default: trx_reg_write(RG_TRX_STATE, CMD_FORCE_PLL_ON); break; } break; case CMD_RX_ON: switch (tal_trx_status) { case RX_ON: break; case PLL_ON: case RX_AACK_ON: case TX_ARET_ON: trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; case CMD_RX_AACK_ON: switch (tal_trx_status) { case RX_AACK_ON: break; case TX_ARET_ON: case PLL_ON: case RX_ON: trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); /* state change from TRX_OFF to * RX_AACK_ON can be done directly, too **/ trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; case CMD_TX_ARET_ON: switch (tal_trx_status) { case TX_ARET_ON: break; case PLL_ON: case RX_ON: case RX_AACK_ON: trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); /* state change from TRX_OFF to * TX_ARET_ON can be done directly, too **/ trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case BUSY_RX: case BUSY_TX: case BUSY_RX_AACK: case BUSY_TX_ARET: /* do nothing if trx is busy */ break; default: Assert("state transition not handled" == 0); break; } break; default: /* CMD_NOP, CMD_TX_START */ Assert("trx command not handled" == 0); break; } do { tal_trx_status = /* (tal_trx_status_t) */ trx_bit_read( SR_TRX_STATUS); } while (tal_trx_status == STATE_TRANSITION_IN_PROGRESS); return tal_trx_status; } /* set_trx_state() */
/** * @brief Resets TAL state machine and sets the default PIB values if requested * * @param trx_id Transceiver identifier * @param set_default_pib Defines whether PIB values need to be set * to its default values * * @return * - @ref MAC_SUCCESS if the transceiver state is changed to TRX_OFF * - @ref FAILURE otherwise * @ingroup apiTalApi */ retval_t tal_reset(trx_id_t trx_id, bool set_default_pib) { rf_cmd_state_t previous_trx_state[NUM_TRX]; previous_trx_state[RF09] = trx_state[RF09]; previous_trx_state[RF24] = trx_state[RF24]; /* Reset the actual device or part of the device */ if (trx_reset(trx_id) != MAC_SUCCESS) { return FAILURE; } /* Init Trx if necessary, e.g. trx was in deep sleep */ if (((previous_trx_state[RF09] == RF_SLEEP) && (previous_trx_state[RF24] == RF_SLEEP)) || (trx_id == RFBOTH)) { trx_init(); /* Initialize generic trx functionality */ } if (trx_id == RFBOTH) { for (uint8_t i = 0; i < NUM_TRX; i++) { /* Clean TAL and removed any pending tasks */ cleanup_tal((trx_id_t)i); /* Configure the transceiver register values. */ trx_config((trx_id_t)i); if (set_default_pib) { /* Set the default PIB values */ init_tal_pib((trx_id_t)i); /* see 'tal_pib.c' */ calculate_pib_values(trx_id); } else { /* nothing to do - the current TAL PIB attribute *values are used */ } write_all_tal_pib_to_trx((trx_id_t)i); /* see *'tal_pib.c' */ config_phy((trx_id_t)i); /* Reset TAL variables. */ tal_state[(trx_id_t)i] = TAL_IDLE; tx_state[(trx_id_t)i] = TX_IDLE; #ifdef ENABLE_FTN_PLL_CALIBRATION /* Stop FTN timer */ stop_ftn_timer((trx_id_t)i); #endif /* ENABLE_FTN_PLL_CALIBRATION */ } } else { /* Maintain other trx */ trx_id_t other_trx_id; if (trx_id == RF09) { other_trx_id = RF24; } else { other_trx_id = RF09; } if (tal_state[other_trx_id] == TAL_SLEEP) { /* Switch other trx back to sleep again */ uint16_t reg_offset = RF_BASE_ADDR_OFFSET * other_trx_id; #ifdef IQ_RADIO pal_dev_reg_write(RF215_BB, reg_offset + RG_RF09_CMD, RF_SLEEP); pal_dev_reg_write(RF215_RF, reg_offset + RG_RF09_CMD, RF_SLEEP); #else trx_reg_write(reg_offset + RG_RF09_CMD, RF_SLEEP); #endif TAL_RF_IRQ_CLR_ALL(trx_id); } /* Clean TAL and removed any pending tasks */ cleanup_tal(trx_id); /* Configure the transceiver register values. */ trx_config(trx_id); if (set_default_pib) { /* Set the default PIB values */ init_tal_pib(trx_id); /* see 'tal_pib.c' */ calculate_pib_values(trx_id); } else { /* nothing to do - the current TAL PIB attribute values *are used */ } write_all_tal_pib_to_trx(trx_id); /* see 'tal_pib.c' */ config_phy(trx_id); /* Reset TAL variables. */ tal_state[trx_id] = TAL_IDLE; tx_state[trx_id] = TX_IDLE; #ifdef ENABLE_FTN_PLL_CALIBRATION /* Stop FTN timer */ stop_ftn_timer(trx_id); #endif /* ENABLE_FTN_PLL_CALIBRATION */ } /* * Configure interrupt handling. * Install a handler for the transceiver interrupt. */ #ifdef IQ_RADIO trx_irq_init(RF215_BB, bb_irq_handler_cb); trx_irq_init(RF215_RF, rf_irq_handler_cb); pal_trx_irq_en(RF215_BB); /* Enable transceiver main interrupt. */ pal_trx_irq_en(RF215_RF); /* Enable transceiver main interrupt. */ #else trx_irq_init((FUNC_PTR)trx_irq_handler_cb); pal_trx_irq_en(); /* Enable transceiver main interrupt. */ #endif return MAC_SUCCESS; }
/** * @brief Initializes the TAL * * This function is called to initialize the TAL. The transceiver is * initialized, the TAL PIBs are set to their default values, and the TAL state * machine is set to TAL_IDLE state. * * @return MAC_SUCCESS if the transceiver state is changed to TRX_OFF and the * current device part number and version number are correct; * FAILURE otherwise */ retval_t tal_init(void) { /* Init the PAL and by this means also the transceiver interface */ if (pal_init() != MAC_SUCCESS) { return FAILURE; } /* Reset trx */ if (trx_reset(RFBOTH) != MAC_SUCCESS) { return FAILURE; } /* Check if RF215 is connected */ if ((trx_reg_read( RG_RF_PN) != 0x34) || (trx_reg_read( RG_RF_VN) != 0x01)) { return FAILURE; } /* Initialize trx */ trx_init(); if (tal_timer_init() != MAC_SUCCESS) { return FAILURE; } /* Initialize the buffer management */ bmm_buffer_init(); /* Configure both trx and set default PIB values */ for (uint8_t trx_id = 0; trx_id < NUM_TRX; trx_id++) { /* Configure transceiver */ trx_config((trx_id_t)trx_id); #ifdef RF215V1 /* Calibrate LO */ calibrate_LO((trx_id_t)trx_id); #endif /* Set the default PIB values */ init_tal_pib((trx_id_t)trx_id); /* see 'tal_pib.c' */ calculate_pib_values((trx_id_t)trx_id); /* * Write all PIB values to the transceiver * that are needed by the transceiver itself. */ write_all_tal_pib_to_trx((trx_id_t)trx_id); /* see 'tal_pib.c' **/ config_phy((trx_id_t)trx_id); tal_rx_buffer[trx_id] = bmm_buffer_alloc(LARGE_BUFFER_SIZE); if (tal_rx_buffer[trx_id] == NULL) { return FAILURE; } /* Init incoming frame queue */ qmm_queue_init(&tal_incoming_frame_queue[trx_id]); tal_state[trx_id] = TAL_IDLE; tx_state[trx_id] = TX_IDLE; } /* Init seed of rand() */ tal_generate_rand_seed(); #ifndef DISABLE_IEEE_ADDR_CHECK for (uint8_t trx_id = 0; trx_id < 2; trx_id++) { /* Check if a valid IEEE address is available. */ /* * This while loop is on purpose, since just in the * rare case that such an address is randomly * generated again, we must repeat this. */ while ((tal_pib[trx_id].IeeeAddress == 0x0000000000000000) || (tal_pib[trx_id].IeeeAddress == ((uint64_t)-1))) { /* * In case no valid IEEE address is available, a random * IEEE address will be generated to be able to run the * applications for demonstration purposes. * In production code this can be omitted. */ /* * The proper seed for function rand() has already been *generated * in function tal_generate_rand_seed(). */ uint8_t *ptr_pib = (uint8_t *)&tal_pib[trx_id].IeeeAddress; for (uint8_t i = 0; i < 8; i++) { *ptr_pib++ = (uint8_t)rand(); /* * Note: * Even if casting the 16 bit rand value back to *8 bit, * and running the loop 8 timers (instead of *only 4 times) * may look cumbersome, it turns out that the *code gets * smaller using 8-bit here. * And timing is not an issue at this place... */ } } } #endif #ifdef IQ_RADIO /* Init BB IRQ handler */ pal_trx_irq_flag_clr(RF215_BB); trx_irq_init(RF215_BB, bb_irq_handler_cb); pal_trx_irq_en(RF215_BB); /* Init RF IRQ handler */ pal_trx_irq_flag_clr(RF215_RF); trx_irq_init(RF215_RF, rf_irq_handler_cb); pal_trx_irq_en(RF215_RF); #else /* * Configure interrupt handling. * Install a handler for the radio and the baseband interrupt. */ pal_trx_irq_flag_clr(); trx_irq_init((FUNC_PTR)trx_irq_handler_cb); pal_trx_irq_en(); /* Enable transceiver main interrupt. */ #endif #if ((defined SUPPORT_FSK) && (defined SUPPORT_MODE_SWITCH)) init_mode_switch(); #endif return MAC_SUCCESS; } /* tal_init() */