ble_error_t nRF51GattServer::updateValue(uint16_t charHandle, uint8_t buffer[], uint16_t len, bool localOnly) { if (localOnly) { /* Only update locally regardless of notify/indicate */ ASSERT_INT( ERROR_NONE, sd_ble_gatts_value_set(nrfCharacteristicHandles[charHandle].value_handle, 0, &len, buffer), BLE_ERROR_PARAM_OUT_OF_RANGE ); } if ((p_characteristics[charHandle]->properties & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)) && (m_connectionHandle != BLE_CONN_HANDLE_INVALID) ) { /* HVX update for the characteristic value */ ble_gatts_hvx_params_t hvx_params; hvx_params.handle = nrfCharacteristicHandles[charHandle].value_handle; hvx_params.type = (p_characteristics[charHandle]->properties & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) ? BLE_GATT_HVX_NOTIFICATION : BLE_GATT_HVX_INDICATION; hvx_params.offset = 0; hvx_params.p_data = buffer; hvx_params.p_len = &len; error_t error = (error_t) sd_ble_gatts_hvx(m_connectionHandle, &hvx_params); /* ERROR_INVALID_STATE, ERROR_BUSY, ERROR_GATTS_SYS_ATTR_MISSING and ERROR_NO_TX_BUFFERS the ATT table has been updated. */ if ( (error != ERROR_NONE ) && (error != ERROR_INVALID_STATE) && (error != ERROR_BLE_NO_TX_BUFFERS ) && (error != ERROR_BUSY ) && (error != ERROR_BLEGATTS_SYS_ATTR_MISSING ) ) { ASSERT_INT( ERROR_NONE, sd_ble_gatts_value_set(nrfCharacteristicHandles[charHandle].value_handle, 0, &len, buffer), BLE_ERROR_PARAM_OUT_OF_RANGE ); } } else { ASSERT_INT( ERROR_NONE, sd_ble_gatts_value_set(nrfCharacteristicHandles[charHandle].value_handle, 0, &len, buffer), BLE_ERROR_PARAM_OUT_OF_RANGE ); } return BLE_ERROR_NONE; }
/**@brief Function for handling the Connect event. * * @param[in] p_hids HID Service structure. * @param[in] p_ble_evt Event received from the BLE stack. */ static void on_connect(ble_hids_t * p_hids, ble_evt_t * p_ble_evt) { uint32_t err_code; uint8_t default_protocol_mode; ble_gatts_value_t gatts_value; p_hids->conn_handle = p_ble_evt->evt.gap_evt.conn_handle; if (p_hids->protocol_mode_handles.value_handle) { // Set Protocol Mode characteristic value to default value default_protocol_mode = DEFAULT_PROTOCOL_MODE; // Initialize value struct. memset(&gatts_value, 0, sizeof(gatts_value)); gatts_value.len = sizeof(uint8_t); gatts_value.offset = 0; gatts_value.p_value = &default_protocol_mode; err_code = sd_ble_gatts_value_set(p_hids->conn_handle, p_hids->protocol_mode_handles.value_handle, &gatts_value); if ((err_code != NRF_SUCCESS) && (p_hids->error_handler != NULL)) { p_hids->error_handler(err_code); } } }
uint32_t sd_ble_gatts_value_set(uint16_t handle, uint16_t offset, uint16_t* const p_len, uint8_t const * const p_value) { ble_gatts_value_t val; val.len = *p_len; val.offset = offset; val.p_value = (uint8_t*)p_value; sd_ble_gatts_value_set(BLE_CONN_HANDLE_INVALID, handle, &val); }
uint32_t ble_hrs_body_sensor_location_set(ble_hrs_t * p_hrs, uint8_t body_sensor_location) { #if 0 uint16_t len = sizeof(uint8_t); return sd_ble_gatts_value_set(p_hrs->bsl_handles.value_handle, 0, &len, &body_sensor_location); #else return 0; #endif }
uint32_t ble_bas_battery_level_update(ble_bas_t * p_bas, uint8_t battery_level) { if (p_bas == NULL) { return NRF_ERROR_NULL; } uint32_t err_code = NRF_SUCCESS; ble_gatts_value_t gatts_value; if (battery_level != p_bas->battery_level_last) { // Initialize value struct. memset(&gatts_value, 0, sizeof(gatts_value)); gatts_value.len = sizeof(uint8_t); gatts_value.offset = 0; gatts_value.p_value = &battery_level; // Update database. err_code = sd_ble_gatts_value_set(p_bas->conn_handle, p_bas->battery_level_handles.value_handle, &gatts_value); if (err_code == NRF_SUCCESS) { // Save new battery value. p_bas->battery_level_last = battery_level; } else { return err_code; } // Send value if connected and notifying. if ((p_bas->conn_handle != BLE_CONN_HANDLE_INVALID) && p_bas->is_notification_supported) { ble_gatts_hvx_params_t hvx_params; memset(&hvx_params, 0, sizeof(hvx_params)); hvx_params.handle = p_bas->battery_level_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; err_code = sd_ble_gatts_hvx(p_bas->conn_handle, &hvx_params); } else { err_code = NRF_ERROR_INVALID_STATE; } } return err_code; }
uint32_t ble_tps_tx_power_level_set(ble_tps_t * p_tps, int8_t tx_power_level) { uint16_t len = sizeof(int8_t); // Update database return sd_ble_gatts_value_set(p_tps->tx_power_level_handles.value_handle, 0, &len, (uint8_t*)&tx_power_level); }
/**@brief Function for decoding a command packet with RPC_SD_BLE_GATTS_VALUE_SET 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_value_set_handle(uint8_t const * const p_command, uint32_t command_len) { uint16_t handle; uint16_t offset; uint32_t err_code; uint32_t index = 0; uint16_t length = 0; uint16_t * p_length = NULL; const uint8_t * p_value = NULL; handle = uint16_decode(&p_command[index]); index += sizeof(uint16_t); RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_VALUE_SET); offset = uint16_decode(&p_command[index]); index += sizeof(uint16_t); RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_VALUE_SET); // Value length present. if (p_command[index++] == RPC_BLE_FIELD_PRESENT) { length = uint16_decode(&p_command[index]); p_length = &length; index += sizeof(uint16_t); } RPC_DECODER_LENGTH_CHECK(command_len, (index + length), SD_BLE_GATTS_VALUE_SET); // Value present. if (p_command[index++] == RPC_BLE_FIELD_PRESENT) { p_value = &p_command[index]; } RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GATTS_VALUE_SET); err_code = sd_ble_gatts_value_set(handle, offset, p_length, p_value); if (err_code == NRF_SUCCESS) { uint8_t resp_data[sizeof(uint16_t)]; UNUSED_VARIABLE(uint16_encode(*p_length, resp_data)); return ble_rpc_cmd_resp_data_send(SD_BLE_GATTS_VALUE_SET, err_code, resp_data, sizeof(resp_data)); } else { return ble_rpc_cmd_resp_send(SD_BLE_GATTS_VALUE_SET, err_code); } }
bool nRF51822::updateCharacteristicValue(BLECharacteristic& characteristic) { bool success = true; for (int i = 0; i < this->_numLocalCharacteristics; i++) { struct localCharacteristicInfo* localCharacteristicInfo = &this->_localCharacteristicInfo[i]; if (localCharacteristicInfo->characteristic == &characteristic) { if (&characteristic == this->_broadcastCharacteristic) { this->broadcastCharacteristic(characteristic); } uint16_t valueLength = characteristic.valueLength(); sd_ble_gatts_value_set(localCharacteristicInfo->handles.value_handle, 0, &valueLength, characteristic.value()); ble_gatts_hvx_params_t hvxParams; memset(&hvxParams, 0, sizeof(hvxParams)); hvxParams.handle = localCharacteristicInfo->handles.value_handle; hvxParams.offset = 0; hvxParams.p_data = NULL; hvxParams.p_len = &valueLength; if (localCharacteristicInfo->notifySubscribed) { if (this->_txBufferCount > 0) { this->_txBufferCount--; hvxParams.type = BLE_GATT_HVX_NOTIFICATION; sd_ble_gatts_hvx(this->_connectionHandle, &hvxParams); } else { success = false; } } if (localCharacteristicInfo->indicateSubscribed) { if (this->_txBufferCount > 0) { this->_txBufferCount--; hvxParams.type = BLE_GATT_HVX_INDICATION; sd_ble_gatts_hvx(this->_connectionHandle, &hvxParams); } else { success = false; } } } } return success; }
uint32_t ble_hrs_body_sensor_location_set(ble_hrs_t * p_hrs, uint8_t body_sensor_location) { ble_gatts_value_t gatts_value; // Initialize value struct. memset(&gatts_value, 0, sizeof(gatts_value)); gatts_value.len = sizeof(uint8_t); gatts_value.offset = 0; gatts_value.p_value = &body_sensor_location; return sd_ble_gatts_value_set(p_hrs->conn_handle, p_hrs->bsl_handles.value_handle, &gatts_value); }
ret_code_t nrf_ble_cgms_update_status(nrf_ble_cgms_t * p_cgms, nrf_ble_cgm_status_t * p_status) { uint8_t encoded_status[NRF_BLE_CGMS_STATUS_LEN]; ble_gatts_value_t status_val; memset(&status_val, 0, sizeof(status_val)); p_cgms->sensor_status = *p_status; status_val.len = encode_status(encoded_status, p_cgms); status_val.p_value = encoded_status; status_val.offset = 0; return (sd_ble_gatts_value_set(p_cgms->conn_handle, p_cgms->char_handles.status.value_handle, &status_val)); }
/**@brief Function for setting the Record. */ uint32_t ble_display_service_record_set(ble_display_service_t * p_display_service, ble_display_service_record_t * p_record) { ble_gatts_value_t gatts_value; uint8_t encoded_value[MAX_RECORD_LEN]; // Initialize value struct. memset(&gatts_value, 0, sizeof(gatts_value)); gatts_value.len = record_encode(p_record, encoded_value); gatts_value.offset = 0; gatts_value.p_value = encoded_value; return sd_ble_gatts_value_set(p_display_service->conn_handle, p_display_service->record_handles.value_handle, &gatts_value); }
/**@brief Function for updating the Ambient Service service values. * * @param[in] p_amb Ambient Service Service structure. * @param[in] values Buffer with new values. * @param[in] number_of_bytes Size of the buffer. * @param[in] type Type of the value. * * @return NRF_SUCCESS on success, otherwise an error code. * @return BLE_ERROR_GATTS_SYS_ATTR_MISSING if notifications disabled */ uint32_t ble_ambient_sensor_update(ble_ambient_t * p_amb, uint8_t * values, uint8_t number_of_bytes, ble_ambient_sensor_type type){ uint32_t err_code = NRF_SUCCESS; int i, t; for(i = 0; i < AMB_NUMBER_OF_SENSORS; i++){ if(type_to_handle[i].type == type){ uint16_t len = (uint16_t)number_of_bytes; // Save new axis value for(t = 0; t < number_of_bytes; t++) type_to_handle[i].value[t] = values[t]; // Update database err_code = sd_ble_gatts_value_set((*(type_to_handle[i].handle)).value_handle, 0, &len, values); if (err_code != NRF_SUCCESS) return err_code; // Send value if connected and notifying if ((p_amb->conn_handle != BLE_CONN_HANDLE_INVALID) && p_amb->is_notification_supported){ ble_gatts_hvx_params_t hvx_params; memset(&hvx_params, 0, sizeof(hvx_params)); hvx_params.handle = (*(type_to_handle[i].handle)).value_handle; hvx_params.type = BLE_GATT_HVX_NOTIFICATION; hvx_params.offset = 0; hvx_params.p_len = &len; hvx_params.p_data = values; err_code = sd_ble_gatts_hvx(p_amb->conn_handle, &hvx_params); } else err_code = NRF_ERROR_INVALID_STATE; //no-one is connected! return err_code; } } //type doesn't exist err_code = NRF_ERROR_NOT_FOUND; return err_code; }
ret_code_t nrf_ble_cgms_srt_set(nrf_ble_cgms_t * p_cgms, uint16_t run_time) { ble_gatts_value_t srt_val; uint8_t encoded_session_run_time[NRF_BLE_CGMS_SRT_LEN]; uint8_t gatts_value_set_len = 0; gatts_value_set_len = uint16_encode(run_time, encoded_session_run_time); // (p_sst, encoded_start_session_time); memset(&srt_val, 0, sizeof(ble_gatts_value_t)); srt_val.len = gatts_value_set_len; srt_val.p_value = encoded_session_run_time; srt_val.offset = 0; return (sd_ble_gatts_value_set(p_cgms->conn_handle, p_cgms->char_handles.srt.value_handle, &srt_val)); }
uint32_t ble_tps_tx_power_level_set(ble_tps_t * p_tps, int8_t tx_power_level) { ble_gatts_value_t gatts_value; // Initialize value struct. memset(&gatts_value, 0, sizeof(gatts_value)); gatts_value.len = sizeof(uint8_t); gatts_value.offset = 0; gatts_value.p_value = (uint8_t*)&tx_power_level; // Update database return sd_ble_gatts_value_set(p_tps->conn_handle, p_tps->tx_power_level_handles.value_handle, &gatts_value); }
uint32_t ble_bas_battery_level_update(ble_bas_t * p_bas, uint8_t battery_level) { uint32_t err_code = NRF_SUCCESS; if (battery_level != p_bas->battery_level_last) { uint16_t len = sizeof(uint8_t); // Save new battery value p_bas->battery_level_last = battery_level; // Update database SERV_LOG("[SERV][bas]: sd_ble_gatts_value_set\r\n"); err_code = sd_ble_gatts_value_set(p_bas->battery_level_handles.value_handle, 0, &len, &battery_level); if (err_code != NRF_SUCCESS) { return err_code; } // Send value if connected and notifying if ((p_bas->conn_handle != BLE_CONN_HANDLE_INVALID) && p_bas->is_notification_supported) { ble_gatts_hvx_params_t hvx_params; memset(&hvx_params, 0, sizeof(hvx_params)); len = sizeof(uint8_t); hvx_params.handle = p_bas->battery_level_handles.value_handle; hvx_params.type = BLE_GATT_HVX_NOTIFICATION; hvx_params.offset = 0; hvx_params.p_len = &len; hvx_params.p_data = &battery_level; SERV_LOG("[SERV][bas]: sd_ble_gatts_hvx(BLE_GATT_HVX_NOTIFICATION, %d)\r\n", battery_level); err_code = sd_ble_gatts_hvx(p_bas->conn_handle, &hvx_params); } else { err_code = NRF_ERROR_INVALID_STATE; } } return err_code; }
uint32_t ble_acc_accel_level_update(ble_acc_t * p_acc, uint16_t accel_level) { uint32_t err_code = NRF_SUCCESS; if (accel_level != p_acc->accel_level_last) { uint16_t len = sizeof(uint16_t); // Save new accel value p_acc->accel_level_last = accel_level; // Update database err_code = sd_ble_gatts_value_set(p_acc->accel_level_handles.value_handle, 0, &len, (uint8_t*)&accel_level); if (err_code != NRF_SUCCESS) { return err_code; } // Send value if connected and notifying if ((p_acc->conn_handle != BLE_CONN_HANDLE_INVALID) && p_acc->is_notification_supported) { ble_gatts_hvx_params_t hvx_params; memset(&hvx_params, 0, sizeof(hvx_params)); len = sizeof(uint8_t); hvx_params.handle = p_acc->accel_level_handles.value_handle; hvx_params.type = BLE_GATT_HVX_NOTIFICATION; hvx_params.offset = 0; hvx_params.p_len = &len; hvx_params.p_data = (uint8_t*)&accel_level; err_code = sd_ble_gatts_hvx(p_acc->conn_handle, &hvx_params); } else { err_code = NRF_ERROR_INVALID_STATE; } } return err_code; }
ret_code_t cgms_sst_set(nrf_ble_cgms_t * p_cgms, ble_cgms_sst_t * p_sst) { uint16_t conn_handle; uint16_t value_handle; ble_gatts_value_t sst_val; uint8_t encoded_start_session_time[NRF_BLE_CGMS_SST_LEN]; uint8_t gatts_value_set_len = 0; gatts_value_set_len = sst_encode(p_sst, encoded_start_session_time); conn_handle = p_cgms->conn_handle; value_handle = p_cgms->char_handles.sst.value_handle; memset(&sst_val, 0, sizeof(ble_gatts_value_t)); sst_val.len = gatts_value_set_len; sst_val.p_value = encoded_start_session_time; sst_val.offset = 0; return (sd_ble_gatts_value_set(conn_handle, value_handle, &sst_val)); }
/** NOT used at this moment, OTP update routine **/ uint32_t ble_otp_update(ble_dp_t * p_dp, uint8_t dp_otp) { uint32_t err_code = NRF_SUCCESS; if (dp_otp != p_dp->otp_last) { uint16_t len = sizeof(uint8_t); // Save new OTP value p_dp->otp_last = dp_otp; // Update database err_code = sd_ble_gatts_value_set(p_dp->dp_otp_handles.value_handle, 0, &len, &dp_otp); } return err_code; }
/**@brief Function for handling the Connect event. * * @param[in] p_hids HID Service structure. * @param[in] p_ble_evt Event received from the BLE stack. */ static void on_connect(ble_hids_t * p_hids, ble_evt_t * p_ble_evt) { uint32_t err_code; uint16_t len; uint8_t default_protocol_mode; p_hids->conn_handle = p_ble_evt->evt.gap_evt.conn_handle; // Set Protocol Mode characteristic value to default value len = sizeof(uint8_t); default_protocol_mode = DEFAULT_PROTOCOL_MODE; err_code = sd_ble_gatts_value_set(p_hids->protocol_mode_handles.value_handle, 0, &len, &default_protocol_mode); if ((err_code != NRF_SUCCESS) && (p_hids->error_handler != NULL)) { p_hids->error_handler(err_code); } }
//--------------------------------------------------------------------------------- uint32_t ble_wechat_target_update(ble_step_t * p_step, uint8_t* target) { if (p_step == NULL) { return NRF_ERROR_NULL; } uint32_t err_code = NRF_SUCCESS; ble_gatts_value_t gatts_value; { // Initialize value struct. memset(&gatts_value, 0, sizeof(gatts_value)); gatts_value.len =4;// sizeof(uint8_t); gatts_value.offset = 0; gatts_value.p_value =target;// &step_count; // Update database. err_code = sd_ble_gatts_value_set(p_step->conn_handle, target_handles.value_handle, &gatts_value); // Send value if connected and notifying. { ble_gatts_hvx_params_t hvx_params; memset(&hvx_params, 0, sizeof(hvx_params)); hvx_params.handle = target_handles.value_handle; hvx_params.type = BLE_GATT_HVX_INDICATION; hvx_params.offset = gatts_value.offset; hvx_params.p_len = &gatts_value.len; hvx_params.p_data = gatts_value.p_value; err_code = sd_ble_gatts_hvx(p_step->conn_handle, &hvx_params); } } //SEGGER_RTT_printf(0,"0x%x,0x%x\r\n",target[0],target[1]); 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; }
void nRF51822::begin(unsigned char advertisementDataType, unsigned char advertisementDataLength, const unsigned char* advertisementData, unsigned char scanDataType, unsigned char scanDataLength, const unsigned char* scanData, BLELocalAttribute** localAttributes, unsigned char numLocalAttributes, BLERemoteAttribute** remoteAttributes, unsigned char numRemoteAttributes) { #ifdef __RFduino__ sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_SYNTH_250_PPM, NULL); #else sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, NULL); // sd_nvic_EnableIRQ(SWI2_IRQn); #endif #ifdef NRF51_S130 ble_enable_params_t enableParams = { .gatts_enable_params = { .service_changed = true } }; sd_ble_enable(&enableParams); #endif #ifdef NRF_51822_DEBUG ble_version_t version; sd_ble_version_get(&version); Serial.print(F("version = ")); Serial.print(version.version_number); Serial.print(F(" ")); Serial.print(version.company_id); Serial.print(F(" ")); Serial.print(version.subversion_number); Serial.println(); #endif ble_gap_conn_params_t gap_conn_params; gap_conn_params.min_conn_interval = 40; // in 1.25ms units gap_conn_params.max_conn_interval = 80; // in 1.25ms unit gap_conn_params.slave_latency = 0; gap_conn_params.conn_sup_timeout = 4000 / 10; // in 10ms unit sd_ble_gap_ppcp_set(&gap_conn_params); sd_ble_gap_tx_power_set(0); unsigned char srData[31]; unsigned char srDataLen = 0; this->_advDataLen = 0; // flags this->_advData[this->_advDataLen + 0] = 2; this->_advData[this->_advDataLen + 1] = 0x01; this->_advData[this->_advDataLen + 2] = 0x06; this->_advDataLen += 3; if (advertisementDataType && advertisementDataLength && advertisementData) { this->_advData[this->_advDataLen + 0] = advertisementDataLength + 1; this->_advData[this->_advDataLen + 1] = advertisementDataType; this->_advDataLen += 2; memcpy(&this->_advData[this->_advDataLen], advertisementData, advertisementDataLength); this->_advDataLen += advertisementDataLength; } if (scanDataType && scanDataLength && scanData) { srData[0] = scanDataLength + 1; srData[1] = scanDataType; memcpy(&srData[2], scanData, scanDataLength); srDataLen = 2 + scanDataLength; } sd_ble_gap_adv_data_set(this->_advData, this->_advDataLen, srData, srDataLen); sd_ble_gap_appearance_set(0); for (int i = 0; i < numLocalAttributes; i++) { BLELocalAttribute *localAttribute = localAttributes[i]; if (localAttribute->type() == BLETypeCharacteristic) { this->_numLocalCharacteristics++; } } this->_numLocalCharacteristics -= 3; // 0x2a00, 0x2a01, 0x2a05 this->_localCharacteristicInfo = (struct localCharacteristicInfo*)malloc(sizeof(struct localCharacteristicInfo) * this->_numLocalCharacteristics); unsigned char localCharacteristicIndex = 0; uint16_t handle = 0; BLEService *lastService = NULL; for (int i = 0; i < numLocalAttributes; i++) { BLELocalAttribute *localAttribute = localAttributes[i]; BLEUuid uuid = BLEUuid(localAttribute->uuid()); const unsigned char* uuidData = uuid.data(); unsigned char value[255]; ble_uuid_t nordicUUID; if (uuid.length() == 2) { nordicUUID.uuid = (uuidData[1] << 8) | uuidData[0]; nordicUUID.type = BLE_UUID_TYPE_BLE; } else { unsigned char uuidDataTemp[16]; memcpy(&uuidDataTemp, uuidData, sizeof(uuidDataTemp)); nordicUUID.uuid = (uuidData[13] << 8) | uuidData[12]; uuidDataTemp[13] = 0; uuidDataTemp[12] = 0; sd_ble_uuid_vs_add((ble_uuid128_t*)&uuidDataTemp, &nordicUUID.type); } if (localAttribute->type() == BLETypeService) { BLEService *service = (BLEService *)localAttribute; if (strcmp(service->uuid(), "1800") == 0 || strcmp(service->uuid(), "1801") == 0) { continue; // skip } sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &nordicUUID, &handle); lastService = service; } else if (localAttribute->type() == BLETypeCharacteristic) { BLECharacteristic *characteristic = (BLECharacteristic *)localAttribute; if (strcmp(characteristic->uuid(), "2a00") == 0) { ble_gap_conn_sec_mode_t secMode; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&secMode); // no security is needed sd_ble_gap_device_name_set(&secMode, characteristic->value(), characteristic->valueLength()); } else if (strcmp(characteristic->uuid(), "2a01") == 0) { const uint16_t *appearance = (const uint16_t*)characteristic->value(); sd_ble_gap_appearance_set(*appearance); } else if (strcmp(characteristic->uuid(), "2a05") == 0) { // do nothing } else { uint8_t properties = characteristic->properties() & 0xfe; uint16_t valueLength = characteristic->valueLength(); this->_localCharacteristicInfo[localCharacteristicIndex].characteristic = characteristic; this->_localCharacteristicInfo[localCharacteristicIndex].notifySubscribed = false; this->_localCharacteristicInfo[localCharacteristicIndex].indicateSubscribed = false; this->_localCharacteristicInfo[localCharacteristicIndex].service = lastService; ble_gatts_char_md_t characteristicMetaData; ble_gatts_attr_md_t clientCharacteristicConfigurationMetaData; ble_gatts_attr_t characteristicValueAttribute; ble_gatts_attr_md_t characteristicValueAttributeMetaData; memset(&characteristicMetaData, 0, sizeof(characteristicMetaData)); memcpy(&characteristicMetaData.char_props, &properties, 1); characteristicMetaData.p_char_user_desc = NULL; characteristicMetaData.p_char_pf = NULL; characteristicMetaData.p_user_desc_md = NULL; characteristicMetaData.p_cccd_md = NULL; characteristicMetaData.p_sccd_md = NULL; if (properties & (BLENotify | BLEIndicate)) { memset(&clientCharacteristicConfigurationMetaData, 0, sizeof(clientCharacteristicConfigurationMetaData)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&clientCharacteristicConfigurationMetaData.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&clientCharacteristicConfigurationMetaData.write_perm); clientCharacteristicConfigurationMetaData.vloc = BLE_GATTS_VLOC_STACK; characteristicMetaData.p_cccd_md = &clientCharacteristicConfigurationMetaData; } memset(&characteristicValueAttributeMetaData, 0, sizeof(characteristicValueAttributeMetaData)); if (properties & (BLERead | BLENotify | BLEIndicate)) { if (this->_bondStore) { BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&characteristicValueAttributeMetaData.read_perm); } else { BLE_GAP_CONN_SEC_MODE_SET_OPEN(&characteristicValueAttributeMetaData.read_perm); } } if (properties & (BLEWriteWithoutResponse | BLEWrite)) { if (this->_bondStore) { BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&characteristicValueAttributeMetaData.write_perm); } else { BLE_GAP_CONN_SEC_MODE_SET_OPEN(&characteristicValueAttributeMetaData.write_perm); } } characteristicValueAttributeMetaData.vloc = BLE_GATTS_VLOC_STACK; characteristicValueAttributeMetaData.rd_auth = 0; characteristicValueAttributeMetaData.wr_auth = 0; characteristicValueAttributeMetaData.vlen = !characteristic->fixedLength(); for (int j = (i + 1); j < numLocalAttributes; j++) { localAttribute = localAttributes[j]; if (localAttribute->type() != BLETypeDescriptor) { break; } BLEDescriptor *descriptor = (BLEDescriptor *)localAttribute; if (strcmp(descriptor->uuid(), "2901") == 0) { characteristicMetaData.p_char_user_desc = (uint8_t*)descriptor->value(); characteristicMetaData.char_user_desc_max_size = descriptor->valueLength(); characteristicMetaData.char_user_desc_size = descriptor->valueLength(); } else if (strcmp(descriptor->uuid(), "2904") == 0) { characteristicMetaData.p_char_pf = (ble_gatts_char_pf_t *)descriptor->value(); } } memset(&characteristicValueAttribute, 0, sizeof(characteristicValueAttribute)); characteristicValueAttribute.p_uuid = &nordicUUID; characteristicValueAttribute.p_attr_md = &characteristicValueAttributeMetaData; characteristicValueAttribute.init_len = valueLength; characteristicValueAttribute.init_offs = 0; characteristicValueAttribute.max_len = characteristic->valueSize(); characteristicValueAttribute.p_value = NULL; sd_ble_gatts_characteristic_add(BLE_GATT_HANDLE_INVALID, &characteristicMetaData, &characteristicValueAttribute, &this->_localCharacteristicInfo[localCharacteristicIndex].handles); if (valueLength) { for (int j = 0; j < valueLength; j++) { value[j] = (*characteristic)[j]; } sd_ble_gatts_value_set(this->_localCharacteristicInfo[localCharacteristicIndex].handles.value_handle, 0, &valueLength, value); } localCharacteristicIndex++; } } else if (localAttribute->type() == BLETypeDescriptor) { BLEDescriptor *descriptor = (BLEDescriptor *)localAttribute; if (strcmp(descriptor->uuid(), "2901") == 0 || strcmp(descriptor->uuid(), "2902") == 0 || strcmp(descriptor->uuid(), "2903") == 0 || strcmp(descriptor->uuid(), "2904") == 0) { continue; // skip } uint16_t valueLength = descriptor->valueLength(); ble_gatts_attr_t descriptorAttribute; ble_gatts_attr_md_t descriptorMetaData; memset(&descriptorAttribute, 0, sizeof(descriptorAttribute)); memset(&descriptorMetaData, 0, sizeof(descriptorMetaData)); descriptorMetaData.vloc = BLE_GATTS_VLOC_STACK; descriptorMetaData.vlen = (valueLength == descriptor->valueLength()) ? 0 : 1; if (this->_bondStore) { BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&descriptorMetaData.read_perm); } else { BLE_GAP_CONN_SEC_MODE_SET_OPEN(&descriptorMetaData.read_perm); } descriptorAttribute.p_uuid = &nordicUUID; descriptorAttribute.p_attr_md = &descriptorMetaData; descriptorAttribute.init_len = valueLength; descriptorAttribute.max_len = descriptor->valueLength(); descriptorAttribute.p_value = NULL; sd_ble_gatts_descriptor_add(BLE_GATT_HANDLE_INVALID, &descriptorAttribute, &handle); if (valueLength) { for (int j = 0; j < valueLength; j++) { value[j] = (*descriptor)[j]; } sd_ble_gatts_value_set(handle, 0, &valueLength, value); } } } if ( numRemoteAttributes > 0) { numRemoteAttributes -= 2; // 0x1801, 0x2a05 } for (int i = 0; i < numRemoteAttributes; i++) { BLERemoteAttribute *remoteAttribute = remoteAttributes[i]; if (remoteAttribute->type() == BLETypeService) { this->_numRemoteServices++; } else if (remoteAttribute->type() == BLETypeCharacteristic) { this->_numRemoteCharacteristics++; } } this->_remoteServiceInfo = (struct remoteServiceInfo*)malloc(sizeof(struct remoteServiceInfo) * this->_numRemoteServices); this->_remoteCharacteristicInfo = (struct remoteCharacteristicInfo*)malloc(sizeof(struct remoteCharacteristicInfo) * this->_numRemoteCharacteristics); BLERemoteService *lastRemoteService = NULL; unsigned char remoteServiceIndex = 0; unsigned char remoteCharacteristicIndex = 0; for (int i = 0; i < numRemoteAttributes; i++) { BLERemoteAttribute *remoteAttribute = remoteAttributes[i]; BLEUuid uuid = BLEUuid(remoteAttribute->uuid()); const unsigned char* uuidData = uuid.data(); ble_uuid_t nordicUUID; if (uuid.length() == 2) { nordicUUID.uuid = (uuidData[1] << 8) | uuidData[0]; nordicUUID.type = BLE_UUID_TYPE_BLE; } else { unsigned char uuidDataTemp[16]; memcpy(&uuidDataTemp, uuidData, sizeof(uuidDataTemp)); nordicUUID.uuid = (uuidData[13] << 8) | uuidData[12]; uuidDataTemp[13] = 0; uuidDataTemp[12] = 0; sd_ble_uuid_vs_add((ble_uuid128_t*)&uuidDataTemp, &nordicUUID.type); } if (remoteAttribute->type() == BLETypeService) { this->_remoteServiceInfo[remoteServiceIndex].service = lastRemoteService = (BLERemoteService *)remoteAttribute; this->_remoteServiceInfo[remoteServiceIndex].uuid = nordicUUID; memset(&this->_remoteServiceInfo[remoteServiceIndex].handlesRange, 0, sizeof(this->_remoteServiceInfo[remoteServiceIndex].handlesRange)); remoteServiceIndex++; } else if (remoteAttribute->type() == BLETypeCharacteristic) { this->_remoteCharacteristicInfo[remoteCharacteristicIndex].characteristic = (BLERemoteCharacteristic *)remoteAttribute; this->_remoteCharacteristicInfo[remoteCharacteristicIndex].service = lastRemoteService; this->_remoteCharacteristicInfo[remoteCharacteristicIndex].uuid = nordicUUID; memset(&this->_remoteCharacteristicInfo[remoteCharacteristicIndex].properties, 0, sizeof(this->_remoteCharacteristicInfo[remoteCharacteristicIndex].properties)); this->_remoteCharacteristicInfo[remoteCharacteristicIndex].valueHandle = 0; remoteCharacteristicIndex++; } } if (this->_bondStore && this->_bondStore->hasData()) { #ifdef NRF_51822_DEBUG Serial.println(F("Restoring bond data")); #endif #ifdef NRF51_S130 this->_bondStore->getData(this->_bondData, 0, sizeof(this->_bondData)); #else this->_bondStore->getData(this->_authStatusBuffer, 0, sizeof(this->_authStatusBuffer)); #endif } this->startAdvertising(); #ifdef __RFduino__ RFduinoBLE_enabled = 1; #endif }
uint32_t conn_mw_ble_gatts_value_set(uint8_t const * const p_rx_buf, uint32_t rx_buf_len, uint8_t * const p_tx_buf, uint32_t * const p_tx_buf_len) { SER_ASSERT_NOT_NULL(p_rx_buf); SER_ASSERT_NOT_NULL(p_tx_buf); SER_ASSERT_NOT_NULL(p_tx_buf_len); uint16_t conn_handle; uint16_t handle; uint8_t attr_val_table[BLE_GATTS_VAR_ATTR_LEN_MAX]; ble_gatts_value_t attr_val = { .len = sizeof (attr_val_table), .offset = 0, .p_value = attr_val_table }; ble_gatts_value_t * p_attr_val = &attr_val; uint32_t err_code = NRF_SUCCESS; uint32_t sd_err_code; err_code = ble_gatts_value_set_req_dec(p_rx_buf, rx_buf_len, &conn_handle, &handle, &p_attr_val); SER_ASSERT(err_code == NRF_SUCCESS, err_code); sd_err_code = sd_ble_gatts_value_set(conn_handle, handle, p_attr_val); err_code = ble_gatts_value_set_rsp_enc(sd_err_code, p_tx_buf, p_tx_buf_len, p_attr_val); SER_ASSERT(err_code == NRF_SUCCESS, err_code); return err_code; } uint32_t conn_mw_ble_gatts_value_get(uint8_t const * const p_rx_buf, uint32_t rx_buf_len, uint8_t * const p_tx_buf, uint32_t * const p_tx_buf_len) { SER_ASSERT_NOT_NULL(p_rx_buf); SER_ASSERT_NOT_NULL(p_tx_buf); SER_ASSERT_NOT_NULL(p_tx_buf_len); uint16_t conn_handle; uint16_t handle; uint8_t val[BLE_GATTS_VAR_ATTR_LEN_MAX]; ble_gatts_value_t attr_value; ble_gatts_value_t * p_attr_value = &attr_value; attr_value.p_value = val; uint32_t err_code = NRF_SUCCESS; uint32_t sd_err_code; err_code = ble_gatts_value_get_req_dec(p_rx_buf, rx_buf_len, &conn_handle, &handle, &p_attr_value); SER_ASSERT(err_code == NRF_SUCCESS, err_code); sd_err_code = sd_ble_gatts_value_get(conn_handle, handle, p_attr_value); err_code = ble_gatts_value_get_rsp_enc(sd_err_code, p_tx_buf, p_tx_buf_len, p_attr_value); SER_ASSERT(err_code == NRF_SUCCESS, err_code); return err_code; }
/**@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; }
/**@brief Handle a write event to the Speed and Cadence Control Point. * * @param[in] p_sc_ctrlpt SC Ctrlpt structure. * @param[in] p_evt_write WRITE event to be handled. */ static void on_ctrlpt_write(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_gatts_evt_write_t const * p_evt_write) { ble_sc_ctrlpt_val_t rcvd_ctrlpt = { BLE_SCPT_RESPONSE_CODE , 0, BLE_SENSOR_LOCATION_OTHER }; ble_sc_ctrlpt_rsp_t rsp; uint32_t err_code; ble_gatts_rw_authorize_reply_params_t auth_reply; ble_sc_ctrlpt_evt_t evt; auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE; auth_reply.params.write.offset = 0; auth_reply.params.write.len = 0; auth_reply.params.write.p_data = NULL; auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; auth_reply.params.write.update = 1; if (is_cccd_configured(p_sc_ctrlpt)) { if (p_sc_ctrlpt->procedure_status == BLE_SCPT_NO_PROC_IN_PROGRESS) { auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; } else { auth_reply.params.write.gatt_status = SC_CTRLPT_NACK_PROC_ALREADY_IN_PROGRESS; } } else { auth_reply.params.write.gatt_status = SC_CTRLPT_NACK_CCCD_IMPROPERLY_CONFIGURED; } err_code = sd_ble_gatts_rw_authorize_reply(p_sc_ctrlpt->conn_handle, &auth_reply); if (err_code != NRF_SUCCESS) { // Report error to application. if (p_sc_ctrlpt->error_handler != NULL) { p_sc_ctrlpt->error_handler(err_code); } } if (auth_reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS) { return; } p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING; rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED; err_code = sc_ctrlpt_decode(p_evt_write->data, p_evt_write->len, &rcvd_ctrlpt); if (err_code != NRF_SUCCESS) { rsp.opcode = rcvd_ctrlpt.opcode; rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED; } else { rsp.opcode = rcvd_ctrlpt.opcode; switch (rcvd_ctrlpt.opcode) { case BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS: if ((p_sc_ctrlpt->supported_functions & BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) == BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) { rsp.status = BLE_SCPT_SUCCESS; } else { rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED; } break; case BLE_SCPT_UPDATE_SENSOR_LOCATION: if ((p_sc_ctrlpt->supported_functions & BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) == BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) { if (is_location_supported(p_sc_ctrlpt, rcvd_ctrlpt.location)) { ble_gatts_value_t gatts_value; uint8_t rcvd_location = (uint8_t)rcvd_ctrlpt.location; rsp.status = BLE_SCPT_SUCCESS; // Initialize value struct. memset(&gatts_value, 0, sizeof(gatts_value)); gatts_value.len = sizeof(uint8_t); gatts_value.offset = 0; gatts_value.p_value = &rcvd_location; evt.evt_type = BLE_SC_CTRLPT_EVT_UPDATE_LOCATION; evt.params.update_location = rcvd_ctrlpt.location; if (p_sc_ctrlpt->evt_handler != NULL) { rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt); } if (rsp.status == BLE_SCPT_SUCCESS) { err_code = sd_ble_gatts_value_set(p_sc_ctrlpt->conn_handle, p_sc_ctrlpt->sensor_location_handle, &gatts_value); if (err_code != NRF_SUCCESS) { // Report error to application if (p_sc_ctrlpt->error_handler != NULL) { p_sc_ctrlpt->error_handler(err_code); } rsp.status = BLE_SCPT_OPERATION_FAILED; } } } else { rsp.status = BLE_SCPT_INVALID_PARAMETER; } } else { rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED; } break; case BLE_SCPT_SET_CUMULATIVE_VALUE: if ((p_sc_ctrlpt->supported_functions & BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED) == BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED) { rsp.status = BLE_SCPT_SUCCESS; evt.evt_type = BLE_SC_CTRLPT_EVT_SET_CUMUL_VALUE; evt.params.cumulative_value = rcvd_ctrlpt.cumulative_value; if (p_sc_ctrlpt->evt_handler != NULL) { rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt); } } else { rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED; } break; case BLE_SCPT_START_AUTOMATIC_CALIBRATION: if ((p_sc_ctrlpt->supported_functions & BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED) == BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED) { p_sc_ctrlpt->procedure_status = BLE_SCPT_AUTOMATIC_CALIB_IN_PROGRESS; evt.evt_type = BLE_SC_CTRLPT_EVT_START_CALIBRATION; if (p_sc_ctrlpt->evt_handler != NULL) { rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt); if (rsp.status != BLE_SCPT_SUCCESS) { // If the application returns an error, the response is to be sent // right away and the calibration is considered as not started. p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING; } } } else { rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED; } break; default: rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED; break; } } p_sc_ctrlpt->response.len = ctrlpt_rsp_encode(p_sc_ctrlpt, &rsp, p_sc_ctrlpt->response.encoded_ctrl_rsp); if (p_sc_ctrlpt->procedure_status == BLE_SCPT_INDICATION_PENDING) { sc_ctrlpt_resp_send(p_sc_ctrlpt); } }
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 updating the Ambient Service config values. * * @param[in] p_amb Ambient Service Service structure. * @param[in] sensor_configuration New sensor configuration. * * @return NRF_SUCCESS on success, otherwise an error code. */ uint32_t ble_ambient_config_update(ble_ambient_t * p_amb, uint8_t sensor_configuration, ble_ambient_sensor_type type){ //new data! #if TEMP_ENABLED || PR_ENABLED || HUM_ENABLED || LUM_ENABLED || HUMSOLO_ENABLED uint16_t len = 1; #endif uint32_t err_code = NRF_SUCCESS; switch(type){ #if TEMP_ENABLED case BLE_AMBIENT_TEMP: // Save new configuration value p_amb->temp_configuration = sensor_configuration; // Update database err_code = sd_ble_gatts_value_set(p_amb->temp_configuration_handles.value_handle, 0, &len, &sensor_configuration); break; #endif #if PR_ENABLED case BLE_AMBIENT_PR: // Save new configuration value p_amb->pr_configuration = sensor_configuration; // Update database err_code = sd_ble_gatts_value_set(p_amb->pr_configuration_handles.value_handle, 0, &len, &sensor_configuration); break; #endif #if HUM_ENABLED case BLE_AMBIENT_HUM: // Save new configuration value p_amb->hum_configuration = sensor_configuration; // Update database err_code = sd_ble_gatts_value_set(p_amb->hum_configuration_handles.value_handle, 0, &len, &sensor_configuration); break; #endif #if HUMSOLO_ENABLED case BLE_AMBIENT_HUMSOLO: // Save new configuration value p_amb->humsolo_configuration = sensor_configuration; // Update database err_code = sd_ble_gatts_value_set(p_amb->humsolo_configuration_handles.value_handle, 0, &len, &sensor_configuration); break; #endif #if LUM_ENABLED case BLE_AMBIENT_LUM: // Save new configuration value p_amb->lum_configuration = sensor_configuration; // Update database err_code = sd_ble_gatts_value_set(p_amb->lum_configuration_handles.value_handle, 0, &len, &sensor_configuration); break; #endif default: break; } return err_code; }
void nRF5xGattServer::hwCallback(const ble_evt_t *p_ble_evt) { GattAttribute::Handle_t handle_value; GattServerEvents::gattEvent_t eventType; const ble_gatts_evt_t *gattsEventP = &p_ble_evt->evt.gatts_evt; switch (p_ble_evt->header.evt_id) { case BLE_GATTS_EVT_WRITE: { /* There are 2 use case here: Values being updated & CCCD (indicate/notify) enabled */ /* 1.) Handle CCCD changes */ handle_value = gattsEventP->params.write.handle; int characteristicIndex = resolveCCCDHandleToCharIndex(handle_value); if ((characteristicIndex != -1) && (p_characteristics[characteristicIndex]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY))) { uint16_t cccd_value = (gattsEventP->params.write.data[1] << 8) | gattsEventP->params.write.data[0]; /* Little Endian but M0 may be mis-aligned */ if (((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) && (cccd_value & BLE_GATT_HVX_INDICATION)) || ((p_characteristics[characteristicIndex]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) && (cccd_value & BLE_GATT_HVX_NOTIFICATION))) { eventType = GattServerEvents::GATT_EVENT_UPDATES_ENABLED; } else { eventType = GattServerEvents::GATT_EVENT_UPDATES_DISABLED; } handleEvent(eventType, p_characteristics[characteristicIndex]->getValueHandle()); return; } /* 2.) Changes to the characteristic value will be handled with other events below */ eventType = GattServerEvents::GATT_EVENT_DATA_WRITTEN; } break; case BLE_GATTS_EVT_HVC: /* Indication confirmation received */ eventType = GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED; handle_value = gattsEventP->params.hvc.handle; break; #if NRF_SD_BLE_API_VERSION >= 4 // This event has been renamed in API V4+ case BLE_GATTS_EVT_HVN_TX_COMPLETE: { handleDataSentEvent(p_ble_evt->evt.gatts_evt.params.hvn_tx_complete.count); return; } #else case BLE_EVT_TX_COMPLETE: { handleDataSentEvent(p_ble_evt->evt.common_evt.params.tx_complete.count); return; } #endif case BLE_GATTS_EVT_SYS_ATTR_MISSING: sd_ble_gatts_sys_attr_set(gattsEventP->conn_handle, NULL, 0, 0); return; case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: switch (gattsEventP->params.authorize_request.type) { case BLE_GATTS_AUTHORIZE_TYPE_READ: eventType = GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ; handle_value = gattsEventP->params.authorize_request.request.read.handle; break; case BLE_GATTS_AUTHORIZE_TYPE_WRITE: eventType = GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ; handle_value = gattsEventP->params.authorize_request.request.write.handle; break; default: return; } break; case BLE_EVT_USER_MEM_REQUEST: { uint16_t conn_handle = p_ble_evt->evt.common_evt.conn_handle; // allocate a new long request for this connection // NOTE: we don't care about the result at this stage, // it is not possible to cancel the operation anyway. // If the request was not allocated then it will gracefully failled // at subsequent stages. allocateLongWriteRequest(conn_handle); sd_ble_user_mem_reply(conn_handle, NULL); return; } default: return; } int characteristicIndex = resolveValueHandleToCharIndex(handle_value); if (characteristicIndex == -1) { // filter out the case were the request is a long one, // and there is no attribute handle provided uint8_t write_op = gattsEventP->params.authorize_request.request.write.op; if (eventType != GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ || (write_op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW && write_op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)) { return; } } /* Find index (charHandle) in the pool */ switch (eventType) { case GattServerEvents::GATT_EVENT_DATA_WRITTEN: { GattWriteCallbackParams cbParams = { /* .connHandle = */ gattsEventP->conn_handle, /* .handle = */ handle_value, /* .writeOp = */ static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.write.op), /* .offset = */ gattsEventP->params.write.offset, /* .len = */ gattsEventP->params.write.len, /* .data = */ gattsEventP->params.write.data }; handleDataWrittenEvent(&cbParams); break; } case GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ: { uint16_t conn_handle = gattsEventP->conn_handle; const ble_gatts_evt_write_t& input_req = gattsEventP->params.authorize_request.request.write; const uint16_t max_size = getBiggestCharacteristicSize(); // this is a long write request, handle it here. switch (input_req.op) { case BLE_GATTS_OP_PREP_WRITE_REQ: { // verify that the request is not outside of the possible range if ((input_req.offset + input_req.len) > max_size) { sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_offset_reply); releaseLongWriteRequest(conn_handle); return; } // find the write request long_write_request_t* req = findLongWriteRequest(conn_handle); if (!req) { sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); return; } // initialize the first request by setting the offset if (req->length == 0) { req->attr_handle = input_req.handle; req->offset = input_req.offset; } else { // it should be the subsequent write if ((req->offset + req->length) != input_req.offset) { sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_offset_reply); releaseLongWriteRequest(conn_handle); return; } // it is not allowed to write multiple characteristic with the same request if (input_req.handle != req->attr_handle) { sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); releaseLongWriteRequest(conn_handle); return; } } // start the copy of what is in input memcpy(req->data + req->length, input_req.data, input_req.len); // update the lenght of the data written req->length = req->length + input_req.len; // success, signal it to the softdevice ble_gatts_rw_authorize_reply_params_t reply = { /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE, /* .params = */ { /* .write = */ { /* .gatt_status = */ BLE_GATT_STATUS_SUCCESS, /* .update = */ 1, /* .offset = */ input_req.offset, /* .len = */ input_req.len, /* .p_data = */ input_req.data } } }; sd_ble_gatts_rw_authorize_reply(conn_handle, &reply); } return; case BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL: { releaseLongWriteRequest(conn_handle); sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_succes_reply); } return; case BLE_GATTS_OP_EXEC_WRITE_REQ_NOW: { long_write_request_t* req = findLongWriteRequest(conn_handle); if (!req) { sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); return; } GattWriteAuthCallbackParams cbParams = { /* .connHandle = */ conn_handle, /* .handle = */ req->attr_handle, /* .offset = */ req->offset, /* .len = */ req->length, /* .data = */ req->data, /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member * set to AUTH_CALLBACK_REPLY_SUCCESS if the client * request is to proceed. */ }; uint16_t write_authorization = p_characteristics[characteristicIndex]->authorizeWrite(&cbParams); // the user code didn't provide the write authorization, // just leave here. if (write_authorization != AUTH_CALLBACK_REPLY_SUCCESS) { // report the status of the operation in any cases sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); releaseLongWriteRequest(conn_handle); return; } // FIXME can't use ::write here, this function doesn't take the offset into account ... ble_gatts_value_t value = { /* .len = */ req->length, /* .offset = */ req->offset, /* .p_value = */ req->data }; uint32_t update_err = sd_ble_gatts_value_set(conn_handle, req->attr_handle, &value); if (update_err) { sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_invalid_reply); releaseLongWriteRequest(conn_handle); return; } sd_ble_gatts_rw_authorize_reply(conn_handle, &write_auth_succes_reply); GattWriteCallbackParams writeParams = { /* .connHandle = */ conn_handle, /* .handle = */ req->attr_handle, /* .writeOp = */ static_cast<GattWriteCallbackParams::WriteOp_t>(input_req.op), /* .offset = */ req->offset, /* .len = */ req->length, /* .data = */ req->data, }; handleDataWrittenEvent(&writeParams); releaseLongWriteRequest(conn_handle); } return; } GattWriteAuthCallbackParams cbParams = { /* .connHandle = */ gattsEventP->conn_handle, /* .handle = */ handle_value, /* .offset = */ gattsEventP->params.authorize_request.request.write.offset, /* .len = */ gattsEventP->params.authorize_request.request.write.len, /* .data = */ gattsEventP->params.authorize_request.request.write.data, /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member * set to AUTH_CALLBACK_REPLY_SUCCESS if the client * request is to proceed. */ }; ble_gatts_rw_authorize_reply_params_t reply = { /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_WRITE, /* .params = */ { /* .write = */ { /* .gatt_status = */ p_characteristics[characteristicIndex]->authorizeWrite(&cbParams), /* .update = */ 1, /* .offset = */ cbParams.offset, /* .len = */ cbParams.len, /* .p_data = */ cbParams.data } } }; if (reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS) { reply.params.write.update = 0; } sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply); /* * If write-authorization is enabled for a characteristic, * AUTHORIZATION_REQ event (if replied with true) is *not* * followed by another DATA_WRITTEN event; so we still need * to invoke handleDataWritten(), much the same as we would * have done if write-authorization had not been enabled. */ if (reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS) { GattWriteCallbackParams cbParams = { /* .connHandle = */ gattsEventP->conn_handle, /* .handle = */ handle_value, /* .writeOp = */ static_cast<GattWriteCallbackParams::WriteOp_t>(gattsEventP->params.authorize_request.request.write.op), /* .offset = */ gattsEventP->params.authorize_request.request.write.offset, /* .len = */ gattsEventP->params.authorize_request.request.write.len, /* .data = */ gattsEventP->params.authorize_request.request.write.data, }; handleDataWrittenEvent(&cbParams); } break; } case GattServerEvents::GATT_EVENT_READ_AUTHORIZATION_REQ: { GattReadAuthCallbackParams cbParams = { /* .connHandle = */ gattsEventP->conn_handle, /* .handle = */ handle_value, /* .offset = */ gattsEventP->params.authorize_request.request.read.offset, /* .len = */ 0, /* .data = */ NULL, /* .authorizationReply = */ AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member * set to AUTH_CALLBACK_REPLY_SUCCESS if the client * request is to proceed. */ }; ble_gatts_rw_authorize_reply_params_t reply = { /* .type = */ BLE_GATTS_AUTHORIZE_TYPE_READ, /* .params = */ { /* .read = */ { /* .gatt_status = */ p_characteristics[characteristicIndex]->authorizeRead(&cbParams) } } }; if (cbParams.authorizationReply == BLE_GATT_STATUS_SUCCESS) { if (cbParams.data != NULL) { reply.params.read.update = 1; reply.params.read.offset = cbParams.offset; reply.params.read.len = cbParams.len; reply.params.read.p_data = cbParams.data; } } sd_ble_gatts_rw_authorize_reply(gattsEventP->conn_handle, &reply); break; } default: handleEvent(eventType, handle_value); break; } }