/** * @brief Start the service. * Here we wish to start the service which means that we will respond to partner requests about it. * Starting a service also means that we can create the corresponding characteristics. * @return Start the service. */ void BLEService::start() { // We ask the BLE runtime to start the service and then create each of the characteristics. // We start the service through its local handle which was returned in the ESP_GATTS_CREATE_EVT event // obtained as a result of calling esp_ble_gatts_create_service(). // ESP_LOGD(LOG_TAG, ">> start(): Starting service (esp_ble_gatts_start_service): %s", toString().c_str()); if (m_handle == NULL_HANDLE) { ESP_LOGE(LOG_TAG, "<< !!! We attempted to start a service but don't know its handle!"); return; } BLECharacteristic *pCharacteristic = m_characteristicMap.getFirst(); while(pCharacteristic != nullptr) { m_lastCreatedCharacteristic = pCharacteristic; pCharacteristic->executeCreate(this); pCharacteristic = m_characteristicMap.getNext(); } // Start each of the characteristics ... these are found in the m_characteristicMap. m_semaphoreStartEvt.take("start"); esp_err_t errRc = ::esp_ble_gatts_start_service(m_handle); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_start_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); return; } m_semaphoreStartEvt.wait("start"); ESP_LOGD(LOG_TAG, "<< start()"); } // start
void BLEPeripheral::handleGapEvent(ble_client_gap_event_t event, struct ble_gap_event *event_data) { if (BLE_CLIENT_GAP_EVENT_CONNECTED == event) { _state = BLE_PERIPH_STATE_CONNECTED; _central.setAddress(event_data->connected.peer_bda); if (_event_handlers[BLEConnected]) { _event_handlers[BLEConnected](_central); } } else if (BLE_CLIENT_GAP_EVENT_DISCONNECTED == event) { for (int i = 0; i < _num_attributes; i++) { BLEAttribute* attribute = _attributes[i]; if (attribute->type() == BLETypeCharacteristic) { BLECharacteristic* characteristic = (BLECharacteristic*)attribute; characteristic->setCccdValue(_central, 0x0000); // reset CCCD } } if (_event_handlers[BLEDisconnected]) _event_handlers[BLEDisconnected](_central); _state = BLE_PERIPH_STATE_READY; _central.clearAddress(); _startAdvertising(); } else if (BLE_CLIENT_GAP_EVENT_CONN_TIMEOUT == event) { _state = BLE_PERIPH_STATE_READY; _startAdvertising(); } }
void BLEPeripheral::handleGattsEvent(ble_client_gatts_event_t event, struct ble_gatts_evt_msg *event_data) { if (BLE_CLIENT_GATTS_EVENT_WRITE == event) { uint16_t handle = event_data->wr.attr_handle; for (int i = 0; i < _num_attributes; i++) { BLEAttribute* attribute = _attributes[i]; if (attribute->type() != BLETypeCharacteristic) { continue; } BLECharacteristic* characteristic = (BLECharacteristic*)attribute; if (characteristic->valueHandle() == handle) { characteristic->setValue(_central, event_data->wr.data, event_data->wr.len); break; } else if (characteristic->cccdHandle() == handle) { uint16_t cccdValue = 0; memcpy(&cccdValue, event_data->wr.data, event_data->wr.len); characteristic->setCccdValue(_central, cccdValue); break; } } } }
void bleConfigChangeHandler(BLECentral& central, BLECharacteristic& characteristic) { // config characteristic event handler DEBUG_PRINTLN("config change event"); handle( (uint8_t*) characteristic.value(), characteristic.valueLength()); DEBUG_PRINT("Pin: "); DEBUG_PRINTLN(pin); }
void setup() { wait_for_serial(); // set the UUID for the service this peripheral advertises: blePeripheral.setAdvertisedServiceUuid(whistlepunkService.uuid()); // add service and characteristics blePeripheral.addAttribute(whistlepunkService); blePeripheral.addAttribute(valueCharacteristic); blePeripheral.addAttribute(configCharacteristic); blePeripheral.addAttribute(versionCharacteristic); versionCharacteristic.setValue(version); // assign event handlers for connected, disconnected to peripheral blePeripheral.setEventHandler(BLEConnected, blePeripheralConnectHandler); blePeripheral.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler); valueCharacteristic.setEventHandler(BLESubscribed, bleNotificationSubscribeHandler); valueCharacteristic.setEventHandler(BLEUnsubscribed, bleNotificationUnsubscribeHandler); configCharacteristic.setEventHandler(BLEWritten, bleConfigChangeHandler); // advertise the service blePeripheral.begin(); while (true) { blePeripheral.poll(); if (blePeripheral.haveAddress()) { have_address = true; address = blePeripheral.getAddress(); sprintf(BleLongName, "Sci%02x%02x", address[0], address[1]); blePeripheral.setLocalName(BleLongName); blePeripheral.begin(); break; } } }
void setup() { wait_for_serial(); // set the local name peripheral advertises blePeripheral.setLocalName("Initial"); // set the UUID for the service this peripheral advertises: blePeripheral.setAdvertisedServiceUuid(whistlepunkService.uuid()); // add service and characteristics blePeripheral.addAttribute(whistlepunkService); blePeripheral.addAttribute(valueCharacteristic); blePeripheral.addAttribute(configCharacteristic); blePeripheral.addAttribute(versionCharacteristic); versionCharacteristic.setValue(version); // assign event handlers for connected, disconnected to peripheral blePeripheral.setEventHandler(BLEConnected, blePeripheralConnectHandler); blePeripheral.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler); valueCharacteristic.setEventHandler(BLESubscribed, bleNotificationSubscribeHandler); valueCharacteristic.setEventHandler(BLEUnsubscribed, bleNotificationUnsubscribeHandler); configCharacteristic.setEventHandler(BLEWritten, bleConfigChangeHandler); ble_addr_t _local_bda; char _device_name[BLE_MAX_DEVICE_NAME+1]; ble_client_get_factory_config(&_local_bda, _device_name); sprintf(BleLongName, "Sci%02x%02x", _local_bda.addr[0], _local_bda.addr[1]); DEBUG_PRINT("Address is: "); DEBUG_PRINTLN(BleLongName); blePeripheral.setLocalName(BleLongName); // advertise the service blePeripheral.begin(); }
void BLEHID::sendData(BLECharacteristic& characteristic, unsigned char data[], unsigned char length) { // wait until we can notify while(!characteristic.canNotify()) { BLEHIDPeripheral::instance()->poll(); } characteristic.setValue(data, length); }
void BLEPeripheral::begin() { unsigned char advertisementData[20]; unsigned char scanData[20]; unsigned char advertisementDataLength = 0; unsigned char scanDataLength = 0; if (this->_advertisedServiceUuid){ BLEUuid advertisedServiceUuid = BLEUuid(this->_advertisedServiceUuid); unsigned char advertisedServiceUuidLength = advertisedServiceUuid.length(); advertisementDataLength = 2 + advertisedServiceUuidLength; advertisementData[0] = (advertisedServiceUuidLength > 2) ? 0x06 : 0x02; advertisementData[1] = advertisedServiceUuidLength; memcpy(&advertisementData[2], advertisedServiceUuid.data(), advertisedServiceUuidLength); } else if (this->_manufacturerData && this->_manufacturerDataLength > 0) { if (this->_manufacturerDataLength > sizeof(advertisementData)) { this->_manufacturerDataLength = sizeof(advertisementData); } advertisementDataLength = 2 + this->_manufacturerDataLength; advertisementData[0] = 0xff; advertisementData[1] = this->_manufacturerDataLength; memcpy(&advertisementData[2], this->_manufacturerData, this->_manufacturerDataLength); } if (this->_localName){ unsigned char originalLocalNameLength = strlen(this->_localName); unsigned char localNameLength = originalLocalNameLength; if (localNameLength > sizeof(scanData)) { localNameLength = sizeof(scanData); } scanDataLength = 2 + localNameLength; scanData[0] = (originalLocalNameLength > sizeof(scanData)) ? 0x08 : 0x09; scanData[1] = localNameLength; memcpy(&scanData[2], this->_localName, localNameLength); } for (int i = 0; i < this->_numAttributes; i++) { BLEAttribute* attribute = this->_attributes[i]; if (attribute->type() == BLETypeCharacteristic) { BLECharacteristic* characteristic = (BLECharacteristic*)attribute; characteristic->setValueChangeListener(*this); } } this->_nRF8001.begin(advertisementData, advertisementDataLength, scanData, scanDataLength, this->_attributes, this->_numAttributes); this->_nRF8001.requestAddress(); }
bool BLEPeripheral::begin() { BleStatus status; status = _init(); if (status != BLE_STATUS_SUCCESS) { return false; } /* Populate advertising data */ _advDataInit(); status = ble_client_gap_wr_adv_data(_adv_data, _adv_data_len); if (BLE_STATUS_SUCCESS != status) { return false; } uint16_t lastServiceHandle = 0; for (int i = 0; i < _num_attributes; i++) { BLEAttribute* attribute = _attributes[i]; BLEAttributeType type = attribute->type(); bool addResult = false; if (BLETypeService == type) { BLEService* service = (BLEService*)attribute; addResult = service->add(); lastServiceHandle = service->handle(); } else if (BLETypeCharacteristic == type) { BLECharacteristic* characteristic = (BLECharacteristic*)attribute; addResult = characteristic->add(lastServiceHandle); } else if (BLETypeDescriptor == type) { BLEDescriptor *descriptor = (BLEDescriptor*)attribute; if (strcmp(descriptor->uuid(), "2901") == 0 || strcmp(descriptor->uuid(), "2902") == 0 || strcmp(descriptor->uuid(), "2903") == 0 || strcmp(descriptor->uuid(), "2904") == 0) { continue; // skip } addResult = descriptor->add(lastServiceHandle); } if (!addResult) { return false; } } return (_startAdvertising() == BLE_STATUS_SUCCESS); }
void loop() { if (Serial) { if (!serialConnected) { serialConnected = true; DEBUG_PRINT(F("LongName: ")); DEBUG_PRINTLN(BleLongName); } } else { if (serialConnected) serialConnected = false; } // poll peripheral blePeripheral.poll(); if (valueCharacteristic.subscribed()) { int sensorValue = 0; if (pin_type == ANALOG) { sensorValue = analogRead(pin); } else if (pin_type == DIGITAL) { sensorValue = digitalRead(pin); } else { sensorValue = 666; } send_data(valueCharacteristic, millis(), sensorValue); } #ifdef GOOSCI_DEVELOPER_MODE heartbeat(); #endif }
static void run() { BLEDevice::init("MYDEVICE"); BLEServer *pServer = BLEDevice::createServer(); BLEService *pService = pServer->createService(BLEUUID(SERVICE_UUID_BIN, 16, true)); BLECharacteristic *pCharacteristic = pService->createCharacteristic( BLEUUID(CHARACTERISTIC_UUID), BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE ); pCharacteristic->setCallbacks(new MyCallbackHandler()); pCharacteristic->setValue("Hello World"); pService->start(); BLEAdvertising *pAdvertising = pServer->getAdvertising(); pAdvertising->start(); }
bool nRF51822::updateCharacteristicValue(BLECharacteristic& characteristic) { bool success = true; for (int i = 0; i < this->_numLocalCharacteristics; i++) { struct localCharacteristicInfo* localCharacteristicInfo = &this->_localCharacteristicInfo[i]; if (localCharacteristicInfo->characteristic == &characteristic) { if (&characteristic == this->_broadcastCharacteristic) { this->broadcastCharacteristic(characteristic); } uint16_t valueLength = characteristic.valueLength(); sd_ble_gatts_value_set(localCharacteristicInfo->handles.value_handle, 0, &valueLength, characteristic.value()); ble_gatts_hvx_params_t hvxParams; memset(&hvxParams, 0, sizeof(hvxParams)); hvxParams.handle = localCharacteristicInfo->handles.value_handle; hvxParams.offset = 0; hvxParams.p_data = NULL; hvxParams.p_len = &valueLength; if (localCharacteristicInfo->notifySubscribed) { if (this->_txBufferCount > 0) { this->_txBufferCount--; hvxParams.type = BLE_GATT_HVX_NOTIFICATION; sd_ble_gatts_hvx(this->_connectionHandle, &hvxParams); } else { success = false; } } if (localCharacteristicInfo->indicateSubscribed) { if (this->_txBufferCount > 0) { this->_txBufferCount--; hvxParams.type = BLE_GATT_HVX_INDICATION; sd_ble_gatts_hvx(this->_connectionHandle, &hvxParams); } else { success = false; } } } } return success; }
void updateHeartRate() { /* Read the current voltage level on the A0 analog input pin. This is used here to simulate the heart rate's measurement. */ int heartRateMeasurement = analogRead(A0); int heartRate = map(heartRateMeasurement, 0, 1023, 0, 100); if (heartRate != oldHeartRate) { // if the heart rate has changed Serial.print("Heart Rate is now: "); // print it Serial.println(heartRate); const unsigned char heartRateCharArray[2] = { 0, (char)heartRate }; heartRateChar.setValue(heartRateCharArray, 2); // and update the heart rate measurement characteristic oldHeartRate = heartRate; // save the level for next comparison } }
bool nRF51822::broadcastCharacteristic(BLECharacteristic& characteristic) { bool success = false; for (int i = 0; i < this->_numLocalCharacteristics; i++) { struct localCharacteristicInfo* localCharacteristicInfo = &this->_localCharacteristicInfo[i]; if (localCharacteristicInfo->characteristic == &characteristic) { if (characteristic.properties() & BLEBroadcast && localCharacteristicInfo->service) { unsigned char advData[31]; unsigned char advDataLen = this->_advDataLen; // copy the existing advertisement data memcpy(advData, this->_advData, advDataLen); advDataLen += (4 + characteristic.valueLength()); if (advDataLen <= 31) { BLEUuid uuid = BLEUuid(localCharacteristicInfo->service->uuid()); advData[this->_advDataLen + 0] = 3 + characteristic.valueLength(); advData[this->_advDataLen + 1] = 0x16; memcpy(&advData[this->_advDataLen + 2], uuid.data(), 2); memcpy(&advData[this->_advDataLen + 4], characteristic.value(), characteristic.valueLength()); sd_ble_gap_adv_data_set(advData, advDataLen, NULL, 0); // update advertisement data success = true; this->_broadcastCharacteristic = &characteristic; } } break; } } return success; }
BLECharacteristicImp::BLECharacteristicImp(BLECharacteristic& characteristic, const BLEDevice& bledevice): BLEAttribute(characteristic.uuid(), BLETypeCharacteristic), _value_length(0), _value_buffer(NULL), _value_updated(false), _value_handle(0), _cccd_handle(0), _attr_chrc_value(NULL), _attr_cccd(NULL), _subscribed(false), _reading(false), _ble_device() { unsigned char properties = characteristic._properties; _value_size = characteristic._value_size; _value = (unsigned char*)malloc(_value_size); if (_value == NULL) { errno = ENOMEM; } if (_value_size > BLE_MAX_ATTR_DATA_LEN) { _value_buffer = (unsigned char*)malloc(_value_size); } memset(&_ccc_cfg, 0, sizeof(_ccc_cfg)); memset(&_ccc_value, 0, sizeof(_ccc_value)); memset(&_gatt_chrc, 0, sizeof(_gatt_chrc)); memset(&_sub_params, 0, sizeof(_sub_params)); memset(&_discover_params, 0, sizeof(_discover_params)); _ccc_value.cfg = &_ccc_cfg; _ccc_value.cfg_len = 1; if (BLERead & properties) { _gatt_chrc.properties |= BT_GATT_CHRC_READ; } if (BLEWrite & properties) { _gatt_chrc.properties |= BT_GATT_CHRC_WRITE; } if (BLEWriteWithoutResponse & properties) { _gatt_chrc.properties |= BT_GATT_CHRC_WRITE_WITHOUT_RESP; } if (BLENotify & properties) { _gatt_chrc.properties |= BT_GATT_CHRC_NOTIFY; _sub_params.value |= BT_GATT_CCC_NOTIFY; } if (BLEIndicate & properties) { _gatt_chrc.properties |= BT_GATT_CHRC_INDICATE; _sub_params.value |= BT_GATT_CCC_INDICATE; } _gatt_chrc.uuid = (bt_uuid_t*)this->bt_uuid();//&_characteristic_uuid;//this->uuid(); memcpy(_event_handlers, characteristic._event_handlers, sizeof(_event_handlers)); memcpy(_oldevent_handlers, characteristic._oldevent_handlers, sizeof(_oldevent_handlers)); _sub_params.notify = profile_notify_process; if (NULL != characteristic._value) { memcpy(_value, characteristic._value, _value_size); } // Update BLE device object _ble_device.setAddress(*bledevice.bt_le_address()); characteristic.setBLECharacteristicImp(this); memset(&_descriptors_header, 0, sizeof(_descriptors_header)); }
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 }
void BLEPeripheral::BLEDeviceCharacteristicValueChanged(BLEDevice& device, BLECharacteristic& characteristic, const unsigned char* value, unsigned char valueLength) { characteristic.setValue(this->_central, value, valueLength); }
void BLEPeripheral::BLEDeviceCharacteristicSubscribedChanged(BLEDevice& device, BLECharacteristic& characteristic, bool subscribed) { characteristic.setSubscribed(this->_central, subscribed); }
void BLESerial::_received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic) { BLESerial::_instance->_received(rxCharacteristic.value(), rxCharacteristic.valueLength()); }
void BLEPeripheral::begin() { unsigned char advertisementDataType = 0; unsigned char scanDataType = 0; unsigned char advertisementDataLength = 0; unsigned char scanDataLength = 0; unsigned char advertisementData[BLE_ADVERTISEMENT_DATA_MAX_VALUE_LENGTH]; unsigned char scanData[BLE_SCAN_DATA_MAX_VALUE_LENGTH]; if (this->_serviceSolicitationUuid){ BLEUuid serviceSolicitationUuid = BLEUuid(this->_serviceSolicitationUuid); advertisementDataLength = serviceSolicitationUuid.length(); advertisementDataType = (advertisementDataLength > 2) ? 0x15 : 0x14; memcpy(advertisementData, serviceSolicitationUuid.data(), advertisementDataLength); } else if (this->_advertisedServiceUuid){ BLEUuid advertisedServiceUuid = BLEUuid(this->_advertisedServiceUuid); advertisementDataLength = advertisedServiceUuid.length(); advertisementDataType = (advertisementDataLength > 2) ? 0x06 : 0x02; memcpy(advertisementData, advertisedServiceUuid.data(), advertisementDataLength); } else if (this->_manufacturerData && this->_manufacturerDataLength > 0) { advertisementDataLength = this->_manufacturerDataLength; if (advertisementDataLength > sizeof(advertisementData)) { advertisementDataLength = sizeof(advertisementData); } advertisementDataType = 0xff; memcpy(advertisementData, this->_manufacturerData, advertisementDataLength); } if (this->_localName){ unsigned char localNameLength = strlen(this->_localName); scanDataLength = localNameLength; if (scanDataLength > sizeof(scanData)) { scanDataLength = sizeof(scanData); } scanDataType = (localNameLength > scanDataLength) ? 0x08 : 0x09; memcpy(scanData, this->_localName, scanDataLength); } if (this->_localAttributes == NULL) { this->initLocalAttributes(); } for (int i = 0; i < this->_numLocalAttributes; i++) { BLELocalAttribute* localAttribute = this->_localAttributes[i]; if (localAttribute->type() == BLETypeCharacteristic) { BLECharacteristic* characteristic = (BLECharacteristic*)localAttribute; characteristic->setValueChangeListener(*this); } } for (int i = 0; i < this->_numRemoteAttributes; i++) { BLERemoteAttribute* remoteAttribute = this->_remoteAttributes[i]; if (remoteAttribute->type() == BLETypeCharacteristic) { BLERemoteCharacteristic* remoteCharacteristic = (BLERemoteCharacteristic*)remoteAttribute; remoteCharacteristic->setValueChangeListener(*this); } } if (this->_numRemoteAttributes) { this->addRemoteAttribute(this->_remoteGenericAttributeService); this->addRemoteAttribute(this->_remoteServicesChangedCharacteristic); } this->_device->begin(advertisementDataType, advertisementDataLength, advertisementData, scanDataType, scanDataLength, scanData, this->_localAttributes, this->_numLocalAttributes, this->_remoteAttributes, this->_numRemoteAttributes); this->_device->requestAddress(); }
void BLEPeripheral::nRF8001CharacteristicValueChanged(nRF8001& nRF8001, BLECharacteristic& characteristic, const unsigned char* value, unsigned char valueLength) { characteristic.setValue(this->_central, value, valueLength); }
void BLEPeripheral::nRF8001CharacteristicSubscribedChanged(nRF8001& nRF8001, BLECharacteristic& characteristic, bool subscribed) { characteristic.setSubscribed(this->_central, subscribed); }
/** * @brief Handle a GATTS server event. */ void BLEService::handleGATTServerEvent( esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { switch(event) { // ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service. // add_char: // - esp_gatt_status_t status // - uint16_t attr_handle // - uint16_t service_handle // - esp_bt_uuid_t char_uuid // If we have reached the correct service, then locate the characteristic and remember the handle // for that characteristic. case ESP_GATTS_ADD_CHAR_EVT: { if (m_handle == param->add_char.service_handle) { BLECharacteristic *pCharacteristic = getCharacteristic(BLEUUID(param->add_char.char_uuid)); if (pCharacteristic == nullptr) { ESP_LOGE(LOG_TAG, "Expected to find characteristic with UUID: %s, but didnt!", BLEUUID(param->add_char.char_uuid).toString().c_str()); dump(); m_semaphoreAddCharEvt.give(); break; } pCharacteristic->setHandle(param->add_char.attr_handle); m_characteristicMap.setByHandle(param->add_char.attr_handle, pCharacteristic); //ESP_LOGD(tag, "Characteristic map: %s", m_characteristicMap.toString().c_str()); m_semaphoreAddCharEvt.give(); break; } // Reached the correct service. break; } // ESP_GATTS_ADD_CHAR_EVT // ESP_GATTS_START_EVT // // start: // esp_gatt_status_t status // uint16_t service_handle case ESP_GATTS_START_EVT: { if (param->start.service_handle == getHandle()) { m_semaphoreStartEvt.give(); } break; } // ESP_GATTS_START_EVT // ESP_GATTS_CREATE_EVT // Called when a new service is registered as having been created. // // create: // * esp_gatt_status_t status // * uint16_t service_handle // * esp_gatt_srvc_id_t service_id // * - esp_gatt_id id // * - esp_bt_uuid uuid // * - uint8_t inst_id // * - bool is_primary // case ESP_GATTS_CREATE_EVT: { if (getUUID().equals(BLEUUID(param->create.service_id.id.uuid))) { setHandle(param->create.service_handle); m_semaphoreCreateEvt.give(); } break; } // ESP_GATTS_CREATE_EVT default: { break; } // Default } // Switch m_characteristicMap.handleGATTServerEvent(event, gatts_if, param); } // handleGATTServerEvent
void BLEPeripheral::begin() { unsigned char advertisementDataSize = 0; BLEEirData advertisementData[3]; BLEEirData scanData; scanData.length = 0; unsigned char remainingAdvertisementDataLength = BLE_ADVERTISEMENT_DATA_MAX_VALUE_LENGTH + 2; if (this->_serviceSolicitationUuid){ BLEUuid serviceSolicitationUuid = BLEUuid(this->_serviceSolicitationUuid); unsigned char uuidLength = serviceSolicitationUuid.length(); advertisementData[advertisementDataSize].length = uuidLength; advertisementData[advertisementDataSize].type = (uuidLength > 2) ? 0x15 : 0x14; memcpy(advertisementData[advertisementDataSize].data, serviceSolicitationUuid.data(), uuidLength); advertisementDataSize += 1; remainingAdvertisementDataLength -= uuidLength + 2; } if (this->_advertisedServiceUuid){ BLEUuid advertisedServiceUuid = BLEUuid(this->_advertisedServiceUuid); unsigned char uuidLength = advertisedServiceUuid.length(); if (uuidLength + 2 <= remainingAdvertisementDataLength) { advertisementData[advertisementDataSize].length = uuidLength; advertisementData[advertisementDataSize].type = (uuidLength > 2) ? 0x06 : 0x02; memcpy(advertisementData[advertisementDataSize].data, advertisedServiceUuid.data(), uuidLength); advertisementDataSize += 1; remainingAdvertisementDataLength -= uuidLength + 2; } } if (this->_manufacturerData && this->_manufacturerDataLength > 0) { if (remainingAdvertisementDataLength >= 3) { unsigned char dataLength = this->_manufacturerDataLength; if (dataLength + 2 > remainingAdvertisementDataLength) { dataLength = remainingAdvertisementDataLength - 2; } advertisementData[advertisementDataSize].length = dataLength; advertisementData[advertisementDataSize].type = 0xff; memcpy(advertisementData[advertisementDataSize].data, this->_manufacturerData, dataLength); advertisementDataSize += 1; remainingAdvertisementDataLength -= dataLength + 2; } } if (this->_localName){ unsigned char localNameLength = strlen(this->_localName); scanData.length = localNameLength; if (scanData.length > BLE_SCAN_DATA_MAX_VALUE_LENGTH) { scanData.length = BLE_SCAN_DATA_MAX_VALUE_LENGTH; } scanData.type = (localNameLength > scanData.length) ? 0x08 : 0x09; memcpy(scanData.data, this->_localName, scanData.length); } if (this->_localAttributes == NULL) { this->initLocalAttributes(); } for (int i = 0; i < this->_numLocalAttributes; i++) { BLELocalAttribute* localAttribute = this->_localAttributes[i]; if (localAttribute->type() == BLETypeCharacteristic) { BLECharacteristic* characteristic = (BLECharacteristic*)localAttribute; characteristic->setValueChangeListener(*this); } } for (int i = 0; i < this->_numRemoteAttributes; i++) { BLERemoteAttribute* remoteAttribute = this->_remoteAttributes[i]; if (remoteAttribute->type() == BLETypeCharacteristic) { BLERemoteCharacteristic* remoteCharacteristic = (BLERemoteCharacteristic*)remoteAttribute; remoteCharacteristic->setValueChangeListener(*this); } } if (this->_numRemoteAttributes) { this->addRemoteAttribute(this->_remoteGenericAttributeService); this->addRemoteAttribute(this->_remoteServicesChangedCharacteristic); } this->_device->begin(advertisementDataSize, advertisementData, scanData.length > 0 ? 1 : 0, &scanData, this->_localAttributes, this->_numLocalAttributes, this->_remoteAttributes, this->_numRemoteAttributes); this->_device->requestAddress(); }