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 }
error_t custom_add_in_characteristic(uint16_t service_handle, ble_uuid_t *p_uuid, uint8_t properties, SecurityManager::SecurityMode_t requiredSecurity, uint8_t *p_data, uint16_t length, uint16_t max_length, const uint8_t *userDescriptionDescriptorValuePtr, uint16_t userDescriptionDescriptorValueLen, bool readAuthorization, bool writeAuthorization, ble_gatts_char_handles_t *p_char_handle) { /* Characteristic metadata */ ble_gatts_attr_md_t cccd_md; ble_gatt_char_props_t char_props; memcpy(&char_props, &properties, 1); if (char_props.notify || char_props.indicate) { /* Notification requires cccd */ memclr_( &cccd_md, sizeof(ble_gatts_attr_md_t)); cccd_md.vloc = BLE_GATTS_VLOC_STACK; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); } ble_gatts_char_md_t char_md = {0}; char_md.char_props = char_props; char_md.p_cccd_md = (char_props.notify || char_props.indicate) ? &cccd_md : NULL; if ((userDescriptionDescriptorValueLen > 0) && (userDescriptionDescriptorValuePtr != NULL)) { char_md.p_char_user_desc = const_cast<uint8_t *>(userDescriptionDescriptorValuePtr); char_md.char_user_desc_max_size = userDescriptionDescriptorValueLen; char_md.char_user_desc_size = userDescriptionDescriptorValueLen; } /* Attribute declaration */ ble_gatts_attr_md_t attr_md = {0}; attr_md.rd_auth = readAuthorization; attr_md.wr_auth = writeAuthorization; attr_md.vloc = BLE_GATTS_VLOC_STACK; /* Always set variable size */ attr_md.vlen = 1; if (char_props.read || char_props.notify || char_props.indicate) { switch (requiredSecurity) { case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK : BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); break; case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM : BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.read_perm); break; case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM : BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&attr_md.read_perm); break; case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM : BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(&attr_md.read_perm); break; case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM : BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(&attr_md.read_perm); break; default: break; }; } if (char_props.write || char_props.write_wo_resp) { switch (requiredSecurity) { case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK : BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); break; case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM : BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.write_perm); break; case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM : BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&attr_md.write_perm); break; case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM : BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(&attr_md.write_perm); break; case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM : BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(&attr_md.write_perm); break; default: break; }; } ble_gatts_attr_t attr_char_value = {0}; attr_char_value.p_uuid = p_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = length; attr_char_value.max_len = max_length; attr_char_value.p_value = p_data; ASSERT_STATUS ( sd_ble_gatts_characteristic_add(service_handle, &char_md, &attr_char_value, p_char_handle)); return ERROR_NONE; }
void GATTController::bleMeshServiceInit() { u32 err = 0; meshService.connectionHandle = BLE_CONN_HANDLE_INVALID; //##### At first, we register our custom service //Add our Service UUID to the BLE stack for management ble_uuid128_t baseUUID128 = { MESH_SERVICE_BASE_UUID128 }; err = sd_ble_uuid_vs_add(&baseUUID128, &meshService.serviceUuid.type); APP_ERROR_CHECK(err); //OK //Add the service err = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &meshService.serviceUuid, &meshService.serviceHandle); APP_ERROR_CHECK(err); //OK //##### Now we need to add a characteristic to that service //BLE GATT Attribute Metadata http://developer.nordicsemi.com/nRF51_SDK/doc/7.1.0/s120/html/a00163.html //Read and write permissions, variable length, etc... ble_gatts_attr_md_t attributeMetadata; memset(&attributeMetadata, 0, sizeof(ble_gatts_attr_md_t)); //If encryption is enabled, we want our mesh handle only to be accessable over an //encrypted connection with authentication if(Config->encryptionEnabled){ BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attributeMetadata.read_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attributeMetadata.write_perm); } else { BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attributeMetadata.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attributeMetadata.write_perm); } attributeMetadata.vloc = BLE_GATTS_VLOC_STACK; //We currently have the value on the SoftDevice stack, we might port that to the application space attributeMetadata.rd_auth = 0; attributeMetadata.wr_auth = 0; attributeMetadata.vlen = 1; //Make it a variable length attribute //Client Characteristic Configuration Descriptor, whatever.... ble_gatts_attr_md_t clientCharacteristicConfigurationDescriptor; memset(&clientCharacteristicConfigurationDescriptor, 0, sizeof(ble_gatts_attr_md_t)); clientCharacteristicConfigurationDescriptor.vloc = BLE_GATTS_VLOC_STACK; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&clientCharacteristicConfigurationDescriptor.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&clientCharacteristicConfigurationDescriptor.write_perm); //Characteristic metadata, whatever.... ble_gatts_char_md_t characteristicMetadata; memset(&characteristicMetadata, 0, sizeof(ble_gatts_char_md_t)); characteristicMetadata.char_props.read = 1; /*Reading value permitted*/ characteristicMetadata.char_props.write = 1; /*Writing value with Write Request permitted*/ characteristicMetadata.char_props.write_wo_resp = 1; /*Writing value with Write Command permitted*/ characteristicMetadata.char_props.auth_signed_wr = 0; /*Writing value with Signed Write Command not permitted*/ characteristicMetadata.char_props.notify = 1; /*Notications of value permitted*/ characteristicMetadata.char_props.indicate = 0; /*Indications of value not permitted*/ characteristicMetadata.p_cccd_md = &clientCharacteristicConfigurationDescriptor; //Set human readable name u8 humanReadableCharacteristicDescription[] = "meshWrite"; characteristicMetadata.p_char_user_desc = humanReadableCharacteristicDescription; characteristicMetadata.char_user_desc_max_size = strlen((const char*) humanReadableCharacteristicDescription); characteristicMetadata.char_user_desc_size = strlen((const char*) humanReadableCharacteristicDescription); //Finally, the attribute ble_gatts_attr_t attribute; memset(&attribute, 0, sizeof(ble_gatts_attr_t)); ble_uuid_t attributeUUID; attributeUUID.type = meshService.serviceUuid.type; attributeUUID.uuid = MESH_SERVICE_CHARACTERISTIC_UUID; attribute.p_uuid = &attributeUUID; /* The UUID of the Attribute*/ attribute.p_attr_md = &attributeMetadata; /* The previously defined attribute Metadata */ attribute.max_len = MESH_CHARACTERISTIC_MAX_LENGTH; attribute.init_len = 0; attribute.init_offs = 0; //Finally, add the characteristic err = sd_ble_gatts_characteristic_add(meshService.serviceHandle, &characteristicMetadata, &attribute, &meshService.sendMessageCharacteristicHandle); APP_ERROR_CHECK(err); //OK }
/**@brief Initialize HID Service. */ static void hids_init(void) { uint32_t err_code; ble_hids_init_t hids_init_obj; ble_hids_inp_rep_init_t input_report_array[1]; ble_hids_inp_rep_init_t * p_input_report; ble_hids_outp_rep_init_t output_report_array[1]; ble_hids_outp_rep_init_t * p_output_report; uint8_t hid_info_flags; static uint8_t report_map_data[] = { 0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x06, // Usage (Keyboard) 0xA1, 0x01, // Collection (Application) 0x05, 0x07, // Usage Page (Key Codes) 0x19, 0xe0, // Usage Minimum (224) 0x29, 0xe7, // Usage Maximum (231) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x75, 0x01, // Report Size (1) 0x95, 0x08, // Report Count (8) 0x81, 0x02, // Input (Data, Variable, Absolute) 0x95, 0x01, // Report Count (1) 0x75, 0x08, // Report Size (8) 0x81, 0x01, // Input (Constant) reserved byte(1) 0x95, 0x05, // Report Count (5) 0x75, 0x01, // Report Size (1) 0x05, 0x08, // Usage Page (Page# for LEDs) 0x19, 0x01, // Usage Minimum (1) 0x29, 0x05, // Usage Maximum (5) 0x91, 0x02, // Output (Data, Variable, Absolute), Led report 0x95, 0x01, // Report Count (1) 0x75, 0x03, // Report Size (3) 0x91, 0x01, // Output (Data, Variable, Absolute), Led report padding 0x95, 0x06, // Report Count (6) 0x75, 0x08, // Report Size (8) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x65, // Logical Maximum (101) 0x05, 0x07, // Usage Page (Key codes) 0x19, 0x00, // Usage Minimum (0) 0x29, 0x65, // Usage Maximum (101) 0x81, 0x00, // Input (Data, Array) Key array(6 bytes) 0x09, 0x05, // Usage (Vendor Defined) 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x75, 0x08, // Report Count (2) 0x95, 0x02, // Report Size (8 bit) 0xB1, 0x02, // Feature (Data, Variable, Absolute) 0xC0 // End Collection (Application) }; // Initialize HID Service p_input_report = &input_report_array[INPUT_REPORT_KEYS_INDEX]; p_input_report->max_len = INPUT_REPORT_KEYS_MAX_LEN; p_input_report->rep_ref.report_id = INPUT_REP_REF_ID; p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT; BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.read_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.write_perm); p_output_report = &output_report_array[OUTPUT_REPORT_INDEX]; p_output_report->max_len = OUTPUT_REPORT_MAX_LEN; p_output_report->rep_ref.report_id = OUTPUT_REP_REF_ID; p_output_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_OUTPUT; BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_output_report->security_mode.read_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_output_report->security_mode.write_perm); hid_info_flags = HID_INFO_FLAG_REMOTE_WAKE_MSK | HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK; memset(&hids_init_obj, 0, sizeof(hids_init_obj)); hids_init_obj.evt_handler = on_hids_evt; hids_init_obj.error_handler = service_error_handler; hids_init_obj.is_kb = true; hids_init_obj.is_mouse = false; hids_init_obj.inp_rep_count = 1; hids_init_obj.p_inp_rep_array = input_report_array; hids_init_obj.outp_rep_count = 1; hids_init_obj.p_outp_rep_array = output_report_array; hids_init_obj.feature_rep_count = 0; hids_init_obj.p_feature_rep_array = NULL; hids_init_obj.rep_map.data_len = sizeof(report_map_data); hids_init_obj.rep_map.p_data = report_map_data; hids_init_obj.hid_information.bcd_hid = BASE_USB_HID_SPEC_VERSION; hids_init_obj.hid_information.b_country_code = 0; hids_init_obj.hid_information.flags = hid_info_flags; hids_init_obj.included_services_count = 0; hids_init_obj.p_included_services_array = NULL; BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.rep_map.security_mode.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hids_init_obj.rep_map.security_mode.write_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.hid_information.security_mode.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hids_init_obj.hid_information.security_mode.write_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_boot_kb_inp_rep.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_boot_kb_inp_rep.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hids_init_obj.security_mode_boot_kb_inp_rep.write_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_boot_kb_outp_rep.read_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_boot_kb_outp_rep.write_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_protocol.read_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_protocol.write_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hids_init_obj.security_mode_ctrl_point.read_perm); BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_ctrl_point.write_perm); err_code = ble_hids_init(&m_hids, &hids_init_obj); APP_ERROR_CHECK(err_code); }
/**@brief Function for initializing services that will be used by the application. * * @details Initialize the Running Speed and Cadence, Battery and Device Information services. */ static void services_init(void) { uint32_t err_code; ble_hts_init_t hts_init; ble_rscs_init_t rscs_init; ble_bas_init_t bas_init; ble_dis_init_t dis_init; // Initialize Health Thermometer Service memset(&hts_init, 0, sizeof(hts_init)); hts_init.evt_handler = on_hts_evt; hts_init.temp_type_as_characteristic = 0; hts_init.temp_type = BLE_HTS_TEMP_TYPE_BODY; // Here the sec level for the Health Thermometer Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hts_init.hts_meas_attr_md.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hts_init.hts_meas_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hts_init.hts_meas_attr_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&hts_init.hts_temp_type_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hts_init.hts_temp_type_attr_md.write_perm); err_code = ble_hts_init(&m_hts, &hts_init); APP_ERROR_CHECK(err_code); // Initialize Running Speed and Cadence Service memset(&rscs_init, 0, sizeof(rscs_init)); rscs_init.evt_handler = NULL; rscs_init.feature = BLE_RSCS_FEATURE_INSTANT_STRIDE_LEN_BIT| BLE_RSCS_FEATURE_TOTAL_DISTANCE_BIT| // BLE_RSCS_FEATURE_WALKING_OR_RUNNING_STATUS_BIT; // Here the sec level for the Running Speed and Cadence Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&rscs_init.rsc_meas_attr_md.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&rscs_init.rsc_meas_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&rscs_init.rsc_meas_attr_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&rscs_init.rsc_feature_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&rscs_init.rsc_feature_attr_md.write_perm); err_code = ble_rscs_init(&m_rscs, &rscs_init); APP_ERROR_CHECK(err_code); // Initialize Battery Service. memset(&bas_init, 0, sizeof(bas_init)); // Here the sec level for the Battery Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.cccd_write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init.battery_level_char_attr_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_report_read_perm); bas_init.evt_handler = NULL; bas_init.support_notification = true; bas_init.p_report_ref = NULL; bas_init.initial_batt_level = 100; err_code = ble_bas_init(&m_bas, &bas_init); APP_ERROR_CHECK(err_code); // Initialize Device Information Service. memset(&dis_init, 0, sizeof(dis_init)); ble_srv_ascii_to_utf8(&dis_init.manufact_name_str, MANUFACTURER_NAME); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dis_init.dis_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init.dis_attr_md.write_perm); err_code = ble_dis_init(&dis_init); APP_ERROR_CHECK(err_code); }
/**@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; }