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