diff --git a/examples/Advanced/NimBLE_Client/main/main.cpp b/examples/Advanced/NimBLE_Client/main/main.cpp index d276aad..452b97c 100644 --- a/examples/Advanced/NimBLE_Client/main/main.cpp +++ b/examples/Advanced/NimBLE_Client/main/main.cpp @@ -1,11 +1,11 @@ -/** NimBLE_Server Demo: +/** NimBLE_Client Demo: * * Demonstrates many of the available features of the NimBLE client library. - * + * * Created: on March 24 2020 * Author: H2zero - * + * */ #include @@ -18,15 +18,15 @@ static uint32_t scanTime = 0; /** scan time in milliseconds, 0 = scan forever */ /** None of these are required as they will be handled by the library with defaults. ** - ** Remove as you see fit for your needs */ + ** Remove as you see fit for your needs */ class ClientCallbacks : public NimBLEClientCallbacks { void onConnect(NimBLEClient* pClient) { printf("Connected\n"); /** After connection we should change the parameters if we don't need fast response times. - * These settings are 150ms interval, 0 latency, 450ms timout. + * These settings are 150ms interval, 0 latency, 450ms timout. * Timeout should be a multiple of the interval, minimum is 100ms. * I find a multiple of 3-5 * the interval works best for quick response/reconnect. - * Min interval: 120 * 1.25ms = 150, Max interval: 120 * 1.25ms = 150, 0 latency, 45 * 10ms = 450ms timeout + * Min interval: 120 * 1.25ms = 150, Max interval: 120 * 1.25ms = 150, 0 latency, 45 * 10ms = 450ms timeout */ pClient->updateConnParams(120,120,0,45); } @@ -36,7 +36,7 @@ class ClientCallbacks : public NimBLEClientCallbacks { pClient->getPeerAddress().toString().c_str(), reason); NimBLEDevice::getScan()->start(scanTime); } - + /********************* Security handled here ********************** ****** Note: these are the same return values as defaults ********/ uint32_t onPassKeyRequest(){ @@ -72,9 +72,9 @@ class scanCallbacks: public NimBLEScanCallbacks { printf("Found Our Service\n"); /** stop scan before connecting */ NimBLEDevice::getScan()->stop(); - /** Save the device reference in a global for the client to use*/ + /** Save the device reference in a global for the client to use*/ advDevice = advertisedDevice; - /** Ready to connect now */ + /** Ready to connect now */ doConnect = true; } } @@ -88,7 +88,7 @@ class scanCallbacks: public NimBLEScanCallbacks { /** Notification / Indication receiving handler callback */ void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify){ - std::string str = (isNotify == true) ? "Notification" : "Indication"; + std::string str = (isNotify == true) ? "Notification" : "Indication"; str += " from "; str += pRemoteCharacteristic->getRemoteService()->getClient()->getPeerAddress().toString(); str += ": Service = " + pRemoteCharacteristic->getRemoteService()->getUUID().toString(); @@ -105,10 +105,10 @@ static ClientCallbacks clientCB; /** Handles the provisioning of clients and connects / interfaces with the server */ bool connectToServer() { NimBLEClient* pClient = nullptr; - + /** Check if we have a client we should reuse first **/ if(NimBLEDevice::getClientListSize()) { - /** Special case when we already know this device, we send false as the + /** Special case when we already know this device, we send false as the * second argument in connect() to prevent refreshing the service database. * This saves considerable time and power. */ @@ -119,7 +119,7 @@ bool connectToServer() { return false; } printf("Reconnected client\n"); - } + } /** We don't already have a client that knows this device, * we will check for a client that is disconnected that we can use. */ @@ -127,28 +127,28 @@ bool connectToServer() { pClient = NimBLEDevice::getDisconnectedClient(); } } - + /** No client to reuse? Create a new one. */ if(!pClient) { if(NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS) { printf("Max clients reached - no more connections available\n"); return false; } - + pClient = NimBLEDevice::createClient(); - + printf("New client created\n"); - + pClient->setClientCallbacks(&clientCB, false); - /** Set initial connection parameters: These settings are 15ms interval, 0 latency, 120ms timout. - * These settings are safe for 3 clients to connect reliably, can go faster if you have less + /** Set initial connection parameters: These settings are 15ms interval, 0 latency, 120ms timout. + * These settings are safe for 3 clients to connect reliably, can go faster if you have less * connections. Timeout should be a multiple of the interval, minimum is 100ms. - * Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 12 * 10ms = 120ms timeout + * Min interval: 12 * 1.25ms = 15, Max interval: 12 * 1.25ms = 15, 0 latency, 12 * 10ms = 120ms timeout */ pClient->setConnectionParams(6,6,0,15); /** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */ pClient->setConnectTimeout(5); - + if (!pClient->connect(advDevice)) { /** Created a client but failed to connect, don't need to keep it as it has no data */ @@ -156,24 +156,24 @@ bool connectToServer() { printf("Failed to connect, deleted client\n"); return false; } - } - + } + if(!pClient->isConnected()) { if (!pClient->connect(advDevice)) { printf("Failed to connect\n"); return false; } } - - printf("Connected to: %s RSSI: %d\n", + + printf("Connected to: %s RSSI: %d\n", pClient->getPeerAddress().toString().c_str(), pClient->getRssi()); - + /** Now we can read/write/subscribe the charateristics of the services we are interested in */ NimBLERemoteService* pSvc = nullptr; NimBLERemoteCharacteristic* pChr = nullptr; NimBLERemoteDescriptor* pDsc = nullptr; - + pSvc = pClient->getService("DEAD"); if(pSvc) { /** make sure it's not null */ pChr = pSvc->getCharacteristic("BEEF"); @@ -185,32 +185,32 @@ bool connectToServer() { pChr->getUUID().toString().c_str(), pChr->readValue().c_str()); } - + if(pChr->canWrite()) { if(pChr->writeValue("Tasty")) { printf("Wrote new value to: %s\n", pChr->getUUID().toString().c_str()); } else { - /** Disconnect if write failed */ + /** Disconnect if write failed */ pClient->disconnect(); return false; } - + if(pChr->canRead()) { printf("The value of: %s is now: %s\n", pChr->getUUID().toString().c_str(), pChr->readValue().c_str()); } } - - /** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe(). - * Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false. - * Unsubscribe parameter defaults are: response=false. + + /** registerForNotify() has been removed and replaced with subscribe() / unsubscribe(). + * Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=true. + * Unsubscribe parameter defaults are: response=true. */ if(pChr->canNotify()) { //if(!pChr->registerForNotify(notifyCB)) { if(!pChr->subscribe(true, notifyCB)) { - /** Disconnect if subscribe failed */ + /** Disconnect if subscribe failed */ pClient->disconnect(); return false; } @@ -219,17 +219,17 @@ bool connectToServer() { /** Send false as first argument to subscribe to indications instead of notifications */ //if(!pChr->registerForNotify(notifyCB, false)) { if(!pChr->subscribe(false, notifyCB)) { - /** Disconnect if subscribe failed */ + /** Disconnect if subscribe failed */ pClient->disconnect(); return false; } } } - + else{ printf("DEAD service not found.\n"); } - + pSvc = pClient->getService("BAAD"); if(pSvc) { /** make sure it's not null */ pChr = pSvc->getCharacteristic("F00D"); @@ -241,39 +241,39 @@ bool connectToServer() { pChr->getUUID().toString().c_str(), pChr->readValue().c_str()); } - + pDsc = pChr->getDescriptor(NimBLEUUID("C01D")); if(pDsc) { /** make sure it's not null */ printf("Descriptor: %s Value: %s\n", pDsc->getUUID().toString().c_str(), pDsc->readValue().c_str()); } - + if(pChr->canWrite()) { if(pChr->writeValue("No tip!")) { printf("Wrote new value to: %s\n", pChr->getUUID().toString().c_str()); } else { - /** Disconnect if write failed */ + /** Disconnect if write failed */ pClient->disconnect(); return false; } - + if(pChr->canRead()) { printf("The value of: %s is now: %s\n", pChr->getUUID().toString().c_str(), pChr->readValue().c_str()); } } - + /** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe(). - * Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false. - * Unsubscribe parameter defaults are: response=false. + * Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=true. + * Unsubscribe parameter defaults are: response=true. */ if(pChr->canNotify()) { //if(!pChr->registerForNotify(notifyCB)) { if(!pChr->subscribe(true, notifyCB)) { - /** Disconnect if subscribe failed */ + /** Disconnect if subscribe failed */ pClient->disconnect(); return false; } @@ -282,17 +282,17 @@ bool connectToServer() { /** Send false as first argument to subscribe to indications instead of notifications */ //if(!pChr->registerForNotify(notifyCB, false)) { if(!pChr->subscribe(false, notifyCB)) { - /** Disconnect if subscribe failed */ + /** Disconnect if subscribe failed */ pClient->disconnect(); return false; } - } - } + } + } else{ printf("BAAD service not found.\n"); } - + printf("Done with this device!\n"); return true; } @@ -308,12 +308,12 @@ void connectTask (void * parameter){ } else { printf("Failed to connect, starting scan\n"); } - + NimBLEDevice::getScan()->start(scanTime); } vTaskDelay(10/portTICK_PERIOD_MS); } - + vTaskDelete(NULL); } @@ -321,7 +321,7 @@ void app_main (void){ printf("Starting NimBLE Client\n"); /** Initialize NimBLE, no device name spcified as we are not advertising */ NimBLEDevice::init(""); - + /** Set the IO capabilities of the device, each option will trigger a different pairing method. * BLE_HS_IO_KEYBOARD_ONLY - Passkey pairing * BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing @@ -329,42 +329,42 @@ void app_main (void){ */ //NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY); // use passkey //NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO); //use numeric comparison - + /** 2 different ways to set security - both calls achieve the same result. * no bonding, no man in the middle protection, secure connections. - * - * These are the default values, only shown here for demonstration. - */ - //NimBLEDevice::setSecurityAuth(false, false, true); + * + * These are the default values, only shown here for demonstration. + */ + //NimBLEDevice::setSecurityAuth(false, false, true); NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC); - + /** Optional: set the transmit power, default is -3db */ NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** 12db */ - + /** Optional: set any devices you don't want to get advertisments from */ - // NimBLEDevice::addIgnored(NimBLEAddress ("aa:bb:cc:dd:ee:ff")); - - /** create new scan */ - NimBLEScan* pScan = NimBLEDevice::getScan(); - + // NimBLEDevice::addIgnored(NimBLEAddress ("aa:bb:cc:dd:ee:ff")); + + /** create new scan */ + NimBLEScan* pScan = NimBLEDevice::getScan(); + /** create a callback that gets called when advertisers are found */ pScan->setScanCallbacks (new scanCallbacks()); - + /** Set scan interval (how often) and window (how long) in milliseconds */ pScan->setInterval(400); pScan->setWindow(100); - + /** Active scan will gather scan response data from advertisers * but will use more energy from both devices */ pScan->setActiveScan(true); /** Start scanning for advertisers for the scan time specified (in seconds) 0 = forever - * Optional callback for when scanning stops. + * Optional callback for when scanning stops. */ pScan->start(scanTime); - + printf("Scanning for peripherals\n"); - + xTaskCreate(connectTask, "connectTask", 5000, NULL, 1, NULL); } diff --git a/examples/basic/BLE_client/main/main.cpp b/examples/basic/BLE_client/main/main.cpp index f6d9495..b0df854 100644 --- a/examples/basic/BLE_client/main/main.cpp +++ b/examples/basic/BLE_client/main/main.cpp @@ -14,7 +14,7 @@ #include "NimBLEDevice.h" extern "C"{void app_main(void);} - + // The remote service we wish to connect to. static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b"); // The characteristic of the remote service we are interested in. @@ -53,11 +53,11 @@ class MyClientCallback : public BLEClientCallbacks { ****** Note: these are the same return values as defaults ********/ uint32_t onPassKeyRequest(){ printf("Client PassKeyRequest\n"); - return 123456; + return 123456; } bool onConfirmPIN(uint32_t pass_key){ printf("The passkey YES/NO number: %d\n", pass_key); - return true; + return true; } void onAuthenticationComplete(BLEConnInfo& connInfo){ @@ -101,10 +101,11 @@ bool connectToServer() { if(pRemoteCharacteristic->canRead()) { std::string value = pRemoteCharacteristic->readValue(); printf("The characteristic value was: %s\n", value.c_str()); - } - /** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe(). - * Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false. - * Unsubscribe parameter defaults are: response=false. + } + + /** registerForNotify() has been removed and replaced with subscribe() / unsubscribe(). + * Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=true. + * Unsubscribe parameter defaults are: response=true. */ if(pRemoteCharacteristic->canNotify()) { //pRemoteCharacteristic->registerForNotify(notifyCallback); @@ -151,7 +152,7 @@ class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { void connectTask (void * parameter){ for(;;) { // If the flag "doConnect" is true then we have scanned for and found the desired - // BLE Server with which we wish to connect. Now we connect to it. Once we are + // BLE Server with which we wish to connect. Now we connect to it. Once we are // connected we set the connected flag to be true. if (doConnect == true) { if (connectToServer()) { @@ -168,17 +169,17 @@ void connectTask (void * parameter){ char buf[256]; snprintf(buf, 256, "Time since boot: %lu", (unsigned long)(esp_timer_get_time() / 1000000ULL)); printf("Setting new characteristic value to %s\n", buf); - + // Set the characteristic's value to be the array of bytes that is actually a string. /*** Note: write value now returns true if successful, false otherwise - try again or disconnect ***/ pRemoteCharacteristic->writeValue((uint8_t*)buf, strlen(buf), false); }else if(doScan){ BLEDevice::getScan()->start(0); // this is just eample to start scan after disconnect, most likely there is better way to do it } - + vTaskDelay(1000/portTICK_PERIOD_MS); // Delay a second between loops. } - + vTaskDelete(NULL); } // End of loop @@ -195,7 +196,7 @@ void app_main(void) { pBLEScan->setInterval(1349); pBLEScan->setWindow(449); pBLEScan->setActiveScan(true); - + xTaskCreate(connectTask, "connectTask", 5000, NULL, 1, NULL); pBLEScan->start(5 * 1000, false); } // End of setup. diff --git a/src/NimBLERemoteCharacteristic.cpp b/src/NimBLERemoteCharacteristic.cpp index e04fc9d..35c191d 100644 --- a/src/NimBLERemoteCharacteristic.cpp +++ b/src/NimBLERemoteCharacteristic.cpp @@ -564,7 +564,7 @@ int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle, * If NULL is provided then no callback is performed. * @return false if writing to the descriptor failed. */ -bool NimBLERemoteCharacteristic::setNotify(uint16_t val, notify_callback notifyCallback) { +bool NimBLERemoteCharacteristic::setNotify(uint16_t val, notify_callback notifyCallback, bool response) { NIMBLE_LOGD(LOG_TAG, ">> setNotify(): %s, %02x", toString().c_str(), val); m_notifyCallback = notifyCallback; @@ -576,7 +576,8 @@ bool NimBLERemoteCharacteristic::setNotify(uint16_t val, notify_callback notifyC } NIMBLE_LOGD(LOG_TAG, "<< setNotify()"); - return desc->writeValue((uint8_t *)&val, 2, true); + + return desc->writeValue((uint8_t *)&val, 2, response); } // setNotify @@ -584,14 +585,15 @@ bool NimBLERemoteCharacteristic::setNotify(uint16_t val, notify_callback notifyC * @brief Subscribe for notifications or indications. * @param [in] notifications If true, subscribe for notifications, false subscribe for indications. * @param [in] notifyCallback A callback to be invoked for a notification. + * @param [in] response If true, require a write response from the descriptor write operation. * If NULL is provided then no callback is performed. * @return false if writing to the descriptor failed. */ -bool NimBLERemoteCharacteristic::subscribe(bool notifications, notify_callback notifyCallback) { +bool NimBLERemoteCharacteristic::subscribe(bool notifications, notify_callback notifyCallback, bool response) { if(notifications) { - return setNotify(0x01, notifyCallback); + return setNotify(0x01, notifyCallback, response); } else { - return setNotify(0x02, notifyCallback); + return setNotify(0x02, notifyCallback, response); } } // subscribe @@ -601,8 +603,8 @@ bool NimBLERemoteCharacteristic::subscribe(bool notifications, notify_callback n * @param [in] response bool if true, require a write response from the descriptor write operation. * @return false if writing to the descriptor failed. */ -bool NimBLERemoteCharacteristic::unsubscribe() { - return setNotify(0x00, nullptr); +bool NimBLERemoteCharacteristic::unsubscribe(bool response) { + return setNotify(0x00, nullptr, response); } // unsubscribe diff --git a/src/NimBLERemoteCharacteristic.h b/src/NimBLERemoteCharacteristic.h index 311f875..a0f8f55 100644 --- a/src/NimBLERemoteCharacteristic.h +++ b/src/NimBLERemoteCharacteristic.h @@ -66,8 +66,9 @@ public: NimBLERemoteService* getRemoteService(); NimBLEAttValue getValue(time_t *timestamp = nullptr); bool subscribe(bool notifications = true, - notify_callback notifyCallback = nullptr); - bool unsubscribe(); + notify_callback notifyCallback = nullptr, + bool response = true); + bool unsubscribe(bool response = true); bool writeValue(const uint8_t* data, size_t length, bool response = false); @@ -149,7 +150,7 @@ private: friend class NimBLERemoteDescriptor; // Private member functions - bool setNotify(uint16_t val, notify_callback notifyCallback = nullptr); + bool setNotify(uint16_t val, notify_callback notifyCallback = nullptr, bool response = true); bool retrieveDescriptors(const NimBLEUUID *uuid_filter = nullptr); static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg);