Example #1
0
File: main.c Project: tkadom/TWBLE
/**
* @brief RBC_MESH framework event handler. Defined in rbc_mesh.h. Handles
*   events coming from the mesh. Sets LEDs according to data
*
* @param[in] evt RBC event propagated from framework
*/
void rbc_mesh_event_handler(rbc_mesh_event_t* evt)
{
    TICK_PIN(28);
    switch (evt->event_type)
    {
        case RBC_MESH_EVENT_TYPE_CONFLICTING_VAL:
        case RBC_MESH_EVENT_TYPE_NEW_VAL:
        case RBC_MESH_EVENT_TYPE_UPDATE_VAL:

            if (evt->value_handle > 2)
                break;

            led_config(evt->value_handle, evt->data[0]);
            break;
        default:
            break;
    }
}
Example #2
0
/**
 * Event handler on receiving a message from
 */
void rbc_mesh_event_handler(rbc_mesh_event_t* evt)
{
	TICK_PIN(28);
	//nrf_gpio_gitpin_toggle(PIN_GPIO_LED1);

	switch (evt->event_type)
	{
	case RBC_MESH_EVENT_TYPE_CONFLICTING_VAL:
		LOGd("conflicting value");
		break;
	case RBC_MESH_EVENT_TYPE_NEW_VAL:
		LOGd("new value");
		break;
	case RBC_MESH_EVENT_TYPE_UPDATE_VAL:
		LOGd("update value");
		break;
	case RBC_MESH_EVENT_TYPE_INITIALIZED:
		LOGd("initialized");
		break;
	}

	switch (evt->event_type)
	{
//		case RBC_MESH_EVENT_TYPE_CONFLICTING_VAL:
		case RBC_MESH_EVENT_TYPE_NEW_VAL:
		case RBC_MESH_EVENT_TYPE_UPDATE_VAL: {

            if (evt->value_handle > 2)
                break;

            //if (evt->data[0]) {
            LOGi("Got data ch: %i, val: %i, len: %d, orig_addr:", evt->value_handle, evt->data[0], evt->data_len);
//            BLEutil::printArray(evt->originator_address.addr, 6);
            MeshControl &meshControl = MeshControl::getInstance();
            meshControl.process(evt->value_handle, evt->data, evt->data_len);
            //}
            //led_config(evt->value_handle, evt->data[0]);
            break;
        }
        default:
            LOGi("Default: %i", evt->event_type);
            break;
	}
}
/**
* @brief RBC_MESH framework event handler. Defined in rbc_mesh.h. Handles
*   events coming from the mesh. Sets LEDs according to data
*
* @param[in] evt RBC event propagated from framework
*/
void rbc_mesh_event_handler(rbc_mesh_event_t* evt)
{
    TICK_PIN(28);
    switch (evt->event_type)
    {
        case RBC_MESH_EVENT_TYPE_CONFLICTING_VAL:   
        case RBC_MESH_EVENT_TYPE_NEW_VAL:
        case RBC_MESH_EVENT_TYPE_UPDATE_VAL:
        
            if (evt->value_handle > 2)
                break;
            
            led_config(evt->value_handle, evt->data[0]);
            break;
        case RBC_MESH_EVENT_TYPE_INITIALIZED:
            /* init BLE gateway softdevice application: */
            nrf_adv_conn_init();
            break;  
    }
}
Example #4
0
uint32_t tc_tx(mesh_packet_t* p_packet)
{
    TICK_PIN(PIN_MESH_TX);
    
    /* queue the packet for transmission */
    radio_event_t event;
    memset(&event, 0, sizeof(radio_event_t));
    event.start_time = 0;
    mesh_packet_ref_count_inc(p_packet); /* queue will have a reference until tx_cb */
    event.packet_ptr = (uint8_t*) p_packet;
    event.access_address = 0;
    event.channel = g_state.channel;
    event.callback.tx = tx_cb;
    event.event_type = RADIO_EVENT_TYPE_TX;
    if (!radio_order(&event))
    {
        mesh_packet_ref_count_dec(p_packet); /* queue couldn't hold the ref */
        return NRF_ERROR_NO_MEM;
    }
    
    return NRF_SUCCESS;
}
/** Allocate a new data entry. Will take the least recently updated entry if all are allocated.
  Returns the index of the resulting entry. */
static uint16_t data_entry_allocate(void)
{
    static uint16_t allocated = 0;
    TICK_PIN(7);

    for (uint32_t i = allocated; i < RBC_MESH_DATA_CACHE_ENTRIES; ++i)
    {
        if (m_data_cache[i].p_packet == NULL)
        {
            trickle_timer_reset(&m_data_cache[i].trickle, 0);
            allocated++;
            return i;
        }
    }

    /* no unused entries, take the least recently updated (and disregard persistent handles) */
    uint32_t handle_index = m_handle_cache_tail;
    while (m_handle_cache[handle_index].data_entry == DATA_CACHE_ENTRY_INVALID ||
           m_handle_cache[handle_index].persistent)
    {
        HANDLE_CACHE_ITERATE_BACK(handle_index);

        if (handle_index == HANDLE_CACHE_ENTRY_INVALID)
        {
            return DATA_CACHE_ENTRY_INVALID;
        }
    }

    uint32_t data_index = m_handle_cache[handle_index].data_entry;
    APP_ERROR_CHECK_BOOL(data_index < RBC_MESH_DATA_CACHE_ENTRIES);

    /* cleanup */
    m_handle_cache[handle_index].data_entry = DATA_CACHE_ENTRY_INVALID;

    data_entry_free(&m_data_cache[data_index]);
    trickle_timer_reset(&m_data_cache[data_index].trickle, 0);
    return data_index;
}
/**
* @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);
    }
}
Example #7
0
/**
* @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)
{
    g_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
    g_is_in_callback = true;
    static uint32_t requested_extend_time = 0;
    static uint32_t successful_extensions = 0;
    static uint64_t last_rtc_value = 0;
    //static uint8_t noise_val = 0x5F;
    SET_PIN(PIN_SYNC_TIME);

    static uint64_t time_now = 0;

    switch (sig)
    {
        case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START:
        {
            NVIC_ClearPendingIRQ(SWI0_IRQn);
            g_is_in_timeslot = true;

            event_fifo_flush();
            timer_init();
            SET_PIN(2);
            successful_extensions = 0;

            g_negotiate_timeslot_length = g_timeslot_length;

            g_timeslot_length = g_next_timeslot_length;

            g_timeslot_end_timer = 
                timer_order_cb_sync_exec(g_timeslot_length - TIMESLOT_END_SAFETY_MARGIN_US, 
                    end_timer_handler);


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

#if USE_SWI_FOR_PROCESSING
            NVIC_EnableIRQ(SWI0_IRQn);
            NVIC_SetPriority(SWI0_IRQn, 3);
#endif

            /* sample RTC timer for trickle timing */
            uint32_t rtc_time = NRF_RTC0->COUNTER;

            /*First time the offset should be added*/
            if(last_rtc_value == 0)
            {
                last_rtc_value = g_start_time_ref;
            }

            /* Calculate delta rtc time */
            uint64_t delta_rtc_time;
            if(last_rtc_value > rtc_time)
            {
                delta_rtc_time = 0xFFFFFF - last_rtc_value + rtc_time;
            }
            else
            {
                delta_rtc_time = rtc_time - last_rtc_value;
            }
            /* Store last rtc time */
            last_rtc_value = rtc_time;


            /* scale to become us */
            time_now += ((delta_rtc_time << 15) / 1000);

            transport_control_timeslot_begin(time_now);
            break;
        }
        case NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO:
            /* send to radio control module */
            TICK_PIN(PIN_RADIO_SIGNAL);
            radio_event_handler();
            break;

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

        case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED:
            g_timeslot_length += requested_extend_time;
            requested_extend_time = 0;
            ++successful_extensions;
            g_ret_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;

            timer_abort(g_timeslot_end_timer);

            g_timeslot_end_timer = 
                timer_order_cb_sync_exec(g_timeslot_length - TIMESLOT_END_SAFETY_MARGIN_US, 
                    end_timer_handler);

            TICK_PIN(1);
            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 */
                transport_control_step();
            }

            break;

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

        default:
            APP_ERROR_CHECK(NRF_ERROR_INVALID_STATE);
    }


    g_is_in_callback = false;
    if (g_ret_param.callback_action == NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND)
    {
        requested_extend_time = g_ret_param.params.extend.length_us;
    }
    else if (g_ret_param.callback_action == NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END)
    {
        CLEAR_PIN(2);
        g_is_in_timeslot = false;
        event_fifo_flush();
    }
    else
    {
        requested_extend_time = 0;
    }

    CLEAR_PIN(PIN_SYNC_TIME);
    return &g_ret_param;
}
uint32_t mesh_srv_packet_process(packet_t* packet)
{
    if (!is_initialized)
    {
        return NRF_ERROR_INVALID_STATE;
    }
    uint32_t error_code;
    
    uint8_t handle = packet->data[MESH_PACKET_HANDLE_OFFSET];
    uint16_t version = (packet->data[MESH_PACKET_VERSION_OFFSET] | 
                    (((uint16_t) packet->data[MESH_PACKET_VERSION_OFFSET + 1]) << 8));
    uint8_t* data = &packet->data[MESH_PACKET_DATA_OFFSET];
    uint16_t data_len = packet->length - MESH_PACKET_DATA_OFFSET;
    
    if (data_len > MAX_VALUE_LENGTH)
    {
        return NRF_ERROR_INVALID_LENGTH;
    }
    
    if (handle > g_mesh_service.value_count || handle == 0)
    {
        return NRF_ERROR_INVALID_ADDR;
    }
    
    
    mesh_char_metadata_t* ch_md = &g_mesh_service.char_metadata[handle - 1];
    
    bool uninitialized = !(ch_md->flags & (1 << MESH_MD_FLAGS_INITIALIZED_POS));
    
    if (uninitialized)
    {
        trickle_init(&ch_md->trickle);
    }
    
    if (ch_md->version_number != version)
    {
        trickle_rx_inconsistent(&ch_md->trickle);
    }
    
    /* new version */  
    uint16_t separation = (version >= ch_md->version_number)?
        (version - ch_md->version_number) : 
        (-(ch_md->version_number - MESH_VALUE_LOLLIPOP_LIMIT) + (version - MESH_VALUE_LOLLIPOP_LIMIT) - MESH_VALUE_LOLLIPOP_LIMIT);

    if ((ch_md->version_number < MESH_VALUE_LOLLIPOP_LIMIT && version >= ch_md->version_number) || 
        (ch_md->version_number >= MESH_VALUE_LOLLIPOP_LIMIT && separation < (UINT16_MAX - MESH_VALUE_LOLLIPOP_LIMIT)/2) || 
        uninitialized)
    {
        /* update value */
        mesh_srv_char_val_set(handle, data, data_len, false);
        ch_md->flags |= (1 << MESH_MD_FLAGS_INITIALIZED_POS);
        ch_md->flags &= ~(1 << MESH_MD_FLAGS_IS_ORIGIN_POS);
        ch_md->version_number = version;
        
        /* Manually set originator address */
        memcpy(&ch_md->last_sender_addr, &packet->sender, sizeof(ble_gap_addr_t));
        
        rbc_mesh_event_t update_evt;
        update_evt.event_type = ((uninitialized)? 
            RBC_MESH_EVENT_TYPE_NEW_VAL :
            RBC_MESH_EVENT_TYPE_UPDATE_VAL);
        update_evt.data_len = data_len;
        update_evt.value_handle = handle;
        
        update_evt.data = data;
        memcpy(&update_evt.originator_address, &packet->sender, sizeof(ble_gap_addr_t));
        
        rbc_mesh_event_handler(&update_evt);
#ifdef RBC_MESH_SERIAL
            mesh_aci_rbc_event_handler(&update_evt);
#endif
    }
    else if (version == ch_md->version_number)
    {
        /* check for conflicting data */
        uint16_t old_len = MAX_VALUE_LENGTH;
        
        error_code = mesh_srv_char_val_get(handle, NULL, &old_len, NULL);
        if (error_code != NRF_SUCCESS)
        {
            return error_code;
        }
        
        volatile bool conflicting = false;
        
        if (packet->rx_crc != ch_md->crc && 
            !(ch_md->flags & (1 << MESH_MD_FLAGS_IS_ORIGIN_POS)))
        {
            conflicting = true;
        }
        else if (old_len != data_len)
        {
            conflicting = true;
        }
        
        
        if (conflicting)
        {
            TICK_PIN(7);
            rbc_mesh_event_t conflicting_evt;
            
            conflicting_evt.event_type = RBC_MESH_EVENT_TYPE_CONFLICTING_VAL;
            
            conflicting_evt.data_len = data_len;
            conflicting_evt.value_handle = handle;
            
            conflicting_evt.data = data;
            memcpy(&conflicting_evt.originator_address, &packet->sender, sizeof(ble_gap_addr_t));
            
            trickle_rx_inconsistent(&ch_md->trickle);
            
            rbc_mesh_event_handler(&conflicting_evt);
#ifdef RBC_MESH_SERIAL
            mesh_aci_rbc_event_handler(&conflicting_evt);
#endif
        }
        else
        { 
            trickle_rx_consistent(&ch_md->trickle);
        }
        
    }
    
    
    ch_md->crc = packet->rx_crc;
    
    return NRF_SUCCESS;
}
/**
* @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;
}