uint32_t handle_storage_rx_inconsistent(uint16_t handle, uint32_t timestamp) { if (handle == RBC_MESH_INVALID_HANDLE) { return NRF_ERROR_INVALID_ADDR; } uint16_t handle_index = handle_entry_get(handle, true); if (handle_index == HANDLE_CACHE_ENTRY_INVALID) { return NRF_ERROR_NOT_FOUND; } uint16_t data_index = m_handle_cache[handle_index].data_entry; if (data_index == DATA_CACHE_ENTRY_INVALID) { return NRF_ERROR_NOT_FOUND; } trickle_rx_inconsistent(&m_data_cache[data_index].trickle, timestamp); return NRF_SUCCESS; }
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; }
uint32_t mesh_srv_char_val_set(uint8_t index, uint8_t* data, uint16_t len, bool update_sender) { if (!is_initialized) { return NRF_ERROR_INVALID_STATE; } if (index > g_mesh_service.value_count || index == 0) { return NRF_ERROR_INVALID_ADDR; } if (len > MAX_VALUE_LENGTH) { return NRF_ERROR_INVALID_LENGTH; } uint32_t error_code = 0; mesh_char_metadata_t* ch_md = &g_mesh_service.char_metadata[index - 1]; /* this is now a new version of this data, signal to the rest of the mesh */ ++ch_md->version_number; bool first_time = (ch_md->flags & (1 << MESH_MD_FLAGS_USED_POS)) == 0; if (first_time) { ch_md->flags |= (1 << MESH_MD_FLAGS_INITIALIZED_POS) | (1 << MESH_MD_FLAGS_USED_POS); trickle_init(&ch_md->trickle); } else { trickle_rx_inconsistent(&ch_md->trickle); } if (update_sender || first_time) { ble_gap_addr_t my_addr; sd_ble_gap_address_get(&my_addr); memcpy(&ch_md->last_sender_addr, &my_addr, sizeof(ble_gap_addr_t)); ch_md->flags |= (1 << MESH_MD_FLAGS_IS_ORIGIN_POS); } /* notify the connected central node, if any */ if (g_active_conn_handle != CONN_HANDLE_INVALID) { ble_gatts_hvx_params_t notify_params; notify_params.handle = ch_md->char_value_handle; notify_params.offset = 0; notify_params.p_data = data; notify_params.p_len = &len; notify_params.type = BLE_GATT_HVX_NOTIFICATION; error_code = sd_ble_gatts_hvx(g_active_conn_handle, ¬ify_params); if (error_code != NRF_SUCCESS) { if (error_code == BLE_ERROR_INVALID_CONN_HANDLE) { g_active_conn_handle = CONN_HANDLE_INVALID; } else if (error_code == BLE_GATTS_EVT_SYS_ATTR_MISSING) { sd_ble_gatts_sys_attr_set(g_active_conn_handle, NULL, 0); } else { return NRF_ERROR_INTERNAL; } } } else { error_code = sd_ble_gatts_value_set( ch_md->char_value_handle, 0, &len, data); if (error_code != NRF_SUCCESS) { return NRF_ERROR_INTERNAL; } } return NRF_SUCCESS; }