void timeslot_handler_init(nrf_clock_lfclksrc_t lfclksrc)
{
    if (g_framework_initialized)
    {
        /* may happen with serial interface, can safely skip redundant inits */
        return;
    }
    uint32_t error;


    switch (lfclksrc)
    {
        case NRF_CLOCK_LFCLKSRC_XTAL_100_PPM:
            g_lfclk_ppm = 100;
            break;
        case NRF_CLOCK_LFCLKSRC_XTAL_150_PPM:
            g_lfclk_ppm = 150;
            break;
        case NRF_CLOCK_LFCLKSRC_XTAL_20_PPM:
            g_lfclk_ppm = 20;
            break;
        case NRF_CLOCK_LFCLKSRC_XTAL_250_PPM:
            g_lfclk_ppm = 250;
            break;
        case NRF_CLOCK_LFCLKSRC_XTAL_30_PPM:
            g_lfclk_ppm = 30;
            break;
        case NRF_CLOCK_LFCLKSRC_XTAL_500_PPM:
            g_lfclk_ppm = 500;
            break;
        case NRF_CLOCK_LFCLKSRC_XTAL_50_PPM:
            g_lfclk_ppm = 50;
            break;
        case NRF_CLOCK_LFCLKSRC_XTAL_75_PPM:
            g_lfclk_ppm = 75;
            break;
        default:
            g_lfclk_ppm = 250;
    }


    g_is_in_callback = false;
    g_framework_initialized = true;

    error = sd_nvic_EnableIRQ(SD_EVT_IRQn);
    APP_ERROR_CHECK(error);

    error = sd_radio_session_open(&radio_signal_callback);
    APP_ERROR_CHECK(error);

    timer_init();
    g_start_time_ref = NRF_RTC0->COUNTER;
    g_timeslot_length = TIMESLOT_SLOT_LENGTH;
    timeslot_order_earliest(g_timeslot_length, true);
}
Exemple #2
0
/**
* @brief Timeslot related events callback
*   Called whenever the softdevice tries to change the original course of actions 
*   related to the timeslots
*/
void ts_sd_event_handler(void)
{
    uint32_t evt;
    SET_PIN(6);
    while (sd_evt_get(&evt) == NRF_SUCCESS)
    {
        PIN_OUT(evt, 32);
        switch (evt)
        {
            case NRF_EVT_RADIO_SESSION_IDLE:

                timeslot_order_earliest(TIMESLOT_SLOT_LENGTH, true);
                break;

            case NRF_EVT_RADIO_SESSION_CLOSED:
                APP_ERROR_CHECK(NRF_ERROR_INVALID_DATA);

                break;

            case NRF_EVT_RADIO_BLOCKED:
                /* something in the softdevice is blocking our requests, 
                go into emergency mode, where slots are short, in order to 
                avoid complete lockout */
                timeslot_order_earliest(TIMESLOT_SLOT_EMERGENCY_LENGTH, true);
                break;

            case NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN:
                APP_ERROR_CHECK(NRF_ERROR_INVALID_DATA);
                break;

            case NRF_EVT_RADIO_CANCELED:
                timeslot_order_earliest(TIMESLOT_SLOT_LENGTH, true);
                break;
            default:
                APP_ERROR_CHECK(NRF_ERROR_INVALID_STATE);
        }
    }
    CLEAR_PIN(6);
}
/**
* @brief Timeslot related events callback
*   Called whenever the softdevice tries to change the original course of actions
*   related to the timeslots
*/
void ts_sd_event_handler(uint32_t evt)
{
    SET_PIN(PIN_SD_EVT_HANDLER);
    switch (evt)
    {
        case NRF_EVT_RADIO_SESSION_IDLE:
            /* the idle event is usually triggered when rbc_mesh_stop is called,
                but if this isn't the case, we have to restart the TS */
            if (g_timeslot_forced_command != TS_FORCED_COMMAND_STOP)
            {
                timeslot_order_earliest(TIMESLOT_SLOT_LENGTH, true);
            }
            break;

        case NRF_EVT_RADIO_SESSION_CLOSED:
            APP_ERROR_CHECK(NRF_ERROR_INVALID_DATA);

            break;

        case NRF_EVT_RADIO_BLOCKED:
            /* something in the softdevice is blocking our requests,
            go into emergency mode, where slots are short, in order to
            avoid complete lockout */
            timeslot_order_earliest(TIMESLOT_SLOT_EMERGENCY_LENGTH, true);
            break;

        case NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN:
            APP_ERROR_CHECK(NRF_ERROR_INVALID_DATA);
            break;

        case NRF_EVT_RADIO_CANCELED:
            timeslot_order_earliest(TIMESLOT_SLOT_LENGTH, true);
            break;
        default:
            break;
    }
    CLEAR_PIN(PIN_SD_EVT_HANDLER);
}
Exemple #4
0
void timeslot_handler_init(void)
{
    uint32_t error;

    g_is_in_callback = false;
    g_framework_initialized = true;

    error = sd_nvic_EnableIRQ(SD_EVT_IRQn);
    APP_ERROR_CHECK(error);

    error = sd_radio_session_open(&radio_signal_callback);
    APP_ERROR_CHECK(error);
    g_start_time_ref = NRF_RTC0->COUNTER;
    g_timeslot_length = TIMESLOT_SLOT_LENGTH;
    timeslot_order_earliest(g_timeslot_length, true);
}
Exemple #5
0
/**
* @brief Timeslot end guard timer callback. Attempts to extend the timeslot. 
*/
static void end_timer_handler(void)
{
    timeslot_order_earliest(((g_timeslot_length > 100000)? 100000 : g_timeslot_length), true);
}
/**
* @brief Radio signal callback handler taking care of all signals in searching
*   mode
*/
static nrf_radio_signal_callback_return_param_t* radio_signal_callback(uint8_t sig)
{
    static uint32_t requested_extend_time = 0;
    static uint32_t successful_extensions = 0;
    static uint32_t timeslot_count = 0;

    if (sig == NRF_RADIO_CALLBACK_SIGNAL_TYPE_START)
    {
        g_timeslot_forced_command = TS_FORCED_COMMAND_NONE;
    }
    else /* on forced command */
    {
        switch (g_timeslot_forced_command)
        {
            case TS_FORCED_COMMAND_STOP:
                g_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_END;
                g_is_in_timeslot = false;
                g_end_timer_triggered = false;
                CLEAR_PIN(PIN_IN_TS);
                event_handler_on_ts_end();
                timeslot_count = 0;
                return &g_ret_param;

            case TS_FORCED_COMMAND_RESTART:
                timeslot_order_earliest(TIMESLOT_SLOT_LENGTH, true);
                g_is_in_timeslot = false;
                g_end_timer_triggered = false;
                CLEAR_PIN(PIN_IN_TS);
                event_handler_on_ts_end();
                radio_disable();

                return &g_ret_param;

            default:
                break;
        }
    }

    g_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
    g_is_in_callback = true;

    SET_PIN(PIN_IN_CB);

    switch (sig)
    {
        case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START:
        {
            SET_PIN(PIN_IN_TS);
            g_is_in_timeslot = true;
            g_end_timer_triggered = false;
            successful_extensions = 0;

            if (timeslot_count > 0)
            {
                global_time_update();
            }
            mesh_packet_on_ts_begin();
            event_handler_on_ts_begin();
            timer_on_ts_begin();
            tc_on_ts_begin();

            g_negotiate_timeslot_length = TIMESLOT_SLOT_EXTEND_LENGTH;
            g_timeslot_length = g_next_timeslot_length;

            timer_order_cb_sync_exec(TIMER_INDEX_TS_END, g_timeslot_length - end_timer_margin(),
                    end_timer_handler);

            /* attempt to extend our time right away */
            timeslot_extend(g_negotiate_timeslot_length);

            /* increase timeslot-count, but skip =0 on rollover */
            if (!++timeslot_count)
            {
                timeslot_count++;
            }

            break;
        }
        case NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO:
            /* send to radio control module */
            SET_PIN(PIN_RADIO_SIGNAL);
            radio_event_handler();
            CLEAR_PIN(PIN_RADIO_SIGNAL);
            break;

        case NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0:
            /* send to timer control module */
            SET_PIN(PIN_TIMER_SIGNAL);
            timer_event_handler();
            CLEAR_PIN(PIN_TIMER_SIGNAL);
            break;

        case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED:
            g_timeslot_length += requested_extend_time;
            requested_extend_time = 0;
            ++successful_extensions;

            timer_abort(TIMER_INDEX_TS_END);

            timer_order_cb_sync_exec(TIMER_INDEX_TS_END, g_timeslot_length - end_timer_margin(),
                    end_timer_handler);

            g_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;

            TICK_PIN(PIN_EXTENSION_OK);
            if (g_timeslot_length + g_negotiate_timeslot_length < TIMESLOT_MAX_LENGTH)
            {
                timeslot_extend(g_negotiate_timeslot_length);
            }
            else
            {
                /* done extending, check for new trickle event */
                vh_on_timeslot_begin();
            }

            break;

        case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED:
            g_negotiate_timeslot_length >>= 1;
            TICK_PIN(PIN_EXTENSION_FAIL);
            if (g_negotiate_timeslot_length > 1000)
            {
                timeslot_extend(g_negotiate_timeslot_length);
            }
            else
            {
                /* done extending, check for new trickle event */
                vh_on_timeslot_begin();
            }
            break;

        default:
            APP_ERROR_CHECK(NRF_ERROR_INVALID_STATE);
    }



    if (g_end_timer_triggered)
    {
        timeslot_order_earliest(TIMESLOT_SLOT_LENGTH, true);
        g_is_in_timeslot = false;
        g_end_timer_triggered = false;
        CLEAR_PIN(PIN_IN_TS);
        event_handler_on_ts_end();
        radio_disable();
        timer_on_ts_end();
    }
    else if (g_ret_param.callback_action == NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND)
    {
        requested_extend_time = g_ret_param.params.extend.length_us;
    }
    else
    {
        requested_extend_time = 0;
    }
    g_is_in_callback = false;

    CLEAR_PIN(PIN_IN_CB);
    return &g_ret_param;
}