Пример #1
0
/**
 * @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() */
Пример #2
0
/**
 * @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;
}
Пример #3
0
/*
 * 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();
}
Пример #4
0
/**
 * @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;
}
Пример #5
0
/**
 * @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);
}
Пример #6
0
/*
 * \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;
}
Пример #7
0
/**
 * @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);
}
Пример #8
0
void rf230_clear_callback_handler(void) {
    ENTER_CRITICAL_REGION();
    rf230_callback_handler = NULL;
    LEAVE_CRITICAL_REGION();
}
Пример #9
0
/*
 * \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;
}
Пример #10
0
void rf230_set_callback_handler(rf230_cb_handler_t handler) {
    ENTER_CRITICAL_REGION();
    rf230_callback_handler = handler;
    LEAVE_CRITICAL_REGION();
}
Пример #11
0
/*
 * \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();
}
Пример #12
0
/*
 * \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() */
Пример #13
0
/*
 * @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();
    }
}