Esempio n. 1
0
/**
 * DCI handler init
 */
void drDcihInit(
    const addr_t    dciBuffer,
    const uint32_t  dciBufferLen
){
    /* Ensure thread stack is clean */
    clearStack( drDcihStack );

    /* DCI message buffer */
    message = (dciMessage_t*) dciBuffer;

    /**
     * Update DCI handler thread so that notifications will be delivered
     * to DCI handler thread
     */
    if (DRAPI_OK != drUtilsUpdateNotificationThread( DRIVER_THREAD_NO_DCIH ))
    {
        drDbgPrintLnf("[Driver DrTemplate] drDcihInit(): Updating notification thread failed");
    }

    /**
     * Start DCI handler thread. EXH thread becomes local
     * exception handler of DCIH thread
     */
    if (DRAPI_OK != drApiStartThread(
                    DRIVER_THREAD_NO_DCIH,
                    FUNC_PTR(drDcih),
                    getStackTop(drDcihStack),
                    DCIH_PRIORITY,
                    DRIVER_THREAD_NO_EXCH))

    {
            drDbgPrintLnf("[Driver DrTemplate] drDcihInit(): drApiStartThread failed");
    }
}
/*
 * @brief Set the transceiver state to PHY_TRX_OFF
 *
 * This actually turns the radio receiver off - i.e. this is the end
 * of the PHY_RX_ON period.
 *
 * @param callback_parameter Callback parameter
 */
static void mac_t_rx_off_cb(void *callback_parameter)
{
    uint8_t status;

    /*
     * Rx is disabled.
     * This will make sure that the radio will be put to sleep in function
     * mac_sleep_trans().
     */
    mac_rx_enabled = false;

    /*
     * In case macRxOnWhenIdle is not set, the radio is put to PHY_TRX_OFF
     * state, until the return status does not match the desired radio state,
     * i.e. PHY_TRX_OFF
     */
    if (!mac_pib.mac_RxOnWhenIdle)
    {
        /*
         * In case the radio is awake, we need to switch RX off.
         */
        if (RADIO_AWAKE == mac_radio_sleep_state)
        {
            status = tal_rx_enable(PHY_TRX_OFF);

            if (status != PHY_TRX_OFF)
            {
                /*
                 * The TAL is still busy and cannot set the TRX to OFF.
                 * In order to get progress this requires another
                 * round of the TAL task being processed.
                 * Therefore the MAC task needs to stopp here and pass
                 * controll back to the TAL.
                 * This is reached by starting the Rx-Enable timer again
                 * for a very short time with the same callback returning
                 * here very soon.
                 */
                pal_timer_start(T_Rx_Enable,
                                MIN_TIMEOUT,
                                TIMEOUT_RELATIVE,
                                (FUNC_PTR())mac_t_rx_off_cb,
                                NULL);

                /*
                 * Return now, since the TAL is still busy, so radio cannot go
                 * to sleep for now.
                 */
                return;
            }
            else
            {
                /* Set radio to sleep if allowed */
                mac_sleep_trans();
            }
        }
    }

    callback_parameter = callback_parameter;  /* Keep compiler happy. */
}
/*
 * @brief Internal function to handle immediate RX_ON
 *
 * This function immediately enables the receiver with the given
 * RxOnDuration time in symbols from now.
 *
 * @param rx_on_duration_symbols Duration in symbols that the reciever is
 *                               switched on.
 */
