static uint32_t mesh_gatt_cmd_rsp_push(mesh_gatt_evt_opcode_t opcode, mesh_gatt_result_t result) { mesh_gatt_evt_t rsp; rsp.opcode = MESH_GATT_EVT_OPCODE_CMD_RSP; rsp.param.cmd_rsp.opcode = opcode; rsp.param.cmd_rsp.result = result; return mesh_gatt_evt_push(&rsp); }
uint32_t send_notification(waiting_notification_t* notification) { uint32_t err_code; uint8_t* data = notification->data; uint8_t length = notification->length; uint8_t offset = notification->offset; rbc_mesh_value_handle_t handle = notification->handle; while (offset < length) { mesh_gatt_evt_t gatt_evt; uint8_t part_len = 16; if (offset == 0) { gatt_evt.opcode = MESH_GATT_EVT_OPCODE_DATA_MULTIPART_START; } else if (length - offset > part_len) { gatt_evt.opcode = MESH_GATT_EVT_OPCODE_DATA_MULTIPART_MID; } else { gatt_evt.opcode = MESH_GATT_EVT_OPCODE_DATA_MULTIPART_END; part_len = length - offset; } gatt_evt.param.data_update.handle = handle; gatt_evt.param.data_update.data_len = part_len; memcpy(gatt_evt.param.data_update.data, data + offset, part_len); err_code = mesh_gatt_evt_push(&gatt_evt); if (err_code == BLE_ERROR_NO_TX_BUFFERS) { // LOGe("out of tx buffers"); // notifactionsPending = true; notification->offset = offset; return BLE_ERROR_NO_TX_BUFFERS; } else if (err_code != NRF_SUCCESS) { // LOGe("err_code: %d", err_code); return err_code; } offset += part_len; } return NRF_SUCCESS; }
uint32_t mesh_gatt_value_set(rbc_mesh_value_handle_t handle, uint8_t* data, uint8_t length) { if (length > RBC_MESH_VALUE_MAX_LEN) { return NRF_ERROR_INVALID_LENGTH; } if (m_active_conn_handle != CONN_HANDLE_INVALID) { mesh_gatt_evt_t gatt_evt; gatt_evt.opcode = MESH_GATT_EVT_OPCODE_DATA; gatt_evt.param.data_update.handle = handle; gatt_evt.param.data_update.data_len = length; memcpy(gatt_evt.param.data_update.data, data, length); return mesh_gatt_evt_push(&gatt_evt); } else { return BLE_ERROR_INVALID_CONN_HANDLE; } }
void mesh_gatt_sd_ble_event_handle(ble_evt_t* p_ble_evt) { switch (p_ble_evt->header.evt_id) { case BLE_GATTS_EVT_WRITE: { if (p_ble_evt->evt.gatts_evt.params.write.handle == m_mesh_service.ble_val_char_handles.value_handle) { mesh_gatt_evt_t* p_gatt_evt = (mesh_gatt_evt_t*) p_ble_evt->evt.gatts_evt.params.write.data; switch ((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode) { case MESH_GATT_EVT_OPCODE_DATA: { if (p_gatt_evt->param.data_update.handle == RBC_MESH_INVALID_HANDLE) { mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_INVALID_HANDLE); break; } vh_data_status_t vh_data_status = vh_local_update( p_gatt_evt->param.data_update.handle, p_gatt_evt->param.data_update.data, p_gatt_evt->param.data_update.data_len); rbc_mesh_event_t mesh_evt; mesh_evt.data = p_gatt_evt->param.data_update.data; mesh_evt.data_len = p_gatt_evt->param.data_update.data_len; mesh_evt.value_handle = p_gatt_evt->param.data_update.handle; mesh_evt.version_delta = 1; bool send_event = true; switch (vh_data_status) { case VH_DATA_STATUS_CONFLICTING: mesh_evt.event_type = RBC_MESH_EVENT_TYPE_CONFLICTING_VAL; break; case VH_DATA_STATUS_NEW: mesh_evt.event_type = RBC_MESH_EVENT_TYPE_NEW_VAL; break; case VH_DATA_STATUS_UPDATED: mesh_evt.event_type = RBC_MESH_EVENT_TYPE_UPDATE_VAL; break; default: mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_BUSY); send_event = false; } if (send_event) { APP_ERROR_CHECK(rbc_mesh_event_push(&mesh_evt)); mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_SUCCESS); } } break; case MESH_GATT_EVT_OPCODE_FLAG_SET: switch ((mesh_gatt_evt_flag_t) p_gatt_evt->param.flag_update.flag) { case MESH_GATT_EVT_FLAG_PERSISTENT: if (vh_value_persistence_set( p_gatt_evt->param.flag_update.handle, !!(p_gatt_evt->param.flag_update.value)) != NRF_SUCCESS) { mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_INVALID_HANDLE); break; } mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_SUCCESS); break; case MESH_GATT_EVT_FLAG_DO_TX: if (p_gatt_evt->param.flag_update.value) { if (vh_value_enable( p_gatt_evt->param.flag_update.handle) != NRF_SUCCESS) { mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_INVALID_HANDLE); break; } mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_SUCCESS); } else { if (vh_value_disable( p_gatt_evt->param.flag_update.handle) != NRF_SUCCESS) { mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_INVALID_HANDLE); break; } mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_SUCCESS); } break; default: mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_UNKNOWN_FLAG); } break; case MESH_GATT_EVT_OPCODE_FLAG_REQ: switch ((mesh_gatt_evt_flag_t) p_gatt_evt->param.flag_update.flag) { case MESH_GATT_EVT_FLAG_PERSISTENT: { if (p_gatt_evt->param.flag_update.handle == RBC_MESH_INVALID_HANDLE) { mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_INVALID_HANDLE); break; } bool is_persistent = false; if (vh_value_persistence_get( p_gatt_evt->param.flag_update.handle, &is_persistent) != NRF_SUCCESS) { mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_NOT_FOUND); break; } mesh_gatt_evt_t rsp_evt; rsp_evt.opcode = MESH_GATT_EVT_OPCODE_FLAG_RSP; rsp_evt.param.flag_update.handle = p_gatt_evt->param.flag_update.handle; rsp_evt.param.flag_update.flag = p_gatt_evt->param.flag_update.flag; rsp_evt.param.flag_update.value = (uint8_t) is_persistent; mesh_gatt_evt_push(&rsp_evt); } break; case MESH_GATT_EVT_FLAG_DO_TX: { bool is_enabled; if (vh_value_is_enabled( p_gatt_evt->param.flag_update.handle, &is_enabled) != NRF_SUCCESS) { mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_INVALID_HANDLE); break; } mesh_gatt_evt_t rsp_evt; rsp_evt.opcode = MESH_GATT_EVT_OPCODE_FLAG_RSP; rsp_evt.param.flag_update.handle = p_gatt_evt->param.flag_update.handle; rsp_evt.param.flag_update.flag = p_gatt_evt->param.flag_update.flag; rsp_evt.param.flag_update.value = (uint8_t) is_enabled; mesh_gatt_evt_push(&rsp_evt); } break; default: mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_UNKNOWN_FLAG); } break; default: mesh_gatt_cmd_rsp_push( (mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_INVALID_OPCODE); } } else if (p_ble_evt->evt.gatts_evt.params.write.handle == m_mesh_service.ble_md_char_handles.value_handle) { mesh_metadata_char_t* p_md = (mesh_metadata_char_t*) p_ble_evt->evt.gatts_evt.params.write.data; tc_radio_params_set(p_md->mesh_access_addr, p_md->mesh_channel); vh_min_interval_set(p_md->mesh_interval_min_ms); } else if (p_ble_evt->evt.gatts_evt.params.write.handle == m_mesh_service.ble_val_char_handles.cccd_handle) { m_mesh_service.notification_enabled = (p_ble_evt->evt.gatts_evt.params.write.data[0] != 0); } break; } case BLE_GAP_EVT_CONNECTED: { m_active_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; break; } case BLE_GAP_EVT_DISCONNECTED: { m_active_conn_handle = CONN_HANDLE_INVALID; // clear notification buffer on disconnect notifactionsPending = false; nb_clear(); break; } case BLE_EVT_TX_COMPLETE: { if (notifactionsPending) { resume_notifications(); } break; } } }
void mesh_gatt_sd_ble_event_handle(ble_evt_t* p_ble_evt) { if (p_ble_evt->header.evt_id == BLE_GATTS_EVT_WRITE) { if (p_ble_evt->evt.gatts_evt.params.write.handle == m_mesh_service.ble_val_char_handles.value_handle) { mesh_gatt_evt_t* p_gatt_evt = (mesh_gatt_evt_t*) p_ble_evt->evt.gatts_evt.params.write.data; switch ((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode) { case MESH_GATT_EVT_OPCODE_DATA: { if (p_gatt_evt->param.data_update.handle == RBC_MESH_INVALID_HANDLE) { mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_INVALID_HANDLE); break; } uint32_t error_code = vh_local_update( p_gatt_evt->param.data_update.handle, p_gatt_evt->param.data_update.data, p_gatt_evt->param.data_update.data_len); if (error_code == NRF_SUCCESS) { rbc_mesh_event_t mesh_evt; mesh_evt.type = RBC_MESH_EVENT_TYPE_UPDATE_VAL; mesh_evt.params.rx.p_data = p_gatt_evt->param.data_update.data; mesh_evt.params.rx.data_len = p_gatt_evt->param.data_update.data_len; mesh_evt.params.rx.value_handle = p_gatt_evt->param.data_update.handle; mesh_evt.params.rx.version_delta = 1; mesh_evt.params.rx.timestamp_us = timer_now(); if (rbc_mesh_event_push(&mesh_evt) != NRF_SUCCESS) { mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_BUSY); } else { mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_SUCCESS); } } else { mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_BUSY); } } break; case MESH_GATT_EVT_OPCODE_FLAG_SET: switch ((mesh_gatt_evt_flag_t) p_gatt_evt->param.flag_update.flag) { case MESH_GATT_EVT_FLAG_PERSISTENT: if (vh_value_persistence_set(p_gatt_evt->param.flag_update.handle, !!(p_gatt_evt->param.flag_update.value)) != NRF_SUCCESS) { mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_INVALID_HANDLE); break; } mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_SUCCESS); break; case MESH_GATT_EVT_FLAG_DO_TX: if (p_gatt_evt->param.flag_update.value) { if (vh_value_enable(p_gatt_evt->param.flag_update.handle) != NRF_SUCCESS) { mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_INVALID_HANDLE); break; } mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_SUCCESS); } else { if (vh_value_disable(p_gatt_evt->param.flag_update.handle) != NRF_SUCCESS) { mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_INVALID_HANDLE); break; } mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_SUCCESS); } break; default: mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_UNKNOWN_FLAG); } break; case MESH_GATT_EVT_OPCODE_FLAG_REQ: switch ((mesh_gatt_evt_flag_t) p_gatt_evt->param.flag_update.flag) { case MESH_GATT_EVT_FLAG_PERSISTENT: { if (p_gatt_evt->param.flag_update.handle == RBC_MESH_INVALID_HANDLE) { mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_INVALID_HANDLE); break; } bool is_persistent = false; if (vh_value_persistence_get(p_gatt_evt->param.flag_update.handle, &is_persistent) != NRF_SUCCESS) { mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_NOT_FOUND); break; } mesh_gatt_evt_t rsp_evt; rsp_evt.opcode = MESH_GATT_EVT_OPCODE_FLAG_RSP; rsp_evt.param.flag_update.handle = p_gatt_evt->param.flag_update.handle; rsp_evt.param.flag_update.flag = p_gatt_evt->param.flag_update.flag; rsp_evt.param.flag_update.value = (uint8_t) is_persistent; mesh_gatt_evt_push(&rsp_evt); } break; case MESH_GATT_EVT_FLAG_DO_TX: { bool is_enabled; if (vh_value_is_enabled(p_gatt_evt->param.flag_update.handle, &is_enabled) != NRF_SUCCESS) { mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_INVALID_HANDLE); break; } mesh_gatt_evt_t rsp_evt; rsp_evt.opcode = MESH_GATT_EVT_OPCODE_FLAG_RSP; rsp_evt.param.flag_update.handle = p_gatt_evt->param.flag_update.handle; rsp_evt.param.flag_update.flag = p_gatt_evt->param.flag_update.flag; rsp_evt.param.flag_update.value = (uint8_t) is_enabled; mesh_gatt_evt_push(&rsp_evt); } break; default: mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_UNKNOWN_FLAG); } break; default: mesh_gatt_cmd_rsp_push((mesh_gatt_evt_opcode_t) p_gatt_evt->opcode, MESH_GATT_RESULT_ERROR_INVALID_OPCODE); } } else if (p_ble_evt->evt.gatts_evt.params.write.handle == m_mesh_service.ble_md_char_handles.value_handle) { mesh_metadata_char_t* p_md = (mesh_metadata_char_t*) p_ble_evt->evt.gatts_evt.params.write.data; tc_radio_params_set(p_md->mesh_access_addr, p_md->mesh_channel); vh_min_interval_set(p_md->mesh_interval_min_ms); } else if (p_ble_evt->evt.gatts_evt.params.write.handle == m_mesh_service.ble_val_char_handles.cccd_handle) { m_mesh_service.notification_enabled = (p_ble_evt->evt.gatts_evt.params.write.data[0] != 0); } } else if (p_ble_evt->header.evt_id == BLE_GAP_EVT_CONNECTED) { m_active_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; } else if (p_ble_evt->header.evt_id == BLE_GAP_EVT_DISCONNECTED) { m_active_conn_handle = CONN_HANDLE_INVALID; } }