/**@brief GAP initialization. * * @details This function shall be used to setup all the necessary GAP (Generic Access Profile) * parameters of the device. It also sets the permissions and appearance. */ static void gap_params_init(void) { uint32_t err_code; ble_gap_conn_params_t gap_conn_params; ble_gap_conn_sec_mode_t sec_mode; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); err_code = sd_ble_gap_device_name_set(&sec_mode, DEVICE_NAME, strlen(DEVICE_NAME)); APP_ERROR_CHECK(err_code); err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR); APP_ERROR_CHECK(err_code); memset(&gap_conn_params, 0, sizeof(gap_conn_params)); gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL; gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL; gap_conn_params.slave_latency = SLAVE_LATENCY; gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT; err_code = sd_ble_gap_ppcp_set(&gap_conn_params); APP_ERROR_CHECK(err_code); }
/**@brief Function for initializing the Advertising functionality. * * @details Encodes the required advertising data and passes it to the stack. * Also builds a structure to be passed to the stack when starting advertising. */ static void advertising_init(void) { uint32_t err_code; ble_advdata_t advdata; ble_gap_conn_sec_mode_t sec_mode; uint8_t flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE; // Set GAP parameters BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)DEVICE_NAME, strlen(DEVICE_NAME)); APP_ERROR_CHECK(err_code); err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_GENERIC_WATCH); APP_ERROR_CHECK(err_code); // Build and set advertising data memset(&advdata, 0, sizeof (advdata)); advdata.name_type = BLE_ADVDATA_FULL_NAME; advdata.include_appearance = false; advdata.flags = flags; err_code = ble_advdata_set(&advdata, NULL); APP_ERROR_CHECK(err_code); // Initialize advertising parameters (used when starting advertising) memset(&m_adv_params, 0, sizeof (m_adv_params)); m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND; m_adv_params.p_peer_addr = NULL; // Undirected advertisement m_adv_params.fp = BLE_GAP_ADV_FP_ANY; m_adv_params.interval = APP_ADV_INTERVAL; m_adv_params.timeout = APP_ADV_TIMEOUT_IN_SECONDS; }
/**@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); }
/** * @brief BLEスタック初期化 * * @detail BLE関連の初期化を行う。 * -# SoftDeviceハンドラ初期化 * -# システムイベントハンドラ初期化 * -# BLEスタック有効化 * -# BLEイベントハンドラ設定 * -# デバイス名設定 * -# Appearance設定(GAP_USE_APPEARANCE定義時) * -# PPCP設定 * -# Service初期化 * -# Advertising初期化 * -# Connection初期化 */ static void ble_stack_init(void) { uint32_t err_code; /* BLEスタックの有効化 */ { ble_enable_params_t ble_enable_params; memset(&ble_enable_params, 0, sizeof(ble_enable_params)); ble_enable_params.gatts_enable_params.service_changed = IS_SRVC_CHANGED_CHARACT_PRESENT; err_code = sd_ble_enable(&ble_enable_params); APP_ERROR_CHECK(err_code); } /* デバイス名設定 */ { //デバイス名へのWrite Permission(no protection, open link) ble_gap_conn_sec_mode_t sec_mode; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)GAP_DEVICE_NAME, strlen(GAP_DEVICE_NAME)); APP_ERROR_CHECK(err_code); } #ifdef GAP_USE_APPEARANCE /* Appearance設定 */ err_code = sd_ble_gap_appearance_set(GAP_USE_APPEARANCE); APP_ERROR_CHECK(err_code); #endif //GAP_USE_APPEARANCE /* * Peripheral Preferred Connection Parameters(PPCP) * ここで設定しておくと、Connection Parameter Update Reqを送信せずに済むらしい。 */ { ble_gap_conn_params_t gap_conn_params = {0}; gap_conn_params.min_conn_interval = MSEC_TO_UNITS(CONN_MIN_INTERVAL, UNIT_1_25_MS); gap_conn_params.max_conn_interval = MSEC_TO_UNITS(CONN_MAX_INTERVAL, UNIT_1_25_MS); gap_conn_params.slave_latency = CONN_SLAVE_LATENCY; gap_conn_params.conn_sup_timeout = MSEC_TO_UNITS(CONN_SUP_TIMEOUT, UNIT_10_MS); err_code = sd_ble_gap_ppcp_set(&gap_conn_params); APP_ERROR_CHECK(err_code); } /* * Service初期化 */ { ble_ios_init_t ios_init; ios_init.evt_handler_in = svc_ios_handler_in; //ios_init.evt_handler_out = svc_ios_handler_out; ios_init.len_in = 64; ios_init.len_out = 32; ble_ios_init(&m_ios, &ios_init); } /* * Advertising初期化 */ { ble_uuid_t adv_uuids[] = { { IOS_UUID_SERVICE, m_ios.uuid_type } }; ble_advdata_t advdata; ble_advdata_t scanrsp; memset(&advdata, 0, sizeof(advdata)); memset(&scanrsp, 0, sizeof(scanrsp)); /* * ble_advdata_name_type_t (ble_advdata.h) * * BLE_ADVDATA_NO_NAME : デバイス名無し * BLE_ADVDATA_SHORT_NAME : デバイス名あり «Shortened Local Name» * BLE_ADVDATA_FULL_NAME : デバイス名あり «Complete Local Name» * * https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile * https://developer.nordicsemi.com/nRF51_SDK/nRF51_SDK_v7.x.x/doc/7.2.0/s110/html/a01015.html#ga03c5ccf232779001be9786021b1a563b */ advdata.name_type = BLE_ADVDATA_FULL_NAME; /* * Appearanceが含まれるかどうか */ #ifdef GAP_USE_APPEARANCE advdata.include_appearance = true; #else //GAP_USE_APPEARANCE advdata.include_appearance = false; #endif //GAP_USE_APPEARANCE /* * Advertisingフラグの設定 * CSS_v4 : Part A 1.3 FLAGS * https://developer.nordicsemi.com/nRF51_SDK/nRF51_SDK_v7.x.x/doc/7.2.0/s110/html/a00802.html * * BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE = BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE | BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED * BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE : LE Limited Discoverable Mode * BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED : BR/EDR not supported */ advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE; //探索時間に制限あり /* SCAN_RSPデータ設定 */ scanrsp.uuids_complete.uuid_cnt = ARRAY_SIZE(adv_uuids); scanrsp.uuids_complete.p_uuids = adv_uuids; err_code = ble_advdata_set(&advdata, &scanrsp); APP_ERROR_CHECK(err_code); } /* * Connection初期化 */ { ble_conn_params_init_t cp_init = {0}; /* APP_TIMER_PRESCALER = 0 */ cp_init.p_conn_params = NULL; cp_init.first_conn_params_update_delay = APP_TIMER_TICKS(CONN_FIRST_PARAMS_UPDATE_DELAY, 0); cp_init.next_conn_params_update_delay = APP_TIMER_TICKS(CONN_NEXT_PARAMS_UPDATE_DELAY, 0); cp_init.max_conn_params_update_count = CONN_MAX_PARAMS_UPDATE_COUNT; cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID; cp_init.disconnect_on_fail = false; cp_init.evt_handler = conn_params_evt_handler; cp_init.error_handler = conn_params_error_handler; err_code = ble_conn_params_init(&cp_init); APP_ERROR_CHECK(err_code); } #ifdef BLE_DFU_APP_SUPPORT /** @snippet [DFU BLE Service initialization] */ { ble_dfu_init_t dfus_init; // Initialize the Device Firmware Update Service. memset(&dfus_init, 0, sizeof(dfus_init)); dfus_init.evt_handler = dfu_app_on_dfu_evt; dfus_init.error_handler = NULL; //service_error_handler - Not used as only the switch from app to DFU mode is required and not full dfu service. dfus_init.evt_handler = dfu_app_on_dfu_evt; dfus_init.revision = DFU_REVISION; err_code = ble_dfu_init(&m_dfus, &dfus_init); APP_ERROR_CHECK(err_code); dfu_app_reset_prepare_set(dfu_reset_prepare); } /** @snippet [DFU BLE Service initialization] */ #endif // BLE_DFU_APP_SUPPORT }
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 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_rscs_init_t rscs_init; ble_bas_init_t bas_init; ble_dis_init_t dis_init; // 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_WALKING_OR_RUNNING_STATUS_BIT; rscs_init.initial_rcm.is_inst_stride_len_present = true; rscs_init.initial_rcm.is_total_distance_present = false; rscs_init.initial_rcm.is_running = false; rscs_init.initial_rcm.inst_stride_length = 0; // 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); #ifdef BLE_DFU_APP_SUPPORT /** @snippet [DFU BLE Service initialization] */ ble_dfu_init_t dfus_init; // Initialize the Device Firmware Update Service. memset(&dfus_init, 0, sizeof(dfus_init)); dfus_init.evt_handler = dfu_app_on_dfu_evt; dfus_init.error_handler = NULL; dfus_init.evt_handler = dfu_app_on_dfu_evt; dfus_init.revision = DFU_REVISION; err_code = ble_dfu_init(&m_dfus, &dfus_init); APP_ERROR_CHECK(err_code); dfu_app_reset_prepare_set(reset_prepare); dfu_app_dm_appl_instance_set(m_app_handle); /** @snippet [DFU BLE Service initialization] */ #endif // BLE_DFU_APP_SUPPORT #ifdef BLE_DATA_SYNC_SUPPORT ble_data_sync_init_t data_syncs_init; memset(&data_syncs_init, 0, sizeof(data_syncs_init)); data_syncs_init.revision = 0X02; err_code = ble_data_sync_init(&m_data_syncs, &data_syncs_init); APP_ERROR_CHECK(err_code); #endif }
/**@brief Function for initializing services that will be used by the application. * * @details Initialize the Cycling Speed and Cadence, Battery and Device Information services. */ static void services_init(void) { uint32_t err_code; ble_cscs_init_t cscs_init; ble_bas_init_t bas_init; ble_dis_init_t dis_init; ble_sensor_location_t sensor_location; // Initialize Cycling Speed and Cadence Service. memset(&cscs_init, 0, sizeof(cscs_init)); cscs_init.evt_handler = NULL; cscs_init.feature = BLE_CSCS_FEATURE_WHEEL_REV_BIT | BLE_CSCS_FEATURE_CRANK_REV_BIT | BLE_CSCS_FEATURE_MULTIPLE_SENSORS_BIT; // Here the sec level for the Cycling Speed and Cadence Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cscs_init.csc_meas_attr_md.cccd_write_perm); // for the measurement characteristic, only the CCCD write permission can be set by the application, others are mandated by service specification BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cscs_init.csc_feature_attr_md.read_perm); // for the feature characteristic, only the read permission can be set by the application, others are mandated by service specification BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cscs_init.csc_ctrlpt_attr_md.write_perm); // for the SC control point characteristic, only the write permission and CCCD write can be set by the application, others are mandated by service specification BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cscs_init.csc_ctrlpt_attr_md.cccd_write_perm); // for the SC control point characteristic, only the write permission and CCCD write can be set by the application, others are mandated by service specification cscs_init.ctrplt_supported_functions = BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED |BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED |BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED; cscs_init.ctrlpt_evt_handler = sc_ctrlpt_event_handler; cscs_init.list_supported_locations = supported_locations; cscs_init.size_list_supported_locations = sizeof(supported_locations) / sizeof(ble_sensor_location_t); sensor_location = BLE_SENSOR_LOCATION_FRONT_WHEEL; // initializes the sensor location to add the sensor location characteristic. cscs_init.sensor_location = &sensor_location; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cscs_init.csc_sensor_loc_attr_md.read_perm); // for the sensor location characteristic, only the read permission can be set by the application, others are mendated by service specification err_code = ble_cscs_init(&m_cscs, &cscs_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); }
//============================================================================// // This is where we initialize our services and register them with the stack. // // The services that we create are: // // 1) Custom Service // 2) Battery Service // 3) Device Information Service // 4) DFU Service (if enabled via macro) static void services_init(void) { uint32_t err_code; ble_bas_init_t bas_init; ble_dis_init_t dis_init; //-------------------------------------------------------------------------- // Set up the Custom Service err_code = CS_Init(&_cs); 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(&_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, (char *)MANUFACTURER_NAME); ble_srv_ascii_to_utf8(&dis_init.model_num_str, (char *)MODEL_NUMBER); ble_srv_ascii_to_utf8(&dis_init.serial_num_str, (char *)SERIAL_NUMBER); ble_srv_ascii_to_utf8(&dis_init.hw_rev_str, (char *)HARDWARE_REVISION); ble_srv_ascii_to_utf8(&dis_init.fw_rev_str, (char *)FIRMWARE_REVISION); 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); #ifdef BLE_DFU_APP_SUPPORT /** @snippet [DFU BLE Service initialization] */ ble_dfu_init_t dfus_init; // Initialize the Device Firmware Update Service. memset(&dfus_init, 0, sizeof(dfus_init)); dfus_init.evt_handler = dfu_app_on_dfu_evt; dfus_init.error_handler = NULL; dfus_init.evt_handler = dfu_app_on_dfu_evt; dfus_init.revision = DFU_REVISION; err_code = ble_dfu_init(&_dfus, &dfus_init); APP_ERROR_CHECK(err_code); dfu_app_reset_prepare_set(reset_prepare); dfu_app_dm_appl_instance_set(_app_handle); /** @snippet [DFU BLE Service initialization] */ #endif // BLE_DFU_APP_SUPPORT }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(hello_world_process, ev, data) { PROCESS_BEGIN(); uint32_t err_code; // Initialize the SoftDevice handler module. SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false); // Register with the SoftDevice handler module for BLE events. err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch); APP_ERROR_CHECK(err_code); // Register with the SoftDevice handler module for BLE events. err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch); APP_ERROR_CHECK(err_code); ble_gap_conn_sec_mode_t sec_mode; char name_buffer[9]; sprintf(name_buffer, "%08X",(unsigned int) NRF_FICR->DEVICEID[0]); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)name_buffer, strlen(name_buffer)); APP_ERROR_CHECK(err_code); ble_advdata_t advdata; uint8_t flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED; ble_advdata_service_data_t service_data[2]; uint8_t battery_data = 98;//battery_level_get(); uint32_t temperature_data = 0xFE001213; service_data[0].service_uuid = BLE_UUID_BATTERY_SERVICE; service_data[0].data.size = sizeof(battery_data); service_data[0].data.p_data = &battery_data; service_data[1].service_uuid = BLE_UUID_HEALTH_THERMOMETER_SERVICE; service_data[1].data.size = sizeof(temperature_data); service_data[1].data.p_data = (uint8_t *) &temperature_data; // Build and set advertising data memset(&advdata, 0, sizeof(advdata)); advdata.name_type = BLE_ADVDATA_FULL_NAME; advdata.include_appearance = false; advdata.flags.size = sizeof(flags); advdata.flags.p_data = &flags; advdata.service_data_count = 2; advdata.p_service_data_array = service_data; err_code = ble_advdata_set(&advdata, NULL); APP_ERROR_CHECK(err_code); ble_gap_adv_params_t adv_params; // Start advertising memset(&adv_params, 0, sizeof(adv_params)); adv_params.type = BLE_GAP_ADV_TYPE_ADV_NONCONN_IND; adv_params.p_peer_addr = NULL; adv_params.fp = BLE_GAP_ADV_FP_ANY; adv_params.interval = ADV_INTERVAL; adv_params.timeout = ADV_TIMEOUT_IN_SECONDS; err_code = sd_ble_gap_adv_start(&adv_params); APP_ERROR_CHECK(err_code); leds_off(LEDS_ALL); leds_on(LEDS_RED); PROCESS_PAUSE(); etimer_set(&et_hello, CLOCK_SECOND/2); rand_val = 0; blinks = 0; while(1) { PROCESS_WAIT_EVENT(); if(ev == PROCESS_EVENT_TIMER) { sd_rand_application_vector_get(&blinks,1); printf("Sensor says #%X\n", (unsigned int) blinks); etimer_reset(&et_hello); } } PROCESS_END(); }
void simble_adv_start(void) { struct ble_gap_advdata advdata = { .length = 0 }; struct ble_gap_ad_flags flags = { .payload_length = 1, .type = BLE_GAP_AD_TYPE_FLAGS, .flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE, }; simble_add_advdata(&flags, &advdata); struct ble_gap_ad_name name; uint16_t namelen = sizeof(advdata); if (sd_ble_gap_device_name_get(name.name, &namelen) != NRF_SUCCESS) namelen = 0; name.type = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME; name.payload_length = namelen; simble_add_advdata(&name, &advdata); sd_ble_gap_adv_data_set(advdata.data, advdata.length, NULL, 0); ble_gap_adv_params_t adv_params = { .type = BLE_GAP_ADV_TYPE_ADV_IND, .fp = BLE_GAP_ADV_FP_ANY, .interval = 0x400, }; sd_ble_gap_adv_start(&adv_params); onboard_led(ONBOARD_LED_ON); } static void simble_srv_tx_init(void) { uint16_t srv_handle; ble_uuid_t srv_uuid = {.type = BLE_UUID_TYPE_BLE, .uuid = 0x1804}; sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &srv_uuid, &srv_handle); ble_gatts_char_handles_t chr_handles; ble_gatts_char_md_t char_meta = {.char_props = {.read = 1}}; ble_uuid_t chr_uuid = {.type = BLE_UUID_TYPE_BLE, .uuid = 0x2a07}; ble_gatts_attr_md_t chr_attr_meta = { .vloc = BLE_GATTS_VLOC_STACK, }; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&chr_attr_meta.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&chr_attr_meta.write_perm); uint8_t tx_val = 0; ble_gatts_attr_t chr_attr = { .p_uuid = &chr_uuid, .p_attr_md = &chr_attr_meta, .init_offs = 0, .init_len = sizeof(tx_val), .max_len = sizeof(tx_val), .p_value = &tx_val, }; sd_ble_gatts_characteristic_add(srv_handle, &char_meta, &chr_attr, &chr_handles); } /* DM requires a `app_error_handler` */ void __attribute__((weak)) app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name) { app_trace_log("[simble]: err: %d, line: %d, file: %s\r\n", error_code, line_num, p_file_name); for (;;) { /* NOTHING */ } } void simble_init(const char *name) { app_trace_init(); sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, NULL); /* XXX assertion handler */ ble_enable_params_t ble_params = { #if defined(SD120) .gap_enable_params = { .role = BLE_GAP_ROLE_PERIPH, }, #endif .gatts_enable_params = { .service_changed = 1, }, }; sd_ble_enable(&ble_params); ble_gap_conn_sec_mode_t mode; BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&mode); sd_ble_gap_device_name_set(&mode, (const uint8_t *)name, strlen(name)); // flash storage pstorage_init(); simble_srv_tx_init(); } uint8_t simble_get_vendor_uuid_class(void) { ble_uuid128_t vendorid = {{0x13,0xb0,0xa0,0x71,0xfe,0x62,0x4c,0x01,0xaa,0x4d,0xd8,0x03,0,0,0x0b,0xd0}}; static uint8_t vendor_type = BLE_UUID_TYPE_UNKNOWN; if (vendor_type != BLE_UUID_TYPE_UNKNOWN) return (vendor_type); sd_ble_uuid_vs_add(&vendorid, &vendor_type); return (vendor_type); } void simble_srv_register(struct service_desc *s) { s->next = services; services = s; sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &s->uuid, &s->handle); for (int i = 0; i < s->char_count; ++i) { struct char_desc *c = &s->chars[i]; ble_gatts_attr_md_t cccd_md; memset(&cccd_md, 0, sizeof(cccd_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); cccd_md.vloc = BLE_GATTS_VLOC_STACK; int have_write = c->write_cb != NULL; ble_gatts_char_md_t char_meta = { .char_props = { .broadcast = 0, .read = 1, .write_wo_resp = have_write, .write = have_write, .notify = c->notify, .indicate = c->indicate, .auth_signed_wr = have_write, }, .p_char_user_desc = (uint8_t *)c->desc, .char_user_desc_size = strlen(c->desc), .char_user_desc_max_size = strlen(c->desc), .p_char_pf = c->format.format != 0 ? &c->format : NULL, .p_cccd_md = (c->notify || c->indicate) ? &cccd_md : NULL, }; ble_gatts_attr_md_t chr_attr_meta = { .vlen = 1, .vloc = BLE_GATTS_VLOC_STACK, .rd_auth = 1, .wr_auth = 1, }; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&chr_attr_meta.read_perm); if (have_write) BLE_GAP_CONN_SEC_MODE_SET_OPEN(&chr_attr_meta.write_perm); else BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&chr_attr_meta.write_perm); ble_gatts_attr_t chr_attr = { .p_uuid = &c->uuid, .p_attr_md = &chr_attr_meta, .init_offs = 0, .init_len = 0, .max_len = c->length, }; sd_ble_gatts_characteristic_add(s->handle, &char_meta, &chr_attr, &c->handles); } } void simble_srv_init(struct service_desc *s, uint8_t type, uint16_t id) { *s = (struct service_desc){ .uuid = {.type = type, .uuid = id}, .char_count = 0, }; }; void simble_srv_char_add(struct service_desc *s, struct char_desc *c, uint8_t type, uint16_t id, const char *desc, uint16_t length) { *c = (struct char_desc){ .uuid = { .type = type, .uuid = id }, .desc = desc, .length = length, };
/**@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 TX characteristic. * * @param[in] p_nus Nordic UART Service structure. * @param[in] p_nus_init Information needed to initialize the service. * * @return NRF_SUCCESS on success, otherwise an error code. */ static uint32_t tx_char_add(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init) { #if(ENABLE_OLD_UUID) 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; uint32_t err_code; //25ccb714-151b-4d8e-b328-38f3fb42dc2e ble_uuid128_t nus_base_uuid = {{0x73,0xa2,0x08,0x47,0x48,0x39,0xe0,0xff,0x3e,0x44,0x02,0xff,0x43,0x42,0x53,0x55}};//0xB714 memset(&char_md, 0, sizeof(char_md)); char_md.char_props.write = 1; char_md.char_props.write_wo_resp = 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; // Add custom base UUID. err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &ble_uuid.type); if (err_code != NRF_SUCCESS) { return err_code; } //ble_uuid.type = p_nus->uuid_type; ble_uuid.uuid = BLE_UUID_NUS_TX_CHARACTERISTIC; memset(&attr_md, 0, sizeof(attr_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.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 = 1; attr_char_value.init_offs = 0; attr_char_value.max_len = BLE_NUS_MAX_TX_CHAR_LEN; return sd_ble_gatts_characteristic_add(p_nus->service_handle, &char_md, &attr_char_value, &p_nus->tx_handles); #else 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; memset(&char_md, 0, sizeof(char_md)); char_md.char_props.write = 1; char_md.char_props.write_wo_resp = 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.type = p_nus->uuid_type; ble_uuid.uuid = BLE_UUID_NUS_TX_CHARACTERISTIC; memset(&attr_md, 0, sizeof(attr_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.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 = 1; attr_char_value.init_offs = 0; attr_char_value.max_len = BLE_NUS_MAX_TX_CHAR_LEN; return sd_ble_gatts_characteristic_add(p_nus->service_handle, &char_md, &attr_char_value, &p_nus->tx_handles); #if ((DEBUG_UART_EN) && (ENABLE_BLE_DEBUG)) DbgPrintf("tx_handles=%x\r\n",p_nus->service_handle); #endif #endif }
/**@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 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_rscs_init_t rscs_init; ble_bas_init_t bas_init; ble_dis_init_t dis_init; // 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_WALKING_OR_RUNNING_STATUS_BIT; rscs_init.initial_rcm.is_inst_stride_len_present = true; rscs_init.initial_rcm.is_total_distance_present = false; rscs_init.initial_rcm.is_running = false; rscs_init.initial_rcm.inst_stride_length = 0; // 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 handling Peer Manager events. * * @param[in] p_evt Peer Manager event. */ static void pm_evt_handler(pm_evt_t const * p_evt) { ret_code_t err_code; switch (p_evt->evt_id) { case PM_EVT_BONDED_PEER_CONNECTED: { NRF_LOG_INFO("Connected to a previously bonded device.\r\n"); } break; case PM_EVT_CONN_SEC_SUCCEEDED: { NRF_LOG_INFO("Connection secured. Role: %d. conn_handle: %d, Procedure: %d\r\n", ble_conn_state_role(p_evt->conn_handle), p_evt->conn_handle, p_evt->params.conn_sec_succeeded.procedure); } break; case PM_EVT_CONN_SEC_FAILED: { /* Often, when securing fails, it shouldn't be restarted, for security reasons. * Other times, it can be restarted directly. * Sometimes it can be restarted, but only after changing some Security Parameters. * Sometimes, it cannot be restarted until the link is disconnected and reconnected. * Sometimes it is impossible, to secure the link, or the peer device does not support it. * How to handle this error is highly application dependent. */ } break; case PM_EVT_CONN_SEC_CONFIG_REQ: { // Reject pairing request from an already bonded peer. pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false}; pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config); } break; case PM_EVT_STORAGE_FULL: { // Run garbage collection on the flash. err_code = fds_gc(); if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES) { // Retry. } else { APP_ERROR_CHECK(err_code); } } break; case PM_EVT_PEERS_DELETE_SUCCEEDED: { err_code = ble_advertising_start(BLE_ADV_MODE_FAST); APP_ERROR_CHECK(err_code); } break; case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED: { // The local database has likely changed, send service changed indications. pm_local_database_has_changed(); } break; case PM_EVT_PEER_DATA_UPDATE_FAILED: { // Assert. APP_ERROR_CHECK(p_evt->params.peer_data_update_failed.error); } break; case PM_EVT_PEER_DELETE_FAILED: { // Assert. APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error); } break; case PM_EVT_PEERS_DELETE_FAILED: { // Assert. APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error); } break; case PM_EVT_ERROR_UNEXPECTED: { // Assert. APP_ERROR_CHECK(p_evt->params.error_unexpected.error); } break; case PM_EVT_CONN_SEC_START: case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED: case PM_EVT_PEER_DELETE_SUCCEEDED: case PM_EVT_LOCAL_DB_CACHE_APPLIED: case PM_EVT_SERVICE_CHANGED_IND_SENT: case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED: default: break; } } /**@brief Function for the GAP initialization. * * @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the * device including the device name, appearance, and the preferred connection parameters. */ static void gap_params_init(void) { uint32_t err_code; ble_gap_conn_params_t gap_conn_params; ble_gap_conn_sec_mode_t sec_mode; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)DEVICE_NAME, strlen(DEVICE_NAME)); APP_ERROR_CHECK(err_code); /* YOUR_JOB: Use an appearance value matching the application's use case. err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_); APP_ERROR_CHECK(err_code); */ memset(&gap_conn_params, 0, sizeof(gap_conn_params)); gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL; gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL; gap_conn_params.slave_latency = SLAVE_LATENCY; gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT; err_code = sd_ble_gap_ppcp_set(&gap_conn_params); APP_ERROR_CHECK(err_code); }
/**@brief Function for initializing services that will be used by the application. * * @details Initialize the Heart Rate, Battery and Device Information services. */ static void services_init(void) { uint32_t err_code; ble_hrs_init_t hrs_init; ble_bas_init_t bas_init; ble_dis_init_t dis_init; uint8_t body_sensor_location; // Initialize Heart Rate Service. body_sensor_location = BLE_HRS_BODY_SENSOR_LOCATION_FINGER; memset(&hrs_init, 0, sizeof(hrs_init)); hrs_init.evt_handler = NULL; hrs_init.is_sensor_contact_supported = true; hrs_init.p_body_sensor_location = &body_sensor_location; // Here the sec level for the Heart Rate Service can be changed/increased. BLE_GAP_CONN_SEC_MODE_SET_OPEN(&hrs_init.hrs_hrm_attr_md.cccd_write_perm); //***************MODIFIED BLE_GAP_CONN_SEC_MODE_SET_OPEN(&hrs_init.hrs_hrm_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&hrs_init.hrs_hrm_attr_md.write_perm); //********************* BLE_GAP_CONN_SEC_MODE_SET_OPEN(&hrs_init.hrs_bsl_attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_bsl_attr_md.write_perm); err_code = ble_hrs_init(&m_hrs, &hrs_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, (char *)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); #ifdef BLE_DFU_APP_SUPPORT /** @snippet [DFU BLE Service initialization] */ ble_dfu_init_t dfus_init; // Initialize the Device Firmware Update Service. memset(&dfus_init, 0, sizeof(dfus_init)); dfus_init.evt_handler = dfu_app_on_dfu_evt; dfus_init.error_handler = NULL; //service_error_handler - Not used as only the switch from app to DFU mode is required and not full dfu service. err_code = ble_dfu_init(&m_dfus, &dfus_init); APP_ERROR_CHECK(err_code); dfu_app_reset_prepare_set(reset_prepare); /** @snippet [DFU BLE Service initialization] */ #endif // BLE_DFU_APP_SUPPORT }
/* * Function for adding the Temperature characteristic. */ static uint32_t temperature_char_add(ble_temp_t * p_temp) { 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; ble_gatts_char_pf_t char_pf; ble_gatts_attr_md_t desc_md; static const uint8_t user_desc[] = "Temperature"; // Setup CCCD attribute memset(&cccd_md, 0, sizeof(cccd_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); cccd_md.vloc = BLE_GATTS_VLOC_STACK; memset(&char_pf, 0, sizeof(char_pf)); char_pf.format = BLE_GATT_CPF_FORMAT_UTF8S; // Setup User Description attribute memset(&desc_md, 0, sizeof(desc_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.read_perm); desc_md.vloc = BLE_GATTS_VLOC_STACK; // Temp Service Characterstic memset(&char_md, 0, sizeof(char_md)); char_md.char_props.read = 1; char_md.char_props.notify = 1; char_md.p_char_user_desc = (uint8_t*) &user_desc; char_md.char_user_desc_size = sizeof(user_desc); char_md.char_user_desc_max_size = sizeof(user_desc); char_md.p_char_pf = &char_pf; char_md.p_user_desc_md = &desc_md; char_md.p_cccd_md = &cccd_md; char_md.p_sccd_md = NULL; ble_uuid.type = p_temp->uuid_type; ble_uuid.uuid = TEMP_UUID_TEMPERATURE_CHAR; memset(&attr_md, 0, sizeof(attr_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&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; 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 = NULL; return sd_ble_gatts_characteristic_add(p_temp->service_handle, &char_md, &attr_char_value, &p_temp->temperature_char_handles); }
static uint32_t ach_report_char_add(const uint8_t uuid_type) { // Report characteristic ble_gatts_char_md_t char_md; ble_gatts_attr_md_t cccd_md; ble_gatts_attr_md_t attr_md; ble_uuid_t char_uuid; ble_gatts_attr_t attr_char_value; // Controlpoint characteristic ble_gatts_char_md_t char_ctrlpt_md; ble_gatts_attr_md_t cccd_ctrlpt_md; ble_gatts_attr_md_t attr_ctrlpt_md; ble_uuid_t char_ctrlpt_uuid; ble_gatts_attr_t attr_char_ctrlpt_value; memset(&cccd_md, 0, sizeof(cccd_md)); 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); memset(&char_md, 0, sizeof(char_md)); char_md.char_props.read = 1; char_md.char_props.notify = 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 = &cccd_md; char_md.p_sccd_md = NULL; char_uuid.type = uuid_type; char_uuid.uuid = LOCAL_CHAR_UUID; memset(&attr_md, 0, sizeof(attr_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&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; memset(&attr_char_value, 0, sizeof(attr_char_value)); //lint --e{545} memset(&m_char_value, 0, APP_REPORT_CHAR_LEN); attr_char_value.p_uuid = &char_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_len = APP_REPORT_CHAR_LEN; attr_char_value.init_offs = 0; attr_char_value.max_len = APP_REPORT_CHAR_LEN; attr_char_value.p_value = m_char_value; uint32_t err_code; err_code = sd_ble_gatts_characteristic_add(m_service_handle, &char_md, &attr_char_value, &m_char_handles); if (err_code != NRF_SUCCESS) { return err_code; } memset(&cccd_ctrlpt_md, 0, sizeof(cccd_ctrlpt_md)); cccd_ctrlpt_md.vloc = BLE_GATTS_VLOC_STACK; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_ctrlpt_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_ctrlpt_md.write_perm); memset(&char_ctrlpt_md, 0, sizeof(char_ctrlpt_md)); char_ctrlpt_md.char_props.notify = 1; char_ctrlpt_md.char_props.write = 1; char_ctrlpt_md.p_char_user_desc = NULL; char_ctrlpt_md.p_char_pf = NULL; char_ctrlpt_md.p_user_desc_md = NULL; char_ctrlpt_md.p_cccd_md = &cccd_ctrlpt_md; char_ctrlpt_md.p_sccd_md = NULL; char_ctrlpt_uuid.type = uuid_type; char_ctrlpt_uuid.uuid = LOCAL_CHAR_CTRLPT_UUID; memset(&attr_ctrlpt_md, 0, sizeof(attr_ctrlpt_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_ctrlpt_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_ctrlpt_md.write_perm); attr_ctrlpt_md.vloc = BLE_GATTS_VLOC_STACK; attr_ctrlpt_md.rd_auth = 0; attr_ctrlpt_md.wr_auth = 1; attr_ctrlpt_md.vlen = 0; memset(&attr_char_ctrlpt_value, 0, sizeof(attr_char_ctrlpt_value)); //lint --e{545} memset(&m_char_ctrlpt_value, 0, APP_CTRLPT_CHAR_LEN); attr_char_ctrlpt_value.p_uuid = &char_ctrlpt_uuid; attr_char_ctrlpt_value.p_attr_md = &attr_ctrlpt_md; attr_char_ctrlpt_value.init_len = APP_CTRLPT_CHAR_LEN; attr_char_ctrlpt_value.init_offs = 0; attr_char_ctrlpt_value.max_len = APP_CTRLPT_CHAR_LEN; attr_char_ctrlpt_value.p_value = m_char_ctrlpt_value; err_code = sd_ble_gatts_characteristic_add(m_service_handle, &char_ctrlpt_md, &attr_char_ctrlpt_value, &m_char_ctrlpt_handles); return err_code; }
// init services static void services_init (void) { uint32_t err_code; // set up service uuid ble_uuid_t data_transfer_uuid; data_transfer_uuid.uuid = data_transfer_srvc_uuid16; err_code = sd_ble_uuid_vs_add(&data_transfer_uuid128, &(data_transfer_uuid.type)); APP_ERROR_CHECK(err_code); app.uuid_type = data_transfer_uuid.type; // add the custom service to the system err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &data_transfer_uuid, &(app.service_handle)); APP_ERROR_CHECK(err_code); // add test characteristic { ble_gatts_char_md_t char_md; ble_uuid_t char_uuid; ble_gatts_attr_md_t attr_md; ble_gatts_attr_t attr_char_value; uint8_t* char_name = (uint8_t*)"Test Characteristic"; // initial value data_transfer.test_char = 0x23; //memset(data_transfer.test_char, 0xBA, 500); // characteristic settings memset(&char_md, 0, sizeof(char_md)); char_md.char_props.read = true; char_md.char_props.write = true; char_md.p_char_user_desc = char_name; char_md.char_user_desc_max_size = sizeof(char_name); char_md.char_user_desc_size = sizeof(char_name); // characteristic uuid char_uuid.type = app.uuid_type; char_uuid.uuid = test_char_uuid16; // attribute metadata memset(&attr_md, 0, sizeof(attr_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); //BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); attr_md.vloc = BLE_GATTS_VLOC_USER; attr_md.rd_auth = 0; attr_md.wr_auth = 0; attr_md.vlen = 1; // gatt attributes memset(&attr_char_value, 0, sizeof(attr_char_value)); attr_char_value.p_uuid = &char_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.init_offs = 0; attr_char_value.init_len = 1; attr_char_value.max_len = 1; attr_char_value.p_value = (uint8_t*)&data_transfer.test_char; //attr_char_value.init_len = 500; //attr_char_value.max_len = 500; //attr_char_value.p_value = (uint8_t*)data_transfer.test_char; err_code = sd_ble_gatts_characteristic_add(app.service_handle, &char_md, &attr_char_value, &data_transfer.test_char_handles); APP_ERROR_CHECK(err_code); } }
static uint32_t mesh_md_char_add(mesh_metadata_char_t* metadata) { /* cccd for metadata char */ ble_gatts_attr_md_t cccd_md; memset(&cccd_md, 0, sizeof(cccd_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); cccd_md.vloc = BLE_GATTS_VLOC_STACK; /* metadata char */ ble_gatts_char_md_t ble_char_md; memset(&ble_char_md, 0, sizeof(ble_char_md)); ble_char_md.char_props.read = 1; ble_char_md.char_props.notify = 1; ble_char_md.p_char_pf = NULL; ble_char_md.p_cccd_md = &cccd_md; ble_char_md.p_char_user_desc = NULL; ble_char_md.p_user_desc_md = NULL; /* ATT metadata */ ble_gatts_attr_md_t ble_attr_md; memset(&ble_attr_md, 0, sizeof(ble_attr_md)); ble_attr_md.read_perm.lv = 1; ble_attr_md.read_perm.sm = 1; ble_attr_md.write_perm.lv = 1; ble_attr_md.write_perm.sm = 1; ble_attr_md.rd_auth = 0; ble_attr_md.wr_auth = 0; ble_attr_md.vlen = 0; ble_attr_md.vloc = BLE_GATTS_VLOC_STACK; /* ble characteristic UUID */ ble_uuid_t ble_uuid; ble_uuid.type = m_mesh_base_uuid_type; ble_uuid.uuid = MESH_MD_CHAR_UUID; /* metadata contents */ uint8_t value_array[MESH_MD_CHAR_LEN]; memcpy(&value_array[MESH_MD_CHAR_AA_OFFSET], &metadata->mesh_access_addr, sizeof(metadata->mesh_access_addr)); memcpy(&value_array[MESH_MD_CHAR_ADV_INT_OFFSET], &metadata->mesh_interval_min_ms, sizeof(metadata->mesh_interval_min_ms)); memcpy(&value_array[MESH_MD_CHAR_CH_OFFSET], &metadata->mesh_channel, sizeof(metadata->mesh_channel)); /* ble attribute */ ble_gatts_attr_t ble_attr; memset(&ble_attr, 0, sizeof(ble_attr)); ble_attr.init_len = MESH_MD_CHAR_LEN; ble_attr.init_offs = 0; ble_attr.max_len = MESH_MD_CHAR_LEN; ble_attr.p_uuid = &ble_uuid; ble_attr.p_value = value_array; ble_attr.p_attr_md = &ble_attr_md; /* add characteristic */ uint32_t error_code = sd_ble_gatts_characteristic_add( m_mesh_service.service_handle, &ble_char_md, &ble_attr, &m_mesh_service.ble_md_char_handles); if (error_code != NRF_SUCCESS) { return NRF_ERROR_INTERNAL; } return NRF_SUCCESS; }
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 }
static uint32_t mesh_value_char_add(void) { /* cccd for value char */ ble_gatts_attr_md_t cccd_md; memset(&cccd_md, 0, sizeof(cccd_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); cccd_md.vloc = BLE_GATTS_VLOC_STACK; /* BLE GATT metadata */ ble_gatts_char_md_t ble_char_md; memset(&ble_char_md, 0, sizeof(ble_char_md)); ble_char_md.char_props.read = 1; ble_char_md.char_props.write_wo_resp = 1; ble_char_md.char_props.notify = 1; ble_char_md.p_cccd_md = &cccd_md; ble_char_md.p_sccd_md = NULL; ble_char_md.p_char_user_desc = NULL; ble_char_md.p_user_desc_md = NULL; /* ATT metadata */ ble_gatts_attr_md_t ble_attr_md; memset(&ble_attr_md, 0, sizeof(ble_attr_md)); /* No security is required */ ble_attr_md.read_perm.lv = 1; ble_attr_md.read_perm.sm = 1; ble_attr_md.write_perm.lv = 1; ble_attr_md.write_perm.sm = 1; ble_attr_md.vloc = BLE_GATTS_VLOC_STACK; ble_attr_md.rd_auth = 0; ble_attr_md.wr_auth = 0; ble_attr_md.vlen = 1; /* ble characteristic UUID */ ble_uuid_t ble_uuid; ble_uuid.type = m_mesh_base_uuid_type; ble_uuid.uuid = MESH_VALUE_CHAR_UUID; /* ble attribute */ ble_gatts_attr_t ble_attr; uint8_t default_value = 0; memset(&ble_attr, 0, sizeof(ble_attr)); ble_attr.init_len = 1; ble_attr.init_offs = 0; ble_attr.max_len = sizeof(mesh_gatt_evt_t); ble_attr.p_attr_md = &ble_attr_md; ble_attr.p_uuid = &ble_uuid; ble_attr.p_value = &default_value; /* add to service */ uint32_t error_code = sd_ble_gatts_characteristic_add( m_mesh_service.service_handle, &ble_char_md, &ble_attr, &m_mesh_service.ble_val_char_handles); if (error_code != NRF_SUCCESS) { return NRF_ERROR_INTERNAL; } return NRF_SUCCESS; }
/**@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; }
uint32_t characteristic_add(uint16_t service_handle, ble_add_char_params_t * p_char_props, ble_gatts_char_handles_t * p_char_handle) { ble_gatts_char_md_t char_md; ble_gatts_attr_t attr_char_value; ble_uuid_t char_uuid; ble_gatts_attr_md_t attr_md; ble_gatts_attr_md_t user_descr_attr_md; ble_gatts_attr_md_t cccd_md; if (p_char_props->uuid_type == 0) { char_uuid.type = BLE_UUID_TYPE_BLE; } else { char_uuid.type = p_char_props->uuid_type; } char_uuid.uuid = p_char_props->uuid; memset(&attr_md, 0, sizeof(ble_gatts_attr_md_t)); set_security_req(p_char_props->read_access, &attr_md.read_perm); set_security_req(p_char_props->write_access, & attr_md.write_perm); attr_md.rd_auth = (p_char_props->is_defered_read ? 1 : 0); attr_md.wr_auth = (p_char_props->is_defered_write ? 1 : 0); attr_md.vlen = (p_char_props->is_var_len ? 1 : 0); attr_md.vloc = (p_char_props->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK); memset(&char_md, 0, sizeof(ble_gatts_char_md_t)); if ((p_char_props->char_props.notify == 1)||(p_char_props->char_props.indicate == 1)) { memset(&cccd_md, 0, sizeof(cccd_md)); set_security_req(p_char_props->cccd_write_access, &cccd_md.write_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); cccd_md.vloc = BLE_GATTS_VLOC_STACK; char_md.p_cccd_md = &cccd_md; } char_md.char_props = p_char_props->char_props; memset(&attr_char_value, 0, sizeof(ble_gatts_attr_t)); attr_char_value.p_uuid = &char_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.max_len = p_char_props->max_len; if (p_char_props->p_init_value != NULL) { attr_char_value.init_len = p_char_props->init_len; attr_char_value.p_value = p_char_props->p_init_value; } if (p_char_props->p_user_descr != NULL) { memset(&user_descr_attr_md, 0, sizeof(ble_gatts_attr_md_t)); char_md.char_user_desc_max_size = p_char_props->p_user_descr->max_size; char_md.char_user_desc_size = p_char_props->p_user_descr->size; char_md.p_char_user_desc = p_char_props->p_user_descr->p_char_user_desc; char_md.p_user_desc_md = &user_descr_attr_md; set_security_req(p_char_props->p_user_descr->read_access, &user_descr_attr_md.read_perm); set_security_req(p_char_props->p_user_descr->write_access, &user_descr_attr_md.write_perm); user_descr_attr_md.rd_auth = (p_char_props->p_user_descr->is_defered_read ? 1 : 0); user_descr_attr_md.wr_auth = (p_char_props->p_user_descr->is_defered_write ? 1 : 0); user_descr_attr_md.vlen = (p_char_props->p_user_descr->is_var_len ? 1 : 0); user_descr_attr_md.vloc = (p_char_props->p_user_descr->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK); } if (p_char_props->p_presentation_format != NULL) { char_md.p_char_pf = p_char_props->p_presentation_format; } return sd_ble_gatts_characteristic_add(service_handle, &char_md, &attr_char_value, p_char_handle); }
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; }
/**@brief Function for initializing services that will be used by the application. * * @details Initialize the Heart Rate, Battery and Device Information services. */ static void services_init(void) { uint32_t err_code; ble_bas_init_t bas_init; ble_dis_init_t dis_init; // 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); if (err_code == NRF_SUCCESS) debug_printf("Battery service initialised!\r\n"); else { debug_printf("Error with initialising battery service.\r\n"); APP_ERROR_CHECK(err_code); } // Initialize Device Information Service. memset(&dis_init, 0, sizeof(dis_init)); 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); if (err_code == NRF_SUCCESS) debug_printf("Device Information service initialised!\r\n"); else { debug_printf("Error with initialising device information service.\r\n"); APP_ERROR_CHECK(err_code); } // Initialize CCH custom Service. cch_service_init(&m_cch_service); #ifdef BLE_DFU_APP_SUPPORT /** @snippet [DFU BLE Service initialization] */ ble_dfu_init_t dfus_init; // Initialize the Device Firmware Update Service. memset(&dfus_init, 0, sizeof(dfus_init)); dfus_init.evt_handler = dfu_app_on_dfu_evt; dfus_init.error_handler = NULL; dfus_init.evt_handler = dfu_app_on_dfu_evt; dfus_init.revision = DFU_REVISION; err_code = ble_dfu_init(&m_dfus, &dfus_init); APP_ERROR_CHECK(err_code); dfu_app_reset_prepare_set(reset_prepare); dfu_app_dm_appl_instance_set(m_app_handle); /** @snippet [DFU BLE Service initialization] */ #endif // BLE_DFU_APP_SUPPORT }
uint32_t ble_crazyflies_init(uint8_t uuidType) { uint32_t err; ble_uuid_t service_uuid; ble_uuid_t crtp_uuid; uint16_t service_handle; uint8_t initial_value = 0xFF; ble_gatts_attr_md_t cccd_md; service_uuid.uuid = UUID_CRAZYFLIE_SERVICE; service_uuid.type = uuidType; err = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &service_uuid, &service_handle); ERROR_CHECK(err); /* Bidirectional full-length CRTP characteristic */ memset(&cccd_md, 0, sizeof(cccd_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); cccd_md.vloc = BLE_GATTS_VLOC_STACK; crtp_md.p_cccd_md = &cccd_md; crtp_uuid.type = uuidType; crtp_uuid.uuid = UUID_CRAZYFLIE_CRTP; crtp_attr.p_uuid = &crtp_uuid; crtp_attr.p_value = &initial_value; crtp_attr.init_len = 1; err = sd_ble_gatts_characteristic_add(service_handle, &crtp_md, &crtp_attr, &crtp_handle); ERROR_CHECK(err); /* Uplink (nrf receives) segmented CRTP characteristic */ memset(&cccd_md, 0, sizeof(cccd_md)); //BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); //BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); //cccd_md.vloc = BLE_GATTS_VLOC_STACK; crtp_md.p_cccd_md = NULL; //&cccd_md; crtp_uuid.type = uuidType; crtp_uuid.uuid = UUID_CRAZYFLIE_CRTP_UP; crtpupdown_attr.p_uuid = &crtp_uuid; crtpupdown_attr.p_value = &initial_value; crtpupdown_attr.init_len = 1; err = sd_ble_gatts_characteristic_add(service_handle, &crtpup_md, &crtpupdown_attr, &crtpup_handle); ERROR_CHECK(err); /* Downlink (nrf Sends) segmented CRTP characteristic */ memset(&cccd_md, 0, sizeof(cccd_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm); cccd_md.vloc = BLE_GATTS_VLOC_STACK; crtpdown_md.p_cccd_md = &cccd_md; crtp_uuid.type = uuidType; crtp_uuid.uuid = UUID_CRAZYFLIE_CRTP_DOWN; crtpupdown_attr.p_uuid = &crtp_uuid; crtpupdown_attr.p_value = &initial_value; crtpupdown_attr.init_len = 1; err = sd_ble_gatts_characteristic_add(service_handle, &crtpdown_md, &crtpupdown_attr, &crtpdown_handle); ERROR_CHECK(err); return NRF_SUCCESS; }
uint32_t ble_sc_ctrlpt_init(ble_sc_ctrlpt_t * p_sc_ctrlpt, const ble_cs_ctrlpt_init_t * p_sc_ctrlpt_init) { 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; p_sc_ctrlpt->conn_handle = BLE_CONN_HANDLE_INVALID; p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS; p_sc_ctrlpt->size_list_supported_locations = p_sc_ctrlpt_init->size_list_supported_locations; if ((p_sc_ctrlpt_init->size_list_supported_locations != 0) && (p_sc_ctrlpt_init->list_supported_locations != NULL)) { memcpy(p_sc_ctrlpt->list_supported_locations, p_sc_ctrlpt_init->list_supported_locations, p_sc_ctrlpt->size_list_supported_locations * sizeof(ble_sensor_location_t)); } p_sc_ctrlpt->service_handle = p_sc_ctrlpt_init->service_handle; p_sc_ctrlpt->evt_handler = p_sc_ctrlpt_init->evt_handler; p_sc_ctrlpt->supported_functions = p_sc_ctrlpt_init->supported_functions; p_sc_ctrlpt->sensor_location_handle = p_sc_ctrlpt_init->sensor_location_handle; p_sc_ctrlpt->error_handler = p_sc_ctrlpt_init->error_handler; memset(&cccd_md, 0, sizeof(cccd_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); cccd_md.write_perm = p_sc_ctrlpt_init->sc_ctrlpt_attr_md.cccd_write_perm; cccd_md.vloc = BLE_GATTS_VLOC_STACK; memset(&char_md, 0, sizeof(char_md)); char_md.char_props.indicate = 1; char_md.char_props.write = 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 = &cccd_md; char_md.p_sccd_md = NULL; BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_SC_CTRLPT_CHAR); memset(&attr_md, 0, sizeof(attr_md)); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm); attr_md.write_perm = p_sc_ctrlpt_init->sc_ctrlpt_attr_md.write_perm; attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.rd_auth = 0; attr_md.wr_auth = 1; 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 = BLE_SC_CTRLPT_MAX_LEN; attr_char_value.p_value = 0; return sd_ble_gatts_characteristic_add(p_sc_ctrlpt->service_handle, &char_md, &attr_char_value, &p_sc_ctrlpt->sc_ctrlpt_handles); }
static uint32_t addCharPHYSEN(ble_pss_t * p_pss, const ble_pss_init_t * p_pss_init) { /// add phy sensor characteristics ble_gatts_char_md_t char_md; ble_gatts_char_md_t char_md_w; ble_gatts_attr_md_t cccd_md; ble_gatts_attr_t attr_char_value; ble_gatts_attr_t attr_char_value_w; ble_uuid_t ble_uuid; ble_uuid_t ble_uuid_w; ble_gatts_attr_md_t attr_md; ble_gatts_attr_md_t attr_md_w; char user_desc[] = "Physics sensor"; memset(&cccd_md, 0, sizeof(cccd_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.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 = 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 = &cccd_md; char_md.p_sccd_md = NULL; char_md.p_char_user_desc = (uint8_t *) user_desc; char_md.char_user_desc_size = strlen(user_desc); char_md.char_user_desc_max_size = strlen(user_desc); memset(&char_md_w, 0, sizeof(char_md_w)); char_md_w.char_props.write = 1; char_md_w.p_char_user_desc = NULL; char_md_w.p_char_pf = NULL; char_md_w.p_user_desc_md = NULL; char_md_w.p_cccd_md = &cccd_md; char_md_w.p_sccd_md = NULL; char_md_w.p_char_user_desc = (uint8_t *) user_desc; char_md_w.char_user_desc_size = strlen(user_desc); char_md_w.char_user_desc_max_size = strlen(user_desc); ble_uuid.type = p_pss->uuid_type; ble_uuid.uuid = PHY_SENSOR_DATA_CHAR; ble_uuid_w.type = p_pss->uuid_type; ble_uuid_w.uuid = PHY_SENSOR_WRITE_CHAR; memset(&attr_md, 0, sizeof(attr_md)); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&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; memset(&attr_md_w, 0, sizeof(attr_md_w)); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md_w.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md_w.write_perm); attr_md_w.vloc = BLE_GATTS_VLOC_STACK; attr_md_w.rd_auth = 0; attr_md_w.wr_auth = 0; attr_md_w.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 = (SENSOR_ROW_SIZE); attr_char_value.init_offs = 0; attr_char_value.max_len = (SENSOR_ROW_SIZE); attr_char_value.p_value = NULL; memset(&attr_char_value_w, 0, sizeof(attr_char_value_w)); attr_char_value_w.p_uuid = &ble_uuid_w; attr_char_value_w.p_attr_md = &attr_md_w; attr_char_value_w.init_len = (SENSOR_ROW_SIZE); attr_char_value_w.init_offs = 0; attr_char_value_w.max_len = (SENSOR_ROW_SIZE); attr_char_value_w.p_value = NULL; sd_ble_gatts_characteristic_add(p_pss->service_handle, &char_md, &attr_char_value, &p_pss->phy_sen_level_handles); return sd_ble_gatts_characteristic_add(p_pss->service_handle_w, &char_md_w, &attr_char_value_w, &p_pss->phy_sen_level_handles_w) ; }
static uint32_t ble_stack_init(bool init_softdevice) { uint32_t err_code; nrf_clock_lf_cfg_t clock_lf_cfg = { .source = NRF_CLOCK_LF_SRC_RC, .rc_ctiv = 16, // recommended for nRF52 .rc_temp_ctiv = 2, // recommended for nRF52 .xtal_accuracy = 0}; if (init_softdevice) { err_code = nrf_dfu_mbr_init_sd(); VERIFY_SUCCESS(err_code); } NRF_LOG_INFO("vector table: 0x%08x\r\n", BOOTLOADER_START_ADDR); err_code = sd_softdevice_vector_table_base_set(BOOTLOADER_START_ADDR); VERIFY_SUCCESS(err_code); SOFTDEVICE_HANDLER_APPSH_INIT(&clock_lf_cfg, true); ble_enable_params_t ble_enable_params; // Only one connection as a central is used when performing dfu. err_code = softdevice_enable_get_default_config(1, 1, &ble_enable_params); VERIFY_SUCCESS(err_code); #if (NRF_SD_BLE_API_VERSION == 3) ble_enable_params.gatt_enable_params.att_mtu = NRF_BLE_MAX_MTU_SIZE; #endif // Enable BLE stack. err_code = softdevice_enable(&ble_enable_params); return err_code; } /**@brief Function for adding DFU Packet characteristic to the BLE Stack. * * @param[in] p_dfu DFU Service structure. * * @return NRF_SUCCESS on success. Otherwise an error code. */ static uint32_t dfu_pkt_char_add(ble_dfu_t * const p_dfu) { ble_gatts_char_md_t char_md = {{0}}; ble_gatts_attr_t attr_char_value = {0}; ble_gatts_attr_md_t attr_md = {{0}}; ble_uuid_t char_uuid; char_md.char_props.write_wo_resp = 1; char_uuid.type = p_dfu->uuid_type; char_uuid.uuid = BLE_DFU_PKT_CHAR_UUID; BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm); BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); attr_md.vloc = BLE_GATTS_VLOC_STACK; attr_md.vlen = 1; attr_char_value.p_uuid = &char_uuid; attr_char_value.p_attr_md = &attr_md; attr_char_value.max_len = MAX_DFU_PKT_LEN; attr_char_value.p_value = NULL; return sd_ble_gatts_characteristic_add(p_dfu->service_handle, &char_md, &attr_char_value, &p_dfu->dfu_pkt_handles); }