static void handle_rx_on(uint32_t rx_on_duration_symbols, uint8_t *m)
{
    retval_t timer_status;
    uint8_t rx_enable_status = mac_rx_enable();

    /*
     * TODO: Once it is possible to restart a timer even if it is
     * already running, this could be improved by simply calling
     * function pal_timer_start() without this previous check using
     * function pal_is_timer_running().
     */
    if (pal_is_timer_running(T_Rx_Enable))
    {
        /*
         * Rx-Enable timer is already running, so we need to stopp it first
         * before it will be started.
         */
        pal_timer_stop(T_Rx_Enable);
    }

    /*
     * Start timer for the Rx On duration of the radio being on
     * in order to switch it off later again.
     */
    timer_status =
        pal_timer_start(T_Rx_Enable,
                        TAL_CONVERT_SYMBOLS_TO_US(rx_on_duration_symbols),
                        TIMEOUT_RELATIVE,
                        (FUNC_PTR())mac_t_rx_off_cb,
                        NULL);

    ASSERT(MAC_SUCCESS == timer_status);

    /*
     * Send the confirm immediately depending on the status of
     * the timer start and the Rx Status
     */
    if (MAC_SUCCESS != timer_status)
    {
        gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_INVALID_PARAMETER);
        /* Do house-keeeping and turn radio off. */
        mac_t_rx_off_cb(NULL);
    }
    else if (PHY_RX_ON != rx_enable_status)
    {
        gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_TX_ACTIVE);
    }
    else
    {
        gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_SUCCESS);
    }

    return;
}
Esempio n. 4
0
/**
 * @brief PLL calibration and filter tuning timer callback
 *
 * @param parameter Unused callback parameter
 */
void calibration_timer_handler_cb(void *parameter)
{
    retval_t timer_status;

    handle_ftn_pll_calibration();

    /* Restart periodic calibration timer again. */
    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);
    }

    parameter = parameter;  /* Keep compiler happy. */
}
/**
 * @brief Implement the MLME-RX-ENABLE.request primitive.
 *
 * The MLME-RX-ENABLE.request primitive is generated by the next
 * higher layer and issued to MAC to enable the receiver for a
 * fixed duration, at a time relative to the start of the current or
 * next superframe on a beacon-enabled PAN or immediately on a
 * nonbeacon-enabled PAN. The receiver is enabled exactly once per
 * primitive request.
 *
 * @param m Pointer to the MLME-RX-ENABLE.request message
 */
void mlme_rx_enable_request(uint8_t *m)
{
    mlme_rx_enable_req_t *rxe;

    rxe = (mlme_rx_enable_req_t *)BMM_BUFFER_POINTER((buffer_t *)m);

    /* If RxOnDuration is zero, the receiver shall be disabled */
    if (0 == rxe->RxOnDuration)
    {
        /*
         * Turn the radio off. This is doney by calling the
         * same function as for the expiration of the Rx on timer.
         */
        mac_t_rx_off_cb(NULL);

        /* Send the confirm immediately. */
        gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_SUCCESS);
        return;
    }

    /*
     * Reject the request when the MAC is currently in any of the
     * polling states or scanning.
     */
    if ((MAC_POLL_IDLE != mac_poll_state) ||
        (MAC_SCAN_IDLE != mac_scan_state)
       )
    {
        /* Send the confirm immediately. */
        gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_TX_ACTIVE);
        return;
    }

#ifdef BEACON_SUPPORT
    if (NON_BEACON_NWK == tal_pib.BeaconOrder)
    {
        handle_rx_on(rxe->RxOnDuration, m);
    }
    else
    {
        /* We have a beacon-enabled network. */
        uint32_t curr_beacon_int_time_symbols = TAL_GET_BEACON_INTERVAL_TIME(tal_pib.BeaconOrder);
        uint32_t now_time_symbols;
        uint32_t symbols_since_beacon;
        uint32_t rx_on_time_symbols;
        retval_t timer_status;

        /*
         * Determine if (RxOnTime + RxOnDuration) is less than the beacon
         * interval.
         * According to 7.1.10.1.3:
         * On a beacon-enabled PAN, the MLME first determines whether
         * (RxOnTime + RxOnDuration) is less than the beacon interval, defined
         * by macBeaconOrder. If it is not less, the MLME issues the
         * MLME-RX-ENABLE.confirm primitive with a status of MAC_INVALID_PARAMETER.
         */

        rx_off_time_symbols = rxe->RxOnTime + rxe->RxOnDuration;

        if (rx_off_time_symbols >= curr_beacon_int_time_symbols)
        {
            /* Send the confirm immediately. */
            gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_INVALID_PARAMETER);
            return;
        }

        pal_get_current_time(&now_time_symbols);
        now_time_symbols = TAL_CONVERT_US_TO_SYMBOLS(now_time_symbols);

        symbols_since_beacon  = tal_sub_time_symbols(now_time_symbols, tal_pib.BeaconTxTime);

        /*
         * Actually, MLME-RX-ENABLE.request in a beacon enabled PAN does
         * only make sense if the MAC is currently tracking beacons, so
         * that macBeaconTxTime is up to date. If it appears that
         * the last known macBeaconTxTime does not relate to the
         * current superframe, reject the request.
         */
        if (symbols_since_beacon > curr_beacon_int_time_symbols)
        {
            /* Send the confirm immediately. */
            gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_INVALID_PARAMETER);
            return;
        }

        rx_on_time_symbols = tal_add_time_symbols(tal_pib.BeaconTxTime, rxe->RxOnTime);

        /* Check whether RxOnTime can still be handled in current CAP. */
        pal_get_current_time(&now_time_symbols);
        now_time_symbols = TAL_CONVERT_US_TO_SYMBOLS(now_time_symbols);

        if (tal_add_time_symbols(rx_on_time_symbols, TAL_CONVERT_US_TO_SYMBOLS(MIN_TIMEOUT))
            < now_time_symbols)
        {
            /* RxOnTime not possible within this CAP, see whether deferred
             * handling is allowed or not.. */
            if (!(rxe->DeferPermit))
            {
                gen_rx_enable_conf((buffer_t *)m, (uint8_t)MAC_PAST_TIME);
                return;
            }
            else
            {
                /*
                 * The MAC defers until the next superframe and attempts to enable
                 * the receiver in that superframe.
                 */
                rx_on_time_symbols = tal_add_time_symbols(rx_on_time_symbols,
                                                          curr_beacon_int_time_symbols);
            }
        }

        /*
         * Since the Rx-Enable timer could already be running,
         * it is stopped first, before it will be started (again).
         */
        pal_timer_stop(T_Rx_Enable);

        do
        {
            /*
             * Start a timer to turn Rx ON at the time "rxe->RxOnTime" from the start
             * of the next superframe.
             * Return value to be checked, because Rx on time could be too short
             * or in the past already.
             */
            timer_status =
                pal_timer_start(T_Rx_Enable,
                                TAL_CONVERT_SYMBOLS_TO_US(rx_on_time_symbols),
                                TIMEOUT_ABSOLUTE,
                                (FUNC_PTR())mac_t_rx_on_cb,
                                (void *)m);

            if (MAC_SUCCESS != timer_status)
            {
                rx_on_time_symbols = tal_add_time_symbols(rx_on_time_symbols,
                                                          curr_beacon_int_time_symbols);
            }
        }
        while (MAC_SUCCESS != timer_status);

        /* Remember the time to turn off the receiver. */
        rx_off_time_symbols = tal_add_time_symbols(rx_on_time_symbols, rxe->RxOnDuration);

        /* The remaining stuff will be done once the Rx On Timer expires. */
    }
#else   /* No BEACON_SUPPORT */
    handle_rx_on(rxe->RxOnDuration, m);
#endif  /* BEACON_SUPPORT / No BEACON_SUPPORT */
} /* mlme_rx_enable_request() */
/**
 * @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;
    }

#if (NUMBER_OF_TAL_TIMERS > 0)
    /* Clear all running TAL timers. */
    {
        uint8_t timer_id;

        ENTER_CRITICAL_REGION();

        for (timer_id = TAL_FIRST_TIMER_ID; timer_id <= TAL_LAST_TIMER_ID;
             timer_id++)
        {
            pal_timer_stop(timer_id);
        }

        LEAVE_CRITICAL_REGION();
    }
#endif

    /* 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(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;
}