void transport_control_step(void)
{
    uint64_t next_time;
    uint64_t time_now = timer_get_timestamp() + global_time;
    trickle_time_update(time_now);
    uint32_t error_code = mesh_srv_get_next_processing_time(&next_time);
    if (error_code != NRF_SUCCESS)
    {
        return;
    }

    if (next_time < time_now)
    {
        async_event_t async_evt;
        async_evt.callback.generic = trickle_step_callback;
        async_evt.type = EVENT_TYPE_GENERIC;
        event_handler_push(&async_evt);
    }
    else
    {
        if (next_time < global_time + timeslot_get_end_time())
        {
            timer_abort(step_timer_index);
            step_timer_index = timer_order_cb(next_time - global_time, trickle_step_callback);
        }
    }
}
/**
* @brief Async event dispatcher, works in APP LOW
*/
void QDEC_IRQHandler(void)
{
    while (true)
    {
        bool got_evt = false;

        got_evt |= event_fifo_pop(&g_async_evt_fifo);

        if (timeslot_get_end_time() > 0) /* in timeslot */
        {
            got_evt |= event_fifo_pop(&g_async_evt_fifo_ts);
        }

        if (!got_evt)
        {
            break;
        }
    }
}
/**
* @brief Handle trickle timing events
*/
static void trickle_step_callback(void)
{
    TICK_PIN(6);
    /* check if timeslot is about to end */
    if (timeslot_get_remaining_time() < RADIO_SAFETY_TIMING_US)
        return;

    uint64_t time_now = global_time + timer_get_timestamp();
    trickle_time_update(time_now);

    packet_t packet;
    bool has_anything_to_send = false;

    mesh_srv_packet_assemble(&packet, PACKET_DATA_MAX_LEN * PACKET_MAX_CHAIN_LEN,
        &has_anything_to_send);

    if (has_anything_to_send)
    {
        TICK_PIN(PIN_MESH_TX);
        radio_disable();

        uint8_t packet_and_addr_type = PACKET_TYPE_ADV_NONCONN |
            ((packet.sender.addr_type == BLE_GAP_ADDR_TYPE_PUBLIC)?
            0 :
            PACKET_ADDR_TYPE_MASK);

        uint8_t* temp_data_ptr = &packet.data[0];
        uint8_t* tx_data_ptr = &tx_data[0];
        tx_data_ptr[PACKET_TYPE_POS] = packet_and_addr_type;

        /* Code structured for packet chaining, although this is yet
         to be implemented. */
        do
        {
            uint8_t min_len = ((packet.length > PACKET_DATA_MAX_LEN)?
                PACKET_DATA_MAX_LEN :
                packet.length);

            tx_data_ptr[PACKET_PADDING_POS] = 0;
            tx_data_ptr[PACKET_LENGTH_POS] = (min_len + PACKET_ADDR_LEN);
            tx_data_ptr[PACKET_TYPE_POS] = packet_and_addr_type;

            memcpy(&tx_data_ptr[PACKET_ADDR_POS], packet.sender.addr, PACKET_ADDR_LEN);
            memcpy(&tx_data_ptr[PACKET_DATA_POS], &temp_data_ptr[0], min_len);

            radio_event_t tx_event;
            tx_event.access_address = 0;
            rbc_mesh_channel_get(&tx_event.channel);
            tx_event.event_type = RADIO_EVENT_TYPE_TX;
            tx_event.packet_ptr = &tx_data_ptr[0];
            tx_event.start_time = 0;
            tx_event.callback.tx = NULL;

            radio_order(&tx_event);
            TICK_PIN(0);
        } while (0);

        order_search(); /* search for the rest of the timeslot */
    }

    /* order next processing */
    uint64_t next_time;
    uint64_t end_time = timeslot_get_end_time();
    uint32_t error_code = mesh_srv_get_next_processing_time(&next_time);

    if (error_code == NRF_SUCCESS && next_time < global_time + end_time)
    {
        timer_abort(step_timer_index);
        step_timer_index = timer_order_cb(next_time - global_time, trickle_step_callback);
    }
}