error_t custom_add_in_descriptor(uint16_t char_handle, ble_uuid_t *p_uuid, uint8_t *p_data, uint16_t length, uint16_t max_length, uint16_t *p_desc_handle) { /* Descriptor metadata */ ble_gatts_attr_md_t desc_md = {0}; desc_md.vloc = BLE_GATTS_VLOC_STACK; /* Always set variable size */ desc_md.vlen = 1; /* Make it readable and writable */ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.write_perm); ble_gatts_attr_t attr_desc = {0}; attr_desc.p_uuid = p_uuid; attr_desc.p_attr_md = &desc_md; attr_desc.init_len = length; attr_desc.max_len = max_length; attr_desc.p_value = p_data; ASSERT_STATUS ( sd_ble_gatts_descriptor_add(char_handle, &attr_desc, p_desc_handle)); return ERROR_NONE; }
uint32_t conn_mw_ble_gatts_descriptor_add(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 char_handle; uint8_t attr_value[BLE_GATTS_VAR_ATTR_LEN_MAX]; ble_uuid_t char_uuid; ble_gatts_attr_md_t metadata; ble_gatts_attr_t attr; ble_gatts_attr_t * p_attr = &attr; attr.p_uuid = &char_uuid; attr.p_attr_md = &metadata; attr.p_value = attr_value; attr.init_len = sizeof (attr_value); uint16_t handle; uint16_t * p_handle = &handle; uint32_t err_code = NRF_SUCCESS; uint32_t sd_err_code; err_code = ble_gatts_descriptor_add_req_dec(p_rx_buf, rx_buf_len, &char_handle, &p_attr, &p_handle); SER_ASSERT(err_code == NRF_SUCCESS, err_code); sd_err_code = sd_ble_gatts_descriptor_add(char_handle, p_attr, p_handle); err_code = ble_gatts_descriptor_add_rsp_enc(sd_err_code, p_tx_buf, p_tx_buf_len, handle); SER_ASSERT(err_code == NRF_SUCCESS, err_code); return err_code; }
uint32_t descriptor_add(uint16_t char_handle, ble_add_descr_params_t * p_descr_props, uint16_t * p_descr_handle) { ble_gatts_attr_t descr_params; ble_uuid_t desc_uuid; ble_gatts_attr_md_t attr_md; memset(&descr_params, 0, sizeof(descr_params)); if (p_descr_props->uuid_type == 0) { desc_uuid.type = BLE_UUID_TYPE_BLE; } else { desc_uuid.type = p_descr_props->uuid_type; } desc_uuid.uuid = p_descr_props->uuid; descr_params.p_uuid = &desc_uuid; set_security_req(p_descr_props->read_access, &attr_md.read_perm); set_security_req(p_descr_props->write_access,&attr_md.write_perm); attr_md.rd_auth = (p_descr_props->is_defered_read ? 1 : 0); attr_md.wr_auth = (p_descr_props->is_defered_write ? 1 : 0); attr_md.vlen = (p_descr_props->is_var_len ? 1 : 0); attr_md.vloc = (p_descr_props->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK); descr_params.p_attr_md = &attr_md; descr_params.init_len = p_descr_props->init_len; descr_params.init_offs = p_descr_props->init_offs; descr_params.max_len = p_descr_props->max_len; descr_params.p_value = p_descr_props->p_value; return sd_ble_gatts_descriptor_add(char_handle, &descr_params, p_descr_handle); }
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 }
/**@brief Function for adding the Battery Level characteristic. * * @param[in] p_bas Battery Service structure. * @param[in] p_bas_init Information needed to initialize the service. * * @return NRF_SUCCESS on success, otherwise an error code. */ static uint32_t battery_level_char_add(ble_bas_t * p_bas, const ble_bas_init_t * p_bas_init) { uint32_t err_code; ble_gatts_char_md_t char_md; ble_gatts_attr_md_t cccd_md; ble_gatts_attr_t attr_char_value; ble_uuid_t ble_uuid; ble_gatts_attr_md_t attr_md; uint8_t initial_battery_level; uint8_t encoded_report_ref[BLE_SRV_ENCODED_REPORT_REF_LEN]; uint8_t init_len; // Add Battery Level characteristic if (p_bas->is_notification_supported) { memset(&cccd_md, 0, sizeof(cccd_md)); // According to BAS_SPEC_V10, the read operation on cccd should be possible without // authentication. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); cccd_md.write_perm = p_bas_init->battery_level_char_attr_md.cccd_write_perm; cccd_md.vloc = BLE_GATTS_VLOC_STACK; } memset(&char_md, 0, sizeof(char_md)); char_md.char_props.read = 1; char_md.char_props.notify = (p_bas->is_notification_supported) ? 1 : 0; char_md.p_char_user_desc = NULL; char_md.p_char_pf = NULL; char_md.p_user_desc_md = NULL; char_md.p_cccd_md = (p_bas->is_notification_supported) ? &cccd_md : NULL; char_md.p_sccd_md = NULL; BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BATTERY_LEVEL_CHAR); memset(&attr_md, 0, sizeof(attr_md)); attr_md.read_perm = p_bas_init->battery_level_char_attr_md.read_perm; attr_md.write_perm = p_bas_init->battery_level_char_attr_md.write_perm; attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 0; initial_battery_level = p_bas_init->initial_batt_level; memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = sizeof(uint8_t); attr_char_value.init_offs = 0; attr_char_value.max_len = sizeof(uint8_t); attr_char_value.p_value = &initial_battery_level; err_code = sd_ble_gatts_characteristic_add(p_bas->service_handle, &char_md, &attr_char_value, &p_bas->battery_level_handles); if (err_code != NRF_SUCCESS) { return err_code; } if (p_bas_init->p_report_ref != NULL) { // Add Report Reference descriptor BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_REPORT_REF_DESCR); memset(&attr_md, 0, sizeof(attr_md)); attr_md.read_perm = p_bas_init->battery_level_report_read_perm; BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm); attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 0; init_len = ble_srv_report_ref_encode(encoded_report_ref, p_bas_init->p_report_ref); memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = init_len; attr_char_value.init_offs = 0; attr_char_value.max_len = attr_char_value.init_len; attr_char_value.p_value = encoded_report_ref; err_code = sd_ble_gatts_descriptor_add(p_bas->battery_level_handles.value_handle, &attr_char_value, &p_bas->report_ref_handle); if (err_code != NRF_SUCCESS) { return err_code; } } else { p_bas->report_ref_handle = BLE_GATT_HANDLE_INVALID; } return NRF_SUCCESS; }
/**@brief Function for adding the accel Level characteristic. * * @param[in] p_acc accel Service structure. * @param[in] p_acc_init Information needed to initialize the service. * * @return NRF_SUCCESS on success, otherwise an error code. */ static uint32_t accel_level_char_add(ble_acc_t * p_acc, const ble_acc_init_t * p_acc_init) { uint32_t err_code; ble_gatts_char_md_t char_md; ble_gatts_attr_md_t cccd_md; ble_gatts_attr_t attr_char_value; // ble_gatts_attr_t attr_char_value_2; ble_uuid_t ble_uuid; ble_gatts_attr_md_t attr_md; // ble_gatts_attr_md_t attr_md_2; ble_gatts_attr_md_t user_desc_md; ble_gatts_char_pf_t accel_pf; uint8_t initial_accel_level; uint8_t encoded_report_ref[BLE_SRV_ENCODED_REPORT_REF_LEN]; uint8_t init_len; uint8_t user_desc[] = "ACCEL"; // Add accel Level characteristic if (p_acc->is_notification_supported) { memset(&cccd_md, 0, sizeof(cccd_md)); // According to acc_SPEC_V10, the read operation on cccd should be possible without // authentication. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); cccd_md.write_perm = p_acc_init->accel_level_char_attr_md.cccd_write_perm; cccd_md.vloc = BLE_GATTS_VLOC_STACK; } memset(&user_desc_md, 0, sizeof(user_desc_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&user_desc_md.read_perm); // BLE_GAP_CONN_SEC_MODE_SET_OPEN(&user_desc_md.write_perm); user_desc_md.vloc = BLE_GATTS_VLOC_STACK; memset(&accel_pf, 0, sizeof(accel_pf)); accel_pf.format = BLE_GATT_CPF_FORMAT_UINT16; accel_pf.exponent = 0; accel_pf.unit = 0x2713; //acceleration data memset(&char_md, 0, sizeof(char_md)); char_md.char_props.read = 1; char_md.char_props.write = 1; char_md.char_props.notify = (p_acc->is_notification_supported) ? 1 : 0; char_md.p_char_user_desc = user_desc; char_md.char_user_desc_max_size = 6; char_md.char_user_desc_size = 6; char_md.p_char_pf = &accel_pf; char_md.p_user_desc_md = &user_desc_md; char_md.p_cccd_md = (p_acc->is_notification_supported) ? &cccd_md : NULL; char_md.p_sccd_md = NULL; //adds the acce id to the softdevice stack, puts a reference to where it is //into acc_uuid_type ble_uuid.type = p_acc->uuid_type; ble_uuid.uuid = BLE_UUID_TYPE_VENDOR_BEGIN; memset(&attr_md, 0, sizeof(attr_md)); attr_md.read_perm = p_acc_init->accel_level_char_attr_md.read_perm; attr_md.write_perm = p_acc_init->accel_level_char_attr_md.write_perm; attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 0; initial_accel_level = p_acc_init->initial_batt_level; memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = sizeof(uint16_t); attr_char_value.init_offs = 0; attr_char_value.max_len = sizeof(uint16_t); attr_char_value.p_value = &initial_accel_level; err_code = sd_ble_gatts_characteristic_add(p_acc->service_handle, &char_md, &attr_char_value, &p_acc->accel_level_handles); if (err_code != NRF_SUCCESS) { return err_code; } if (p_acc_init->p_report_ref != NULL) { // Add Report Reference descriptor BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_REPORT_REF_DESCR); memset(&attr_md, 0, sizeof(attr_md)); attr_md.read_perm = p_acc_init->accel_level_report_read_perm; BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm); attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 0; init_len = ble_srv_report_ref_encode(encoded_report_ref, p_acc_init->p_report_ref); memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = init_len; attr_char_value.init_offs = 0; attr_char_value.max_len = attr_char_value.init_len; attr_char_value.p_value = encoded_report_ref; err_code = sd_ble_gatts_descriptor_add(p_acc->accel_level_handles.value_handle, &attr_char_value, &p_acc->report_ref_handle); if (err_code != NRF_SUCCESS) { return err_code; } } else { p_acc->report_ref_handle = BLE_GATT_HANDLE_INVALID; } return NRF_SUCCESS; }
/**@brief Function for adding Report Map characteristics. * * @param[in] p_hids HID Service structure. * @param[in] p_hids_init Service initialization structure. * * @return NRF_SUCCESS on success, otherwise an error code. */ static uint32_t rep_map_char_add(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init) { uint32_t err_code; ble_gatts_char_md_t char_md; ble_gatts_attr_t attr_char_value; ble_uuid_t ble_uuid; ble_gatts_attr_md_t attr_md; // Add Report Map characteristic memset(&char_md, 0, sizeof(char_md)); char_md.char_props.read = 1; char_md.p_char_user_desc = NULL; char_md.p_char_pf = NULL; char_md.p_user_desc_md = NULL; char_md.p_cccd_md = NULL; char_md.p_sccd_md = NULL; BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_REPORT_MAP_CHAR); memset(&attr_md, 0, sizeof(attr_md)); attr_md.read_perm = p_hids_init->rep_map.security_mode.read_perm; attr_md.write_perm = p_hids_init->rep_map.security_mode.write_perm; attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 1; memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = p_hids_init->rep_map.data_len; attr_char_value.init_offs = 0; attr_char_value.max_len = p_hids_init->rep_map.data_len; attr_char_value.p_value = p_hids_init->rep_map.p_data; err_code = sd_ble_gatts_characteristic_add(p_hids->service_handle, &char_md, &attr_char_value, &p_hids->rep_map_handles); if (err_code != NRF_SUCCESS) { return err_code; } if (p_hids_init->rep_map.ext_rep_ref_num != 0 && p_hids_init->rep_map.p_ext_rep_ref == NULL) { return NRF_ERROR_INVALID_PARAM; } for (int i = 0; i < p_hids_init->rep_map.ext_rep_ref_num; ++i) { uint8_t encoded_rep_ref[sizeof(ble_uuid128_t)]; uint8_t encoded_rep_ref_len; // Add External Report Reference descriptor BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_EXTERNAL_REPORT_REF_DESCR); memset(&attr_md, 0, sizeof(attr_md)); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm); attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 0; err_code = sd_ble_uuid_encode(&p_hids_init->rep_map.p_ext_rep_ref[i], &encoded_rep_ref_len, encoded_rep_ref); if (err_code != NRF_SUCCESS) { return err_code; } memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = encoded_rep_ref_len; attr_char_value.init_offs = 0; attr_char_value.max_len = attr_char_value.init_len; attr_char_value.p_value = encoded_rep_ref; err_code = sd_ble_gatts_descriptor_add(p_hids->rep_map_handles.value_handle, &attr_char_value, &p_hids->rep_map_ext_rep_ref_handle); if (err_code != NRF_SUCCESS) { return err_code; } } return NRF_SUCCESS; }
/**@brief Function for adding report characteristics. * * @param[in] p_hids HID Service structure. * @param[in] p_properties Report characteristic properties. * @param[in] max_len Maximum length of report value. * @param[in] p_rep_ref Report Reference descriptor. * @param[in] p_rep_ref_attr_md Characteristic security settings. * @param[in] is_read_resp Characteristic read authorization. * @param[out] p_rep_char Handles of new characteristic. * * @return NRF_SUCCESS on success, otherwise an error code. */ static uint32_t rep_char_add(ble_hids_t * p_hids, ble_gatt_char_props_t * p_properties, uint16_t max_len, ble_srv_report_ref_t * p_rep_ref, ble_srv_cccd_security_mode_t * p_rep_ref_attr_md, bool is_read_resp, ble_hids_rep_char_t * p_rep_char) { uint32_t err_code; ble_gatts_char_md_t char_md; ble_gatts_attr_md_t cccd_md; ble_gatts_attr_t attr_char_value; ble_uuid_t ble_uuid; ble_gatts_attr_md_t attr_md; uint8_t encoded_rep_ref[BLE_SRV_ENCODED_REPORT_REF_LEN]; // Add Report characteristic if (p_properties->notify) { memset(&cccd_md, 0, sizeof(cccd_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); cccd_md.write_perm = p_rep_ref_attr_md->cccd_write_perm; cccd_md.vloc = BLE_GATTS_VLOC_STACK; } memset(&char_md, 0, sizeof(char_md)); char_md.char_props = *p_properties; char_md.p_char_user_desc = NULL; char_md.p_char_pf = NULL; char_md.p_user_desc_md = NULL; char_md.p_cccd_md = (p_properties->notify) ? &cccd_md : NULL; char_md.p_sccd_md = NULL; BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_REPORT_CHAR); memset(&attr_md, 0, sizeof(attr_md)); attr_md.read_perm = p_rep_ref_attr_md->read_perm; attr_md.write_perm = p_rep_ref_attr_md->write_perm; attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = is_read_resp ? 1 : 0; attr_md.wr_auth = 0; attr_md.vlen = 1; memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = 0; attr_char_value.init_offs = 0; attr_char_value.max_len = max_len; attr_char_value.p_value = NULL; err_code = sd_ble_gatts_characteristic_add(p_hids->service_handle, &char_md, &attr_char_value, &p_rep_char->char_handles); if (err_code != NRF_SUCCESS) { return err_code; } // Add Report Reference descriptor BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_REPORT_REF_DESCR); memset(&attr_md, 0, sizeof(attr_md)); attr_md.read_perm = p_rep_ref_attr_md->read_perm; attr_md.write_perm = p_rep_ref_attr_md->write_perm; attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 0; memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &ble_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = ble_srv_report_ref_encode(encoded_rep_ref, p_rep_ref); attr_char_value.init_offs = 0; attr_char_value.max_len = attr_char_value.init_len; attr_char_value.p_value = encoded_rep_ref; return sd_ble_gatts_descriptor_add(p_rep_char->char_handles.value_handle, &attr_char_value, &p_rep_char->ref_handle); }