/** * @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((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. */ 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((FUNC_PTR)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 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 /* 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 Receives data from USB0 * * This function receives data from USB0 * * @param data pointer to the buffer where the received data will be stored * @param max_length maximum length of data to be received * * @return actual number of bytes received */ uint8_t sio_usb_0_rx(uint8_t *data, uint8_t max_length) { uint8_t data_received = 0; uint8_t size = 0; if (usb_0_buffer.rx_count == 0) { /* usb receive buffer is empty. */ return 0; } /* The receive interrupt is disabled. */ ENTER_CRITICAL_REGION(); if (USB_RX_BUF_MAX_SIZE <= usb_0_buffer.rx_count) { /* * Bytes between head and tail are overwritten by new data. * The oldest data in buffer is the one to which the tail is * pointing. So reading operation should start from the tail. */ usb_0_buffer.rx_buf_head = usb_0_buffer.rx_buf_tail; /* * This is a buffer overflow case. But still only bytes equivalent to * full buffer size are useful. */ usb_0_buffer.rx_count = USB_RX_BUF_MAX_SIZE; /* Bytes received is more than or equal to buffer. */ if (USB_RX_BUF_MAX_SIZE <= max_length) { /* * Requested receive length (max_length) is more than the * max size of receive buffer, but at max the full * buffer can be read. */ max_length = USB_RX_BUF_MAX_SIZE; } } else { /* Bytes received is less than receive buffer maximum length. */ if (max_length > usb_0_buffer.rx_count) { /* * Requested receive length (max_length) is more than the data * present in receive buffer. Hence only the number of bytes * present in receive buffer are read. */ max_length = usb_0_buffer.rx_count; } } data_received = max_length; while (max_length > 0) { /* Start to copy from head. */ *data = usb_0_buffer.rx_buf[usb_0_buffer.rx_buf_head]; usb_0_buffer.rx_buf_head++; usb_0_buffer.rx_count--; data++; max_length--; if ((USB_RX_BUF_MAX_SIZE) == usb_0_buffer.rx_buf_head) { usb_0_buffer.rx_buf_head = 0; } } size = get_buffer_size( usb_0_buffer.rx_buf_head, usb_0_buffer.rx_buf_tail, USB_RX_BUF_MAX_SIZE); /* The receive interrupt is enabled back. */ LEAVE_CRITICAL_REGION(); if (size > 60) { CDCDSerialDriver_Read( usb_0_rx_temp_buf, sizeof(usb_0_rx_temp_buf), (TransferCallback) usb0_rx_complete_handler, 0); usb_0_rx_disable_flag = 0; } return data_received; }
/* * This function is called when the USB transfer from the * device to the host is finished. */ static void usb0_tx_complete_handler( unsigned int unused, unsigned char status, unsigned int transferred, unsigned int remaining) { ENTER_CRITICAL_REGION(); while (transferred--) { if ((USB_TX_BUF_MAX_SIZE - 1) == usb_0_buffer.tx_buf_head) { /* Reached the end of buffer, revert back to beginning of buffer. */ usb_0_buffer.tx_buf_head = 0; } else { /* * * Increment the index to point the next character to be * * transmitted. * */ usb_0_buffer.tx_buf_head++; } } if (usb_0_buffer.tx_buf_head != usb_0_buffer.tx_buf_tail) { /* * Prepare a linear buffer for submitting data * remaining data in the buffer */ uint8_t tx_length = 0; uint8_t i = 0; uint8_t head = 0; uint8_t tail = 0; head = usb_0_buffer.tx_buf_head; tail = usb_0_buffer.tx_buf_tail; while (head != tail) { usb_0_tx_temp_buf[i] = usb_0_buffer.tx_buf[head]; if (i == (USB_TX_MAX_SIZE - 1)) //cannot transmit more than USB_TX_MAX_SIZE at once break; if ((head) == (USB_TX_BUF_MAX_SIZE - 1)) head = 0; else head++; i++; } tx_length = i; usb_0_buffer.tx_count = 1; while (CDCDSerialDriver_Write(usb_0_tx_temp_buf, tx_length, (TransferCallback) usb0_tx_complete_handler, 0) != USBD_STATUS_SUCCESS) ; } else { /* No more data for transmission */ usb_0_buffer.tx_count = 0; } LEAVE_CRITICAL_REGION(); }
/** * @brief Starts high priority timer * * This function starts a high priority timer for the specified timeout. * * @param timer_id Timer identifier * @param timer_count Timeout in microseconds * @param timer_cb Callback handler invoked upon timer expiry * @param param_cb Argument for the callback handler * * @return * - @ref PAL_TMR_INVALID_ID if the identifier is undefined, * - @ref MAC_INVALID_PARAMETER if the callback function for this timer is NULL, * - @ref PAL_TMR_ALREADY_RUNNING if the timer is already running, or * - @ref MAC_SUCCESS if timer is started successfully. */ retval_t pal_start_high_priority_timer(uint8_t timer_id, uint16_t timer_count, FUNC_PTR timer_cb, void *param_cb) { if (timer_id >= TOTAL_NUMBER_OF_TIMERS) { return PAL_TMR_INVALID_ID; } if (NULL == timer_cb) { return MAC_INVALID_PARAMETER; } if (NULL != timer_array[timer_id].timer_cb) { /* * Irrespective of the type, the timer is already running if the * callback function of the corresponding timer index in the timer * array is not NULL. */ return PAL_TMR_ALREADY_RUNNING; } /* * A high priority timer can be started, as currently * there is no high priority timer running. */ { uint32_t tc_status; ENTER_CRITICAL_REGION(); high_priority_timer_id = timer_id; /* * The corresponding running timer queue's timer index is updated * with the new values. */ timer_count = (uint32_t)(timer_count / CLOCK_PERIOD); timer_array[timer_id].abs_exp_timer = timer_count; timer_array[timer_id].timer_cb = timer_cb; timer_array[timer_id].param_cb = param_cb; timer_array[timer_id].next_timer_in_queue = NO_TIMER; LEAVE_CRITICAL_REGION(); /* The clock for high prio timer is enabled here. */ PERIPHERAL_CLOCK_ENABLE(PAL_HIGHPRIO_TIMER_PERIPH_ID); /* The clock is enabled at the timer level. */ PAL_HIGHPRIO_TIMER_CCR = PAL_HIGHPRIO_TIMER_CCR_EN; /* * The status register is read to clear any pending compare match * interrupts. */ tc_status = PAL_HIGHPRIO_TIMER_STATUS_REG; /* The compare register is programmed */ PAL_HIGHPRIO_TIMER_COMP_REG = timer_count; /* * The output compare match of timer channel interrupt is * enabled. */ PAL_HIGHPRIO_TIMER_IER = PAL_HIGHPRIO_TIMER_IER_FLAG; /* The timer channel interrupt in AIC is enabled. */ NVIC_EnableIRQ(PAL_HIGHPRIO_TIMER_IRQ_ID); /* Reset counter and Timer channel is triggered. */ PAL_HIGHPRIO_TIMER_CCR = TC_CCR2_SWTRG; /* * Done to avoid compiler warning about variable being not used after * setting. */ tc_status = tc_status; } return MAC_SUCCESS; }
/** * @brief Stops a running timer * * This function stops a running timer with the specified timer_id. * * @param timer_id Timer identifier * * @return * - @ref MAC_SUCCESS if the timer was stopped successfully, * - @ref PAL_TMR_NOT_RUNNING if the specified timer is not running, * - @ref PAL_TMR_INVALID_ID if the specified timer id is undefined. */ retval_t pal_timer_stop(uint8_t timer_id) { bool timer_stop_request_status = false; uint8_t curr_index; uint8_t prev_index; if (timer_id >= TOTAL_NUMBER_OF_TIMERS) { return (PAL_TMR_INVALID_ID); } ENTER_CRITICAL_REGION(); /* Check if any timer has expired. */ internal_timer_handler(); /* The requested timer is first searched in the running timer queue */ if (running_timers > 0) { uint8_t timer_count = running_timers; prev_index = curr_index = running_timer_queue_head; while (timer_count > 0) { if (timer_id == curr_index) { timer_stop_request_status = true; if (timer_id == running_timer_queue_head) { running_timer_queue_head = timer_array[timer_id].next_timer_in_queue; /* * The value in TC_RC corresponds to the timeout pointed * by the 'running_timer_queue_head'. As the head has * changed here, TC_RC needs to be loaded by the new * timeout value, if any. */ prog_comp_reg(); } else { timer_array[prev_index].next_timer_in_queue = timer_array[timer_id].next_timer_in_queue; } /* * The next timer element of the stopped timer is updated * to its default value. */ timer_array[timer_id].next_timer_in_queue = NO_TIMER; break; } else { prev_index = curr_index; curr_index = timer_array[curr_index].next_timer_in_queue; } timer_count--; } if (timer_stop_request_status) { running_timers--; } } /* * The requested timer is not present in the running timer queue. * It will be now searched in the expired timer queue */ if (!timer_stop_request_status) { prev_index = curr_index = expired_timer_queue_head; while (NO_TIMER != curr_index) { if (timer_id == curr_index) { if (timer_id == expired_timer_queue_head) { /* * The requested timer is the head of the expired timer * queue */ if (expired_timer_queue_head == expired_timer_queue_tail) { /* Only one timer in expired timer queue */ expired_timer_queue_head = expired_timer_queue_tail = NO_TIMER; } else { /* * The head of the expired timer queue is moved to next * timer in the expired timer queue. */ expired_timer_queue_head = timer_array[expired_timer_queue_head].next_timer_in_queue; } } else { /* * The requested timer is present in the middle or at the * end of the expired timer queue. */ timer_array[prev_index].next_timer_in_queue = timer_array[timer_id].next_timer_in_queue; /* * If the stopped timer is the one which is at the tail of * the expired timer queue, then the tail is updated. */ if (timer_id == expired_timer_queue_tail) { expired_timer_queue_tail = prev_index; } } timer_stop_request_status = true; break; } else { prev_index = curr_index; curr_index = timer_array[curr_index].next_timer_in_queue; } } } if (timer_stop_request_status) { /* * The requested timer is stopped, hence the structure elements of the * timer are updated. */ timer_array[timer_id].timer_cb = NULL; } LEAVE_CRITICAL_REGION(); if (timer_stop_request_status) { return (MAC_SUCCESS); } return (PAL_TMR_NOT_RUNNING); }
/* * \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. */ pal_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 Calibrates the internal RC oscillator * * This function calibrates the internal RC oscillator, based * on the external 32.768 Hz crystal clock source. * * @return True if calibration is successful, false otherwise. */ bool pal_calibrate_rc_osc(void) { /* * Use the 32.768 kHz external crystal oscillator as reference clock source. */ /* * This is the actual value of the timer to be calibrated * after each calibration run. */ uint16_t curr_value_cal_timer = 0; /* This is the best OSCCAL value. */ uint8_t best_value_osccal = 0; /* * This is the smallest difference between the target value and the actual value * of the timer the timer to be calibrated. */ uint16_t best_dif_timers = ~(uint16_t)0; /* * This is the difference between between the target value and the actual value * of the timer the timer to be calibrated of the current calibration attempt. */ uint16_t curr_dif_timers = 0; uint16_t counter; uint8_t tccr2b; uint8_t tccr1b; uint8_t tccr1a; bool cal_result = true; ENTER_CRITICAL_REGION(); /* * Save current values of timer status. */ tccr2b = TCCR2B; tccr1b = TCCR1B; tccr1a = TCCR1A; /* * Stop timers 1 and 2. * Set timer 1 to normal mode (no CTC, no PWM, just count). */ TCCR2B = 0; TCCR1B = 0; TCCR1A = 0; for (counter = 0; counter < MAX_CAL_LOOP_CNT; counter++) { /* * Delete pending timer 1 and 2 interrupts, and clear the * counters. */ TIFR1 = 0xFF; TIFR2 = 0xFF; TCNT2 = 0; TCNT1 = 0; /* Kick timer1 with internal clock source and no prescaler */ TCCR1B = (1 << CS10); /* * Kick timer2 with external 32.768 Hz asynchronous clock * and no prescaler */ TCCR2B = (1 << CS20); ASSR = (1 << AS2); /* * Wait for timer 2 to overflow. */ while (!(TIFR2 & (1 << TOV2))) { /* Wait */ } /* * Stop timer 1. Now, TCNT1 contains the number of CPU cycles * counted during F_CPU / (32 * 256) cycles. */ TCCR1B = 0; TCCR2B = 0; curr_value_cal_timer = TCNT1; /* * Check if reference timer is running at all, * i.e. the reference clock is available. */ if (0 == curr_value_cal_timer) { /* Reference timer is not running, return error. */ cal_result = false; break; } if (curr_value_cal_timer <= (uint16_t)(TARGETVAL_CALIBRATION)) { curr_dif_timers = (uint16_t)(TARGETVAL_CALIBRATION) - curr_value_cal_timer; } else { curr_dif_timers = curr_value_cal_timer - (uint16_t)(TARGETVAL_CALIBRATION); } if (curr_dif_timers < best_dif_timers) { best_dif_timers = curr_dif_timers; best_value_osccal = OSCCAL; } if (curr_value_cal_timer <= (uint16_t)(TARGETVAL_CALIBRATION)) { /* Too slow, increase speed */ OSCCAL++; } else { /* Too fast, lower speed */ OSCCAL--; } } TCCR2B = tccr2b; TCCR1B = tccr1b; TCCR1A = tccr1a; LEAVE_CRITICAL_REGION(); OSCCAL = best_value_osccal; return (cal_result); }
void rf230_clear_callback_handler(void) { ENTER_CRITICAL_REGION(); rf230_callback_handler = NULL; LEAVE_CRITICAL_REGION(); }
/* * \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. 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; }
void rf230_set_callback_handler(rf230_cb_handler_t handler) { ENTER_CRITICAL_REGION(); rf230_callback_handler = handler; LEAVE_CRITICAL_REGION(); }
/* * \brief Sends frame * * \param use_csma Flag indicating if CSMA is requested * \param tx_retries Flag indicating if transmission retries are requested * by the MAC layer */ void send_frame(csma_mode_t csma_mode, bool tx_retries) { tal_trx_status_t trx_status; /* Configure tx according to tx_retries */ if (tx_retries) { trx_bit_write(SR_MAX_FRAME_RETRIES, tal_pib.MaxFrameRetries); } else { trx_bit_write(SR_MAX_FRAME_RETRIES, 0); } /* Configure tx according to csma usage */ if ((csma_mode == NO_CSMA_NO_IFS) || (csma_mode == NO_CSMA_WITH_IFS)) { if (tx_retries) { trx_bit_write(SR_MAX_CSMA_RETRIES, tal_pib.MaxCSMABackoffs); trx_reg_write(RG_CSMA_BE, 0x00); } else { trx_bit_write(SR_MAX_CSMA_RETRIES, 7); } } else { trx_reg_write(RG_CSMA_BE, ((tal_pib.MaxBE << 4) | tal_pib.MinBE)); trx_bit_write(SR_MAX_CSMA_RETRIES, tal_pib.MaxCSMABackoffs); } CONF_REG_WRITE(); do { trx_status = set_trx_state(CMD_TX_ARET_ON); } while (trx_status != TX_ARET_ON); /* Handle interframe spacing */ if (csma_mode == NO_CSMA_WITH_IFS) { if (last_frame_length > aMaxSIFSFrameSize) { pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US( macMinLIFSPeriod_def) - IRQ_PROCESSING_DLY_US - PRE_TX_DURATION_US); last_frame_length = 0; } else { pal_timer_delay(TAL_CONVERT_SYMBOLS_TO_US( macMinSIFSPeriod_def) - IRQ_PROCESSING_DLY_US - PRE_TX_DURATION_US); last_frame_length = 0; } } else { /* * If no delay is applied after switching to TX_ARET_ON, * a short delay is required that allows that a pending TX_END *IRQ for * ACK transmission gets served. */ pal_timer_delay(TRX_IRQ_DELAY_US); } ENTER_CRITICAL_REGION(); /* prevent from buffer underrun */ /* Toggle the SLP_TR pin triggering transmission. */ TRX_SLP_TR_HIGH(); PAL_WAIT_65_NS(); TRX_SLP_TR_LOW(); /* * Send the frame to the transceiver. * Note: The PhyHeader is the first byte of the frame to * be sent to the transceiver and this contains the frame * length. */ trx_frame_write(tal_frame_to_tx, tal_frame_to_tx[0] - 1); tal_state = TAL_TX_AUTO; LEAVE_CRITICAL_REGION(); }
/* * \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 regular interrupts except Awake-IRQ */ 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, PA_EXT_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 #ifdef EXT_RF_FRONT_END_CTRL /* Disable RF front end control */ trx_bit_write(SR_PA_EXT_EN, PA_EXT_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_CCA_ED_READY); 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 Reads or removes a buffer from queue * * This function reads or removes a buffer from a queue as per * the search criteria provided. If search criteria is NULL, then the first * buffer is returned, otherwise buffer matching the given criteria is returned * * @param q Queue from which buffer is to be read or removed. * * @param mode Mode of operations. If this parameter has value REMOVE_MODE, * buffer will be removed from queue and returned. If this parameter *is * READ_MODE, buffer pointer will be returned without * removing from queue. * * @param search Search criteria structure pointer. * * @return Buffer header pointer, if the buffer is successfully * removed or read, otherwise NULL is returned. * \ingroup group_qmm */ static buffer_t *queue_read_or_remove(queue_t *q, buffer_mode_t mode, search_t *search) { buffer_t *buffer_current = NULL; buffer_t *buffer_previous; ENTER_CRITICAL_REGION(); /* Check whether queue is empty */ if (q->size != 0) { buffer_current = q->head; buffer_previous = q->head; /* First get buffer matching with criteria */ if (NULL != search) { uint8_t match; /* Search for all buffers in the queue */ while (NULL != buffer_current) { match = search->criteria_func( (void *)buffer_current->body, search->handle); if (match) { /* Break, if search criteria matches */ break; } buffer_previous = buffer_current; buffer_current = buffer_current->next; } } /* Buffer matching with search criteria found */ if (NULL != buffer_current) { /* Remove buffer from the queue */ if (REMOVE_MODE == mode) { /* Update head if buffer removed is first node **/ if (buffer_current == q->head) { q->head = buffer_current->next; } else { /* Update the link by removing the *buffer */ buffer_previous->next = buffer_current->next; } /* Update tail if buffer removed is last node */ if (buffer_current == q->tail) { q->tail = buffer_previous; } /* Update size */ q->size--; if (NULL == q->head) { q->tail = NULL; } } /* Read buffer from the queue */ else { /* Nothing needs done if the mode is READ_MODE **/ } } } /* q->size != 0 */ LEAVE_CRITICAL_REGION(); /* Return the buffer. note that pointer to header of buffer is returned **/ return (buffer_current); } /* queue_read_or_remove */
void main(void) { #else int main(void) { #endif /* Ensure that the watchdog is not running. */ wdt_disable(); /* Initialize AVR peripheral modules. */ (bool)avr_init(); /* Check if the RX and TX pins are shorted. If they are shorted, the RZUSBSTICK * shall start the bootloader. If not, continue to verify if the application * requested to enter the bootloader. */ /* Check if the application has requested to enter the bootloader. */ if ((BOOT_PIN & (1 << BOOT_RX)) != (1 << BOOT_RX)) { /* Check that RX goes high when TX is pulled high. */ BOOT_PORT |= (1 << BOOT_TX); nop(); nop(); nop(); nop(); if ((BOOT_PIN & (1 << BOOT_RX)) != (1 << BOOT_RX)) { start_application(); } } else { /* Check if the application has requested to enter the bootloader. */ uint8_t volatile magic_value = 0xAA; EEGET(magic_value, EE_BOOT_MAGIC_ADR); if (EE_BOOT_MAGIC_VALUE != magic_value) { start_application(); } else { EEPUT(EE_BOOT_MAGIC_ADR, 0xFF); } } /* Set the interrupt vectors to the bootloader, initialize the LEDs and the * VRT kernel. */ ENTER_CRITICAL_REGION(); uint8_t temp_mcucr = MCUCR; MCUCR = (1 << IVCE); MCUCR = (1 << IVSEL); MCUCR = temp_mcucr; LEAVE_CRITICAL_REGION(); LED_INIT(); vrt_init(); if (true != eep_init()) { error_handler(); } else if (true != cmd_if_init()) { error_handler(); } LED_ORANGE_ON(); /* Enable Interrupts. */ sei(); /* Enter the endless application loop. */ for (;;) { vrt_dispatch_event(); usb_task(); } }