uint32_t ble_bps_measurement_send(ble_bps_t * p_bps, ble_bps_meas_t * p_bps_meas) { uint32_t err_code; // Send value if connected if (p_bps->conn_handle != BLE_CONN_HANDLE_INVALID) { uint8_t encoded_bps_meas[MAX_BPM_LEN]; uint16_t len; uint16_t hvx_len; ble_gatts_hvx_params_t hvx_params; len = bps_measurement_encode(p_bps, p_bps_meas, encoded_bps_meas); hvx_len = len; memset(&hvx_params, 0, sizeof(hvx_params)); hvx_params.handle = p_bps->meas_handles.value_handle; hvx_params.type = BLE_GATT_HVX_INDICATION; hvx_params.offset = 0; hvx_params.p_len = &hvx_len; hvx_params.p_data = encoded_bps_meas; err_code = sd_ble_gatts_hvx(p_bps->conn_handle, &hvx_params); if ((err_code == NRF_SUCCESS) && (hvx_len != len)) { err_code = NRF_ERROR_DATA_SIZE; } } else { err_code = NRF_ERROR_INVALID_STATE; } return err_code; }
uint32_t ble_hrs_heart_rate_measurement_send(ble_hrs_t * p_hrs, uint16_t heart_rate) { uint32_t err_code; // Send value if connected and notifying if (p_hrs->conn_handle != BLE_CONN_HANDLE_INVALID) { uint8_t encoded_hrm[MAX_HRM_LEN]; uint16_t len; uint16_t hvx_len; ble_gatts_hvx_params_t hvx_params; len = hrm_encode(p_hrs, heart_rate, encoded_hrm); hvx_len = len; memset(&hvx_params, 0, sizeof(hvx_params)); hvx_params.handle = p_hrs->hrm_handles.value_handle; hvx_params.type = BLE_GATT_HVX_NOTIFICATION; hvx_params.offset = 0; hvx_params.p_len = &hvx_len; hvx_params.p_data = encoded_hrm; err_code = sd_ble_gatts_hvx(p_hrs->conn_handle, &hvx_params); if ((err_code == NRF_SUCCESS) && (hvx_len != len)) { err_code = NRF_ERROR_DATA_SIZE; } } else { err_code = NRF_ERROR_INVALID_STATE; } return err_code; }
uint32_t ble_dfu_bytes_rcvd_report(ble_dfu_t * p_dfu, uint32_t num_of_firmware_bytes_rcvd) { if (p_dfu == NULL) { return NRF_ERROR_NULL; } if ((p_dfu->conn_handle == BLE_CONN_HANDLE_INVALID) || !m_is_dfu_service_initialized) { return NRF_ERROR_INVALID_STATE; } ble_gatts_hvx_params_t hvx_params; uint16_t index = 0; // Encode the Op Code. m_notif_buffer[index++] = OP_CODE_RESPONSE; // Encode the Reqest Op Code. m_notif_buffer[index++] = OP_CODE_IMAGE_SIZE_REQ; // Encode the Response Value. m_notif_buffer[index++] = (uint8_t)BLE_DFU_RESP_VAL_SUCCESS; index += uint32_encode(num_of_firmware_bytes_rcvd, &m_notif_buffer[index]); memset(&hvx_params, 0, sizeof(hvx_params)); hvx_params.handle = p_dfu->dfu_ctrl_pt_handles.value_handle; hvx_params.type = BLE_GATT_HVX_NOTIFICATION; hvx_params.offset = 0; hvx_params.p_len = &index; hvx_params.p_data = m_notif_buffer; return sd_ble_gatts_hvx(p_dfu->conn_handle, &hvx_params); }
uint32_t sendDataPHYSENS(ble_pss_t * p_pss) { uint32_t err_code = NRF_SUCCESS; uint16_t len = (SENSOR_ROW_SIZE); uint8_t data[SENSOR_ROW_SIZE] = {0}; uint8_t memory[6] = {0}; // 3 datas of 6 bytes each uint8_t iter, iter_data; uint16_t new_remember = 0; uint16_t add = 0; uint16_t skip = g_index_skip; if ((p_pss->conn_handle != BLE_CONN_HANDLE_INVALID) && p_pss->is_notification_supported) { ble_gatts_hvx_params_t hvx_params; memset(&hvx_params, 0, sizeof(hvx_params)); hvx_params.handle = p_pss->phy_sen_level_handles.value_handle; hvx_params.type = BLE_GATT_HVX_NOTIFICATION; hvx_params.p_len = &len; switch (ble_mode) { case BLE_STICK_MODE: if (g_state == 2) { data[0] = STICK_MOMENT; data[1] = g_battery_int; data[2] = 1; for (iter=0; iter<10; iter++) { data[3+iter] = g_data_send[iter]; } g_state = 3; } else if (g_state == 3) { data[0] = STICK_MOMENT; data[1] = g_battery_int; data[2] = 2; for (iter=10; iter<22; iter++) { data[3+iter-10] = g_data_send[iter]; } g_state = 0; //RESTART } else { //TODO, put code from settings //Send settings /*data[0] = STICK_MOMENT; data[1] = g_battery_int; for (iter=0; iter<14; iter++) { data[2+iter] = g_data_send[iter]; }*/ data[0] = SETTINGS_READ; data[1] = g_battery_int; for (iter=0; iter<18; iter++) { data[2+iter] = g_settings[iter]; } } break; case BLE_SETTINGS_MODE: data[0] = SETTINGS_READ; data[1] = g_battery_int; for (iter=0; iter<18; iter++) { data[2+iter] = g_settings[iter]; } break; case BLE_CALIB_AXIS_MODE: data[0] = CALIB_OUTPUT; data[1] = g_battery_int; for (iter=0; iter<8; iter++) { data[2+iter] = g_calib_axis[iter]; } for (iter=8; iter<18; iter++) { data[2+iter] = 0; } break; case BLE_FREE_MODE: case BLE_OTHER_MODE: case BLE_SHOT_MODE: // TODO mode magement // Draft mode and real mode mangement // Indexing later switch(g_state) { case 0: case 1: data[0] = DATA_DRAFT; data[1] = g_battery_int; for (iter_data = 0; iter_data<3; iter_data++) { for (iter=0; iter<6; iter++) { data[2+iter + (iter_data*6)] = g_data_send[iter + (iter_data*6)]; } } break; case 2: data[0] = DATA_START; data[1] = g_battery_int; // 300 for 30, but 32 indexes system. // Take ratio (300 / (30/32)) //TODO if (g_remember < 320) { g_remember = BR25S_CIRCULAR_BUFFER - (320-g_remember); } else { g_remember -= 320; } g_shot_br25s_index = 0; break; case 3: data[0] = DATA; data[1] = g_battery_int; break; case 4: data[0] = DATA_END; data[1] = g_battery_int; break; } if (g_state >= 2) { new_remember = g_remember; for (iter_data=0; iter_data<3; iter_data++) { getDatas(memory, 6, new_remember); new_remember += g_skip[g_index_skip % 5]; add += g_skip[g_index_skip % 5]; g_index_skip++; if (new_remember >= BR25S_CIRCULAR_BUFFER) { new_remember = 0; } for (iter=0; iter<6; iter++) { data[2+iter + (iter_data*6)] = memory[iter]; } } } break; } hvx_params.p_data = data; err_code = sd_ble_gatts_hvx(p_pss->conn_handle, &hvx_params); if (ble_mode == BLE_STICK_MODE && g_state <= 1) { return NRF_ERROR_INVALID_STATE; // Send only one data } else if (ble_mode == BLE_STICK_MODE) { return err_code; } // Add only if complete data if (ble_mode == BLE_SHOT_MODE && err_code == NRF_SUCCESS && g_state >= 2) { if (g_state == 2) { g_state = 3; } else if (g_state == 4) { g_state = 0; g_real_index = 0; //Flush everything g_valid = 1; g_index_skip = 0; } g_remember = new_remember; g_shot_br25s_index += add; if (g_remember >= BR25S_CIRCULAR_BUFFER) g_remember == 0; if (g_state == 3) { // 18 left + 2 extra(Nothing) if (g_shot_br25s_index >= BR25S_CIRCULAR_BUFFER - 20) { // This sample and the last one g_state = 4; } } } else if (g_state >= 2) { // Reinit some value g_index_skip = skip; } } else { err_code = NRF_ERROR_INVALID_STATE; } if ((ble_mode == BLE_SHOT_MODE || ble_mode == BLE_FREE_MODE) && g_state <= 1) { return NRF_ERROR_INVALID_STATE; // Send only one data } return err_code; }
/**@brief Function for sending response from Specific Operation Control Point. * * @param[in] p_cgms Service instance. * @param[in] p_racp_val RACP value to be sent. */ static void racp_send(nrf_ble_cgms_t * p_cgms, ble_racp_value_t * p_racp_val) { uint32_t err_code; uint8_t encoded_resp[25]; uint8_t len; uint16_t hvx_len; ble_gatts_hvx_params_t hvx_params; if ( (p_cgms->cgms_com_state != STATE_RACP_RESPONSE_PENDING) && (p_cgms->racp_data.racp_proc_records_reported_since_txcomplete > 0) ) { p_cgms->cgms_com_state = STATE_RACP_RESPONSE_PENDING; return; } // Send indication len = ble_racp_encode(p_racp_val, encoded_resp); hvx_len = len; memset(&hvx_params, 0, sizeof(hvx_params)); hvx_params.handle = p_cgms->char_handles.racp.value_handle; hvx_params.type = BLE_GATT_HVX_INDICATION; hvx_params.offset = 0; hvx_params.p_len = &hvx_len; hvx_params.p_data = encoded_resp; err_code = sd_ble_gatts_hvx(p_cgms->conn_handle, &hvx_params); // Error handling if ((err_code == NRF_SUCCESS) && (hvx_len != len)) { err_code = NRF_ERROR_DATA_SIZE; } switch (err_code) { case NRF_SUCCESS: // Wait for HVC event p_cgms->cgms_com_state = STATE_RACP_RESPONSE_IND_VERIF; break; case BLE_ERROR_NO_TX_PACKETS: // Wait for TX_COMPLETE event to retry transmission p_cgms->cgms_com_state = STATE_RACP_RESPONSE_PENDING; break; case NRF_ERROR_INVALID_STATE: // Make sure state machine returns to the default state p_cgms->cgms_com_state = STATE_NO_COMM; break; default: // Report error to application if (p_cgms->error_handler != NULL) { p_cgms->error_handler(err_code); } // Make sure state machine returns to the default state p_cgms->cgms_com_state = STATE_NO_COMM; break; } }
/**@brief Function for handling the Disconnect event. * * @param[in] p_si7021 si7021 Service structure. * @param[in] hum Relative Humidity Raw 16-Bit. * @param[in] temp Temperature Raw 16-Bit. */ uint32_t ble_si7021_sensor_update(ble_si7021_t * p_si7021, uint16_t hum, uint16_t temp) { uint8_t encoded_data[BLE_si7021_VALUE_MAX_LEN]; //uint8_t len; if (p_si7021 == NULL) { return NRF_ERROR_NULL; } uint32_t err_code = NRF_SUCCESS; ble_gatts_value_t gatts_value; if ((hum != p_si7021->last_humraw && hum != 0) || (temp != p_si7021->last_tempraw && temp != 0)) { NRF_LOG_DEBUG("ble_si7021_sensor_update %x,%x\n\r",hum,temp); uint16_encode(hum,&encoded_data[0]); uint16_encode(temp,&encoded_data[2]); // Initialize value struct. memset(&gatts_value, 0, sizeof(gatts_value)); gatts_value.len = BLE_si7021_VALUE_MAX_LEN; gatts_value.offset = 0; gatts_value.p_value = &encoded_data[0]; NRF_LOG_DEBUG("sd_ble_gatts_value_set %x,%x\n\r",p_si7021->conn_handle,p_si7021->value_char_handles.value_handle); // Update database. Set the value of a given attribute err_code = sd_ble_gatts_value_set(p_si7021->conn_handle, p_si7021->value_char_handles.value_handle, &gatts_value); NRF_LOG_DEBUG("sd_ble_gatts_value_set =%d\n\r",err_code); if (err_code == NRF_SUCCESS) { // save new temperature value. p_si7021->last_humraw = hum; p_si7021->last_tempraw = temp; } else { return err_code; } // Send value if connected and notifying. if (p_si7021->conn_handle != BLE_CONN_HANDLE_INVALID) { ble_gatts_hvx_params_t hvx_params; memset(&hvx_params, 0, sizeof(hvx_params)); hvx_params.handle = p_si7021->value_char_handles.value_handle; hvx_params.type = BLE_GATT_HVX_NOTIFICATION; hvx_params.offset = gatts_value.offset; hvx_params.p_len = &gatts_value.len; hvx_params.p_data = gatts_value.p_value; NRF_LOG_DEBUG("sd_ble_gatts_hvx\n\r"); // Notify or Indicate an attribute value err_code = sd_ble_gatts_hvx(p_si7021->conn_handle, &hvx_params); NRF_LOG_DEBUG("sd_ble_gatts_hvx =%d\n\r",err_code); } else { err_code = NRF_ERROR_INVALID_STATE; } } return err_code; }
ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly) { ble_error_t returnValue = BLE_ERROR_NONE; ble_gatts_value_t value = { /* .len = */ len, /* .offset = */ 0, /* .p_value = */ const_cast<uint8_t *>(buffer), }; if (localOnly) { /* Only update locally regardless of notify/indicate */ ASSERT_INT( ERROR_NONE, sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), BLE_ERROR_PARAM_OUT_OF_RANGE ); return BLE_ERROR_NONE; } int characteristicIndex = resolveValueHandleToCharIndex(attributeHandle); if ((characteristicIndex != -1) && (p_characteristics[characteristicIndex]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) { /* HVX update for the characteristic value */ ble_gatts_hvx_params_t hvx_params; hvx_params.handle = attributeHandle; hvx_params.type = (p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INDICATION; hvx_params.offset = 0; hvx_params.p_data = const_cast<uint8_t *>(buffer); hvx_params.p_len = &len; if (connectionHandle == BLE_CONN_HANDLE_INVALID) { /* use the default connection handle if the caller hasn't specified a valid connectionHandle. */ nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap(); connectionHandle = gap.getConnectionHandle(); } bool updatesEnabled = false; if (connectionHandle != BLE_CONN_HANDLE_INVALID) { ble_error_t err = areUpdatesEnabled(connectionHandle, attributeHandle, &updatesEnabled); // FIXME: The softdevice allocates and populates CCCD when the client // interract with them. Checking for updates may return an out of // range error in such case. if(err && err != BLE_ERROR_PARAM_OUT_OF_RANGE) { return err; } } bool updates_permitted = false; ble_gap_conn_sec_t connection_security; uint32_t err = sd_ble_gap_conn_sec_get(connectionHandle, &connection_security); if (!err && (connection_security.sec_mode.sm == 1) && (connection_security.sec_mode.lv >= p_characteristics[characteristicIndex]->getUpdateSecurityRequirement().value())) { updates_permitted = true; } if (updatesEnabled && updates_permitted) { error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params); if (error != ERROR_NONE) { switch (error) { case ERROR_BLE_NO_TX_BUFFERS: /* Notifications consume application buffers. The return value can be used for resending notifications. */ case ERROR_BUSY: returnValue = BLE_STACK_BUSY; break; case ERROR_INVALID_STATE: case ERROR_BLEGATTS_SYS_ATTR_MISSING: returnValue = BLE_ERROR_INVALID_STATE; break; default : ASSERT_INT( ERROR_NONE, sd_ble_gatts_value_set(connectionHandle, attributeHandle, &value), BLE_ERROR_PARAM_OUT_OF_RANGE ); /* Notifications consume application buffers. The return value can * be used for resending notifications. */ returnValue = BLE_STACK_BUSY; break; } } } else { returnValue = set_attribute_value(connectionHandle, attributeHandle, &value); } } else { returnValue = set_attribute_value(connectionHandle, attributeHandle, &value); } return returnValue; }
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; }
/**@brief Function for decoding a command packet with RPC_SD_BLE_GATTS_HVX opcode. * * This function will decode the command, call the BLE Stack API, and also send command response * to the peer through the the transport layer. * * @param[in] p_command The encoded structure that needs to be decoded and passed on * to the BLE Stack API. * @param[in] command_len The length of the encoded command read from transport layer. * * @retval NRF_SUCCESS If the decoding of the command was successful, the SoftDevice * API was called, and the command response was sent to peer, * otherwise an error code. * @retval NRF_ERROR_INVALID_LENGTH If the content length of the packet is not conforming to the * codec specification. */ static uint32_t gatts_hvx_handle(uint8_t * const p_command, uint32_t command_len) { uint32_t err_code; uint16_t conn_handle; ble_gatts_hvx_params_t hvx_params; uint8_t resp_data[sizeof(uint16_t)]; uint16_t hvx_params_data_length = 0; uint32_t index = 0; ble_gatts_hvx_params_t * p_hvx_params = NULL; conn_handle = uint16_decode(&p_command[index]); index += sizeof(uint16_t); RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_HVX); if (p_command[index++] == RPC_BLE_FIELD_PRESENT) { hvx_params.handle = uint16_decode(&p_command[index]); index += sizeof(uint16_t); hvx_params.type = p_command[index++]; hvx_params.offset = uint16_decode(&p_command[index]); index += sizeof(uint16_t); RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_HVX); if (p_command[index++] == RPC_BLE_FIELD_PRESENT) { hvx_params_data_length = uint16_decode(&p_command[index]); index += sizeof(uint16_t); hvx_params.p_len = &hvx_params_data_length; } else { hvx_params.p_len = NULL; } RPC_DECODER_LENGTH_CHECK(command_len, (index + hvx_params_data_length), SD_BLE_GATTS_HVX); if (p_command[index++] == RPC_BLE_FIELD_PRESENT) { hvx_params.p_data = &(p_command[index]); } else { hvx_params.p_data = NULL; } p_hvx_params = &hvx_params; } RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_HVX); err_code = sd_ble_gatts_hvx(conn_handle, p_hvx_params); if (err_code == NRF_SUCCESS) { if (p_hvx_params != NULL && p_hvx_params->p_len != NULL) { UNUSED_VARIABLE(uint16_encode(*(p_hvx_params->p_len), resp_data)); return ble_rpc_cmd_resp_data_send(SD_BLE_GATTS_HVX, err_code, resp_data, sizeof(resp_data)); } } return ble_rpc_cmd_resp_send(SD_BLE_GATTS_HVX, err_code); }