/** * @brief Generates a 16-bit random number used as initial seed for srand() * * This function generates a 16-bit random number by means of using the * Random Number Generator from the transceiver. * The Random Number Generator generates 2-bit random values. These 2-bit * random values are concatenated to the required 16-bit random seed. * * The generated random 16-bit number is feed into function srand() * as initial seed. * * The transceiver state is initally set to RX_ON. * After the completion of the random seed generation, the * trancseiver is set to TRX_OFF. * * As a prerequisite the preamble detector must not be disabled. * * Also in case the function is called from a different state than TRX_OFF, * additional trx state handling is required, such as reading the original * value and restoring this state after finishing the sequence. * Since in our case the function is called from TRX_OFF, this is not required * here. */ void tal_generate_rand_seed(void) { uint16_t seed = 0; uint8_t cur_random_val = 0; /* RPC could influence the randomness; therefore disable it here. */ uint8_t previous_RPC_value = pal_trx_reg_read(RG_TRX_RPC); pal_trx_reg_write(RG_TRX_RPC, 0xC1); /* * We need to disable TRX IRQs while generating random values in RX_ON, * we do not want to receive frames at this point of time at all. */ ENTER_TRX_REGION(); /* Ensure that PLL has locked and receive mode is reached. */ tal_trx_status_t trx_state; do { trx_state = set_trx_state(CMD_RX_ON); } while (trx_state != RX_ON); /* Ensure that register bit RX_PDT_DIS is set to 0. */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* * The 16-bit random value is generated from various 2-bit random values. */ for (uint8_t i = 0; i < 8; i++) { /* Now we can safely read the 2-bit random number. */ cur_random_val = pal_trx_bit_read(SR_RND_VALUE); seed = seed << 2; seed |= cur_random_val; PAL_WAIT_1_US(); // wait that the random value gets updated } set_trx_state(CMD_FORCE_TRX_OFF); /* * Now we need to clear potential pending TRX IRQs and * enable the TRX IRQs again. */ pal_trx_reg_read(RG_IRQ_STATUS); pal_trx_irq_flag_clr(); LEAVE_TRX_REGION(); /* Set the seed for the random number generator. */ srand(seed); /* Restore RPC settings. */ pal_trx_reg_write(RG_TRX_RPC, previous_RPC_value); }
/** * @brief Generates a 16-bit random number used as initial seed for srand() * * This function generates a 16-bit random number by means of using the * Random Number Generator from the transceiver. * The Random Number Generator generates 2-bit random values. These 2-bit * random values are concatenated to the required 16-bit random seed. * * The generated random 16-bit number is feed into function srand() * as initial seed. * * The transceiver state is initally set to RX_ON. * After the completion of the random seed generation, the * trancseiver is set to TRX_OFF. * * As a prerequisite the preamble detector must not be disabled. * * Also in case the function is called from a different state than TRX_OFF, * additional trx state handling is required, such as reading the original * value and restoring this state after finishing the sequence. * Since in our case the function is called from TRX_OFF, this is not required * here. */ void tal_generate_rand_seed(void) { uint16_t seed = 0; uint8_t cur_random_val = 0; /* Ensure that PLL has locked and receive mode is reached. */ tal_trx_status_t trx_state; do { trx_state = set_trx_state(CMD_RX_ON); } while (trx_state != RX_ON); /* Ensure that register bit RX_PDT_DIS is set to 0. */ pal_trx_bit_write(SR_RX_PDT_DIS, RX_ENABLE); /* * We need to disable TRX IRQs while generating random values in RX_ON, * we do not want to receive frames at this point of time at all. */ pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_NONE); /* * The 16-bit random value is generated from various 2-bit random values. */ for (uint8_t i = 0; i < 8; i++) { /* Now we can safely read the 2-bit random number. */ cur_random_val = pal_trx_bit_read(SR_RND_VALUE); seed = seed << 2; seed |= cur_random_val; PAL_WAIT_1_US(); // wait that the random value gets updated } set_trx_state(CMD_FORCE_TRX_OFF); /* * Now we need to clear potential pending TRX IRQs and * enable the TRX IRQs again. */ pal_trx_reg_write(RG_IRQ_STATUS, 0xFF); pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); /* Set the seed for the random number generator. */ srand(seed); }
/** * @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. */ tal_awake_end_flag = false; /* Set callback function for the awake interrupt. */ pal_trx_irq_init(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. */ PAL_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 */ pal_trx_reg_read(RG_IRQ_STATUS); /* Re-install default IRQ handler for main interrupt. */ pal_trx_irq_init(trx_irq_handler_cb); /* Re-enable TRX_END interrupt */ pal_trx_reg_write(RG_IRQ_MASK, TRX_IRQ_DEFAULT); #if (ANTENNA_DIVERSITY == 1) /* Enable antenna diversity. */ pal_trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_ENABLE); #endif #ifdef EXT_RF_FRONT_END_CTRL /* Enable RF front end control */ pal_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) { /* Leave trx sleep mode. */ PAL_SLP_TR_LOW(); /* Check if trx has left deep sleep. */ tal_trx_status_t trx_state; do { trx_state = (tal_trx_status_t)pal_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 pal_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. */ pal_trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_DISABLE); #endif #ifdef EXT_RF_FRONT_END_CTRL /* Disable RF front end control */ pal_trx_bit_write(SR_PA_EXT_EN, 0); #endif /* Clear existing interrupts */ pal_trx_reg_read(RG_IRQ_STATUS); /* * Enable Awake_end interrupt. * This is used for save wake-up from sleep later. */ pal_trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); #ifdef ENABLE_DEEP_SLEEP if (trx_cmd == CMD_DEEP_SLEEP) { pal_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. */ pal_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. */ pal_trx_bit_write(SR_IRQ_MASK, TRX_IRQ_4_CCA_ED_DONE); tal_trx_status = TRX_SLEEP; #endif PAL_WAIT_1_US(); PAL_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: pal_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: pal_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: pal_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: pal_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: pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); pal_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: pal_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 pal_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: pal_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 pal_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)pal_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. */ pal_trx_irq_init_awake((FUNC_PTR)trx_awake_handler_cb); /* 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_write(RG_IRQ_STATUS, 0xFF); /* 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 { 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)); } /* * Clear existing interrupts to have clear interrupt flags * during wake-up. */ trx_reg_write(RG_IRQ_STATUS, 0xFF); /* * Enable Awake_end interrupt. * This is used for save wake-up from sleep later. */ trx_reg_write(RG_IRQ_MASK, TRX_IRQ_AWAKE_ONLY); 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) { uint8_t bit_status; PAL_SLP_TR_LOW(); do { bit_status = pal_trx_bit_read(SR_TRX_STATUS); } while (bit_status != TRX_OFF); if ((trx_cmd == CMD_TRX_OFF) || (trx_cmd == CMD_FORCE_TRX_OFF)) { tal_trx_status = TRX_OFF; return TRX_OFF; } } tal_trx_status = (tal_trx_status_t)pal_trx_bit_read(SR_TRX_STATUS); switch (trx_cmd) /* new state */ { case CMD_TRX_SLEEP: pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); { uint16_t rand_value; /* * Init the SEED value of the CSMA backoff algorithm. */ rand_value = (uint16_t)rand(); pal_trx_reg_write(RG_CSMA_SEED_0, (uint8_t)rand_value); pal_trx_bit_write(SR_CSMA_SEED_1, (uint8_t)(rand_value >> 8)); } PAL_WAIT_1_US(); PAL_SLP_TR_HIGH(); pal_timer_delay(TRX_OFF_TO_SLEEP_TIME); tal_trx_status = TRX_SLEEP; return TRX_SLEEP; /* transceiver register cannot be read during TRX_SLEEP */ //break; // do not use break, since it is unreachable case CMD_TRX_OFF: switch (tal_trx_status) { case TRX_OFF: break; default: pal_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; case TX_ARET_ON: pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); PAL_SLP_TR_HIGH(); pal_timer_delay(2); PAL_SLP_TR_LOW(); break; default: pal_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: pal_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: /* software state */ switch (tal_trx_status) { case RX_ON: case BUSY_RX: case RX_AACK_ON: case BUSY_RX_AACK: ENTER_TRX_REGION(); pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); // clear trx irq in case a frame is received meanwhile pal_trx_reg_read(RG_IRQ_STATUS); pal_trx_irq_flag_clr(); LEAVE_TRX_REGION(); PAL_WAIT_1_US(); break; case BUSY_TX: ENTER_TRX_REGION(); pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); LEAVE_TRX_REGION(); PAL_WAIT_1_US(); break; case BUSY_TX_ARET: ENTER_TRX_REGION(); pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); PAL_SLP_TR_LOW(); pal_timer_delay(SLP_TR_TOGGLE_US); PAL_SLP_TR_HIGH(); pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); LEAVE_TRX_REGION(); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); break; case PLL_ON: break; default: ASSERT("state transition not handled" == 0); break; } break; case CMD_RX_ON: switch (tal_trx_status) { case RX_ON: break; case PLL_ON: pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case RX_AACK_ON: case TX_ARET_ON: pal_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)pal_trx_bit_read(SR_TRX_STATUS); if (tal_trx_status != PLL_ON) { return tal_trx_status; } pal_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 PLL_ON: pal_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 pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case TX_ARET_ON: case RX_ON: pal_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)pal_trx_bit_read(SR_TRX_STATUS); if (tal_trx_status != PLL_ON) { return tal_trx_status; } pal_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: pal_trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case RX_ON: case RX_AACK_ON: pal_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)pal_trx_bit_read(SR_TRX_STATUS); if (tal_trx_status != PLL_ON) { return tal_trx_status; } pal_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 pal_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)pal_trx_bit_read(SR_TRX_STATUS); } while (tal_trx_status == STATE_TRANSITION_IN_PROGRESS); return tal_trx_status; } /* set_trx_state() */
static tal_trx_status_t set_trx_state(trx_cmd_t trx_cmd) { tal_trx_status = (tal_trx_status_t) pal_trx_bit_read(SR_TRX_STATUS); /* * State transition is handled among FORCE_TRX_OFF, RX_ON and PLL_ON. * These are the essential states required for a basic transmission * and reception. */ switch (trx_cmd) { /* requested state */ case CMD_FORCE_TRX_OFF: /* Handling FORCE_TRX_OFF state */ switch (tal_trx_status) { case TRX_OFF: /* Do nothing - maintain the previous state */ break; default: pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); PAL_WAIT_1_US(); break; } break; case CMD_PLL_ON: /* Handling PLL_ON state */ switch (tal_trx_status) { case PLL_ON: /* Do nothing - maintain the previous state */ break; case TRX_OFF: switch_pll_on(); break; case RX_ON: pal_trx_reg_write(RG_TRX_STATE, CMD_PLL_ON); PAL_WAIT_1_US(); break; default: Assert("state transition not handled" == 0); break; } break; case CMD_RX_ON: /* Handling the RX_ON state */ switch (tal_trx_status) { case RX_ON: /* Do nothing - maintain the previous state */ break; case PLL_ON: pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; default: Assert("state transition not handled" == 0); break; } break; default: Assert("trx command not handled" == 0); break; } /* Hold till the state transition is complete */ do { tal_trx_status = (tal_trx_status_t) pal_trx_bit_read(SR_TRX_STATUS); } while (tal_trx_status == STATE_TRANSITION_IN_PROGRESS); return tal_trx_status; }
/** * @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) { uint8_t bit_status; uint8_t cnt; tryagain: cnt = 100; PAL_SLP_TR_LOW(); /* poll status register until TRX_OFF is reached */ do { bit_status = pal_trx_bit_read(SR_TRX_STATUS); if (bit_status != TRX_OFF) { if (--cnt == 0) { /* Work around for trx being "half awake". */ PAL_SLP_TR_HIGH(); goto tryagain; } PAL_WAIT_1_US(); } } while (bit_status != TRX_OFF); #if (DEBUG > 0) pal_trx_reg_read(RG_IRQ_STATUS); /* clear Wake irq, dummy read */ #endif #ifdef ANTENNA_DIVERSITY /* Enable antenna diversity. */ pal_trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_SWITCH_ENABLE); #endif if ((trx_cmd == CMD_TRX_OFF) || (trx_cmd == CMD_FORCE_TRX_OFF)) { tal_trx_status = TRX_OFF; return TRX_OFF; } } tal_trx_status = (tal_trx_status_t)pal_trx_bit_read(SR_TRX_STATUS); switch (trx_cmd) /* requested state */ { case CMD_SLEEP: pal_trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF); #ifdef ANTENNA_DIVERSITY /* Disable antenna diversity: sets pulls */ pal_trx_bit_write(SR_ANT_EXT_SW_EN, ANT_EXT_SW_SWITCH_DISABLE); #endif { uint16_t rand_value; /* * Init the SEED value of the CSMA backoff algorithm. */ rand_value = (uint16_t)rand(); pal_trx_reg_write(RG_CSMA_SEED_0, (uint8_t)rand_value); pal_trx_bit_write(SR_CSMA_SEED_1, (uint8_t)(rand_value >> 8)); } PAL_WAIT_1_US(); PAL_SLP_TR_HIGH(); pal_timer_delay(TRX_OFF_TO_SLEEP_TIME); 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: pal_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: pal_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: pal_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: pal_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: pal_trx_reg_write(RG_TRX_STATE, CMD_RX_ON); PAL_WAIT_1_US(); break; case TRX_OFF: switch_pll_on(); pal_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: pal_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 pal_trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); PAL_WAIT_1_US(); break; case RX_ON: pal_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)pal_trx_bit_read(SR_TRX_STATUS); if (tal_trx_status != PLL_ON) { return tal_trx_status; } pal_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: pal_trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); PAL_WAIT_1_US(); break; case RX_ON: case RX_AACK_ON: pal_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)pal_trx_bit_read(SR_TRX_STATUS); if (tal_trx_status != PLL_ON) { return tal_trx_status; } pal_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 pal_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)pal_trx_bit_read(SR_TRX_STATUS); } while (tal_trx_status == STATE_TRANSITION_IN_PROGRESS); return tal_trx_status; } /* set_trx_state() */
/** * @brief Resets transceiver(s) * * @param trx_id Transceiver identifier * * @return MAC_SUCCESS if the transceiver returns TRX_OFF * FAILURE otherwise */ retval_t trx_reset(trx_id_t trx_id) { ENTER_TRX_REGION(); uint32_t start_time; uint32_t current_time; pal_get_current_time(&start_time); if (trx_id == RFBOTH) { TAL_RF_IRQ_CLR_ALL(RF09); TAL_RF_IRQ_CLR_ALL(RF24); tal_state[RF09] = TAL_RESET; tal_state[RF24] = TAL_RESET; /* Apply reset pulse; low active */ #ifdef IQ_RADIO RST_LOW(); PAL_WAIT_1_US(); PAL_WAIT_1_US(); RST_HIGH(); #if (BOARD_TYPE == EVAL215_FPGA) pal_timer_delay(10000); #endif RST_LOW(); PAL_WAIT_1_US(); RST_HIGH(); #else RST_LOW(); PAL_WAIT_1_US(); RST_HIGH(); #endif /* Wait for IRQ line */ while (1) { /* * @ToDo: Use a different macro for IRQ line; the *polarity might be * different after reset */ #ifdef IQ_RADIO if ((PAL_DEV_IRQ_GET(RF215_BB) == HIGH) && (PAL_DEV_IRQ_GET(RF215_RF) == HIGH)) { break; } #else if (TRX_IRQ_GET() == HIGH) { break; } #endif /* Handle timeout */ pal_get_current_time(¤t_time); /* @ToDo: Remove magic number */ if (pal_sub_time_us(current_time, start_time) > 1000) { return FAILURE; } } #ifdef IQ_RADIO trx_state[RF09] = (rf_cmd_state_t)pal_dev_reg_read(RF215_RF, RG_RF09_STATE); trx_state[RF24] = (rf_cmd_state_t)pal_dev_reg_read(RF215_RF, RG_RF24_STATE); rf_cmd_state_t bb_trx_state[NUM_TRX]; bb_trx_state[RF09] = (rf_cmd_state_t)pal_dev_reg_read(RF215_BB, RG_RF09_STATE); bb_trx_state[RF24] = (rf_cmd_state_t)pal_dev_reg_read(RF215_BB, RG_RF24_STATE); if ((bb_trx_state[RF09] != RF_TRXOFF) || (bb_trx_state[RF24] != RF_TRXOFF)) { return FAILURE; } #else trx_state[RF09] = trx_reg_read(RG_RF09_STATE); trx_state[RF24] = trx_reg_read(RG_RF24_STATE); #endif if ((trx_state[RF09] != RF_TRXOFF) || (trx_state[RF24] != RF_TRXOFF)) { return FAILURE; } /* Get all IRQ status information */ #ifdef IQ_RADIO bb_irq_handler_cb(); rf_irq_handler_cb(); #else trx_irq_handler_cb(); #endif TAL_RF_IRQ_CLR(RF09, RF_IRQ_WAKEUP); TAL_RF_IRQ_CLR(RF24, RF_IRQ_WAKEUP); } else { TAL_RF_IRQ_CLR_ALL(trx_id); tal_state[trx_id] = TAL_RESET; /* Trigger reset of device */ uint16_t reg_offset = RF_BASE_ADDR_OFFSET * trx_id; #ifdef IQ_RADIO pal_trx_reg_write(RF215_RF, reg_offset + RG_RF09_CMD, RF_RESET); pal_trx_reg_write(RF215_BB, reg_offset + RG_RF09_CMD, RF_RESET); #else trx_reg_write(reg_offset + RG_RF09_CMD, RF_RESET); #endif /* Wait for IRQ line */ while (1) { #ifdef IQ_RADIO if ((PAL_DEV_IRQ_GET(RF215_BB) == HIGH) && (PAL_DEV_IRQ_GET(RF215_RF) == HIGH)) { break; } #else if (TRX_IRQ_GET() == HIGH) { break; } #endif /* Handle timeout */ pal_get_current_time(¤t_time); /* @ToDo: Remove magic number */ if (pal_sub_time_us(current_time, start_time) > 1000) { return FAILURE; } } trx_state[trx_id] = RF_TRXOFF; /* Get all IRQ status information */ #ifdef IQ_RADIO bb_irq_handler_cb(); rf_irq_handler_cb(); #else trx_irq_handler_cb(); #endif TAL_RF_IRQ_CLR(trx_id, RF_IRQ_WAKEUP); } #ifdef IQ_RADIO pal_trx_irq_flag_clr(RF215_BB); pal_trx_irq_flag_clr(RF215_RF); #else pal_trx_irq_flag_clr(); #endif LEAVE_TRX_REGION(); return MAC_SUCCESS; }