Code Monkey home page Code Monkey logo

nimble-arduino's People

Contributors

0xxon avatar ankgt avatar asukiaaa avatar bascy avatar beegee-tokyo avatar boozer2 avatar corneliusmunz avatar csmith-morningstar avatar davidjrobertson avatar deepak4395 avatar doudar avatar fabdelgado avatar gkoh avatar h2zero avatar huming2207 avatar j4m3s avatar jason2866 avatar jcontrerasf avatar jpzv avatar ketan avatar lknop avatar lultimouomo avatar mblasee avatar mr-mime avatar scoutzknifez avatar spleen1981 avatar staars avatar thorrak avatar tobozo avatar wakwak-koba avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nimble-arduino's Issues

More examples?

I’m thinking this library could use a couple more examples. Does anyone have suggestions on what would be informative?

I have some of my own ideas but I’d like to hear from users as to what they would like to see.

Also if anyone would like to submit a PR for any examples (or anything else) please feel free to do so.

Scan state to be available

@h2zero I've just seen the other question on non-blocking scan so I thought I would ask mine! Is it possible to add a property to access the state of the scan when used in non-blocking fashion? At the moment, I am setting my own flag at the start of the scan, and when scan complete is called, but that's a bit clunky when I really want the internal state (and it looks like m_stopped or the inverse might do). Thanks!

Advertised device payload not copied?

Is there any good reason why payload is not copied into the advertised device member variable std::string m_payload? Now only the pointer returned from the stack is saved, see here.

Type redefinition errors on latest Arduino IDE master

First: compliments for the excellent work to reduce the memory footprint for BLE!

Today I updated my ESP32 Arduino IDE to the latest master, and I got compilation errors (type redefinition errors). The cause was in NimbleAddress.h:

typedef enum {
    BLE_ADDR_TYPE_PUBLIC        = 0x00,
    BLE_ADDR_TYPE_RANDOM        = 0x01,
    BLE_ADDR_TYPE_RPA_PUBLIC    = 0x02,
    BLE_ADDR_TYPE_RPA_RANDOM    = 0x03,
} esp_nimble_addr_type_t;

typedef uint8_t esp_nimble_addr_type_t ;

I changed it to:

typedef enum {
    NIMBLE_ADDR_TYPE_PUBLIC        = 0x00,
    NIMBLE_ADDR_TYPE_RANDOM        = 0x01,
    NIMBLE_ADDR_TYPE_RPA_PUBLIC    = 0x02,
    NIMBLE_ADDR_TYPE_RPA_RANDOM    = 0x03,
} esp_nimble_addr_type_t;

//typedef uint8_t esp_nimble_addr_type_t ;

Now I also had to change NimBLEClient.h into:

bool connect(NimBLEAddress address, esp_nimble_addr_type_t type = NIMBLE_ADDR_TYPE_PUBLIC, bool refreshServices = true); // Connect to the remote BLE Server

and NimBLEClient.cpp:

bool NimBLEClient::connect(NimBLEAddress address, esp_nimble_addr_type_t type, bool refreshServices) {
and lastly in this file:
return connect(address, (esp_nimble_addr_type_t)type, refreshServices);

BLERemoteCharacteristic::readValue() does not return the correct value

I would love to get this library running, but I think I found another issue...

I already thought it was my problem so I asked question #19 today, but it is an error of the library.

MVCE:

#include <NimBLEDevice.h>

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("/n/nStarted");

  BLEDevice::init("ESP32");

  readBLEClients();
}


void readBLEClients() {
// LYWSD03MMC
  static BLEClient * pClient = BLEDevice::createClient();

  Serial.println("Connecting...");
  bool success = pClient->connect(BLEAddress("a4:c1:38:5d:ef:16"));
  if(!success) {
    BLEDevice::deleteClient(pClient);

    Serial.println("Failed to connect");
    return;
  }
  Serial.println("Connected");

  BLERemoteService * pRemoteService = pClient->getService(BLEUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6"));
  if(pRemoteService == nullptr) {
    Serial.print("Failed to find our service UUID: ");
  } else {
    Serial.println(" - Found our service");

    // Obtain a reference to the characteristic in the service of the remote BLE server.
    BLERemoteCharacteristic * pRemoteCharacteristic = pRemoteService->getCharacteristic(BLEUUID("ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6"));
    if(pRemoteCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
    } else {
      Serial.println(" - Found our characteristic");
      if(pRemoteCharacteristic->canRead()) {
        Serial.println("Can read");
//        Serial.printf("string value is '%s'\n", pRemoteCharacteristic->readValue().c_str());
//        Serial.printf("uint8_t value is %u\n", pRemoteCharacteristic->readUInt8());
//        Serial.printf("uint16_t value is %u\n", pRemoteCharacteristic->readUInt16());
//        const uint8_t * pData = pRemoteCharacteristic->readRawData();
        const uint8_t * pData = reinterpret_cast<const uint8_t*>(pRemoteCharacteristic->readValue().c_str());

        float temperature = (pData[0] | (pData[1] << 8)) * 0.01; //little endian 
        uint8_t humidity = pData[2];
        Serial.printf("LYWSD03MMC temperature = %.2f : humidity = %u\n", temperature, humidity);    
      }
      if(pRemoteCharacteristic->canNotify()) {
        Serial.println("Can notify");
//        pRemoteCharacteristic->registerForNotify(notifyCallback);
      }
    }
  }
  pClient->disconnect();
  BLEDevice::deleteClient(pClient);
}

void loop() {
}

returns 0.00 for temperature and 0 for humidity.

Digging for hours in the library resulted in:

Here the data is still correct. If I add the following line at this exact position:

characteristic->second->m_value = std::string((char*) event->notify_rx.om->om_data, event->notify_rx.om->om_len);

And comment out this line (otherwise the value just sets gets overwritten), the MVCE actually works correctly.

HOWEVER it does not feel good. My gut feeling says that onReadCB should indeed read the value from struct ble_gatt_attr *attr, but that value is not correct. At least the data from event->notify_rx.om in NimBLEClient differs from attr->om in NimbleRemoteCharacteristic.

I am not familiair enough with BLE and the library to solve this, and I am stuck now, any suggestions would be very welcome!.

Can't connect anymore...

I try to connect to a MJ-HT-V1. I connected to this device before, but now I do don't succeed. This is the logging:

I NimBLEDevice: "BLE Host Task Started"
I NimBLEDevice: "NimBle host synced."
Connecting...
D NimBLEClient: ">> connect(58:2d:34:39:22:58)"
D FreeRTOS: "Semaphore taking: name: OpenEvt (0x3ffc8a58), owner: <N/A> for connect"
D FreeRTOS: "Semaphore taken:  name: OpenEvt (0x3ffc8a58), owner: connect"
D FreeRTOS: ">> wait: Semaphore waiting: name: OpenEvt (0x3ffc8a58), owner: connect for connect"
D NimBLEClient: "Got Client event BLE_GAP_EVENT_CONNECT "
D NimBLEClient: "Connection established"
D FreeRTOS: "Semaphore giving: name: OpenEvt (0x3ffc8a58), owner: connect"
D FreeRTOS: "<< wait: Semaphore released: name: OpenEvt (0x3ffc8a58), owner: <N/A>"
D NimBLEClient: "Refreshing Services for: (58:2d:34:39:22:58)"
D NimBLEClient: ">> clearServices"
D NimBLEClient: "<< clearServices"
D NimBLEClient: ">> retrieveServices"
D FreeRTOS: "Semaphore taking: name: SearchCmplEvt (0x3ffc8ab8), owner: <N/A> for retrieveServices"
D FreeRTOS: "Semaphore taken:  name: SearchCmplEvt (0x3ffc8ab8), owner: retrieveServices"
D FreeRTOS: ">> wait: Semaphore waiting: name: SearchCmplEvt (0x3ffc8ab8), owner: retrieveServices for retrieveServices"
D NimBLEClient: "Got Client event BLE_GAP_EVENT_MTU"
I NimBLEClient: "mtu update event; conn_handle=0 mtu=23"
D FreeRTOS: "Semaphore giving: name: OpenEvt (0x3ffc8a58), owner: <N/A>"
D NimBLEClient: "Service Discovered >> status: 7 handle: 0"
D FreeRTOS: "Semaphore giving: name: SearchCmplEvt (0x3ffc8ab8), owner: retrieveServices"
D NimBLEClient: "<< Service Discovered. status: 7"
D FreeRTOS: "<< wait: Semaphore released: name: SearchCmplEvt (0x3ffc8ab8), owner: <N/A>"
D NimBLEClient: "Got Client event BLE_GAP_EVENT_DISCONNECT"
E NimBLEClient: "Could not retrieve services"
I NimBLEClient: "disconnect; reason=531, Remote User Terminated Connection"
D NimBLEClient: ">> disconnect()"
D FreeRTOS: "Semaphore giving: name: OpenEvt (0x3ffc8a58), owner: <N/A>"
D NimBLEClient: "<< disconnect()"
D FreeRTOS: "Semaphore giving: name: SearchCmplEvt (0x3ffc8ab8), owner: <N/A>"
D NimBLEClient: ">> clearServices"
D FreeRTOS: "Semaphore giving: name: Security (0x3ffc8b18), owner: <N/A>"
D NimBLEClient: "<< clearServices"
FDa NimBLEClientCallbacks: "onDisconnect: default"

Maybe the cause is that I did not disconnect before I ran a new sketch? I unplugged the ESP32 and took the battery out the peripheral without success...

Scan with duration 0 in background

I have modified the function start of NimBLEScan in order to return immediately if is called with duration = 0.
That can permit to leave the scan in background and release the task to do something else.

/**
 * @brief Start scanning and block until scanning has been completed.
 * @param [in] duration The duration in seconds for which to scan.
 * @param [in] is_continue Set to true to save previous scan results, false to clear them.
 * @return The NimBLEScanResults.
 */
NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) {
    if(duration == 0) {
        NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever");
    }

    ble_task_data_t taskData = {nullptr, xTaskGetCurrentTaskHandle(),0, nullptr};
    m_pTaskData = &taskData;

    if(start(duration, nullptr, is_continue)) {
        if(duration==0) return m_scanResults;
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
    }
    m_pTaskData = nullptr;

    return m_scanResults;
} // start

I'm not an expert, than i don't know if m_pTaskData must be cleared before the return.
This patch is intended as a draft

BLE UART example

How can we use ble UART example for UART 1 / UART 2 of esp32?

Why does scanEndedCB get called twice in client connection example?

Hi

Firstly I would like to say thanks for the library; I got stuck very quickly using the "built in" library on an esp32 arduino project needing multi client connect, and then discovered this which has given me confidence to proceed.

I have a query relating to the NimBLE_Client.ino example...

When the preferred service is found by scanning, getScan()->stop() is called which triggers the scanEndedCB callback.

That callback is then unexpectedly triggered again after the client is connected (even though the scan has not been restarted at that point).

Is this behaviour by design?

Thanks

Bonding doesn't work

I have this to setup my security

 NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_YESNO ); // set display output capability 
    NimBLEDevice::setSecurityAuth(true, true, true); // bonding, man in the middle protection, secure connection
 _service->createCharacteristic(FINGERPRINT_UUID, NIMBLE_PROPERTY::READ |
                                                            NIMBLE_PROPERTY::WRITE | 
                                                            NIMBLE_PROPERTY::WRITE_ENC);

And I am just wondering if I have the correct understanding of bonding. My thought was after my phone pairs with this it won't have to confirm the connection ever again, but every time I try to right that characteristic after I reboot the chip I get the pop up on my android device confirming that I want to connect.

Is it possible to just have it remain connected using the BLE_HS_IO_DISPLAY_YESNO or am I just confused about what should be happening.

Endianness in addresses and UUIDs

Since I am basing some functionalities on peer addresses and beacon UUIDs, I am struggling with incompatibilities of NimBLE against the older stack (and other vendors).

It seems all the addresses are reversed, which is not a huge issue per se since they are internally stored as 6-byte arrays, but perhaps this could be mentioned in the Breaking API changes document.

A larger problem, however, is connected with the UUIDs (so far I only noticed a problem with beacon uuids, service and characteristic ones work correctly). Example output from the BLE_Beacon_Scanner.ino:

Scan done!
Found an iBeacon!
iBeacon Frame
             ID: 004C Major: 1 Minor: 1 UUID: f31a5871-9179-2a97-d84d-f63cc5dc5fc7 Power: -56

However, the broadcast was configured with the UUID in reverse order:
#define BEACON_UUID "c75fdcc5-3cf6-4dd8-972a-799171581af3"

Other tools such as nRF Connect report the correct UUID:
beacon_scaled

And the scanner based on Bluedroid also discovers it as c75fdcc5-3cf6-4dd8-972a-799171581af3, not the other way round.

The question is where it should be solved - the obvious location would be void NimBLEBeacon::setData(const std::string &data) where the data is set directly with memcpy whereas other methods do perform ENDIAN_CHANGE_U16 on other fields. Although proximityUUID is never reversed, and it most probably should be.

However, I am wondering whether this could not be solved globally, any migration from bluedroid will need conversion of addresses, and even if that is relatively simple, keeping the data in little endian arrays is cumbersome in any debug display or string conversion.

As a side note, it seems strange to me that I have found only a single mention of the endianness issue in NimBLE docs.

Should we pass UUIDs (and maybe other objects) as const reference?

I did a small experiment, changing in BLEClient this function BLERemoteService * getService(const BLEUUID &uuid), so I passed a const reference instead of the object. This lead to having to change in BLEUUID the function std::string toString() const, because the compiler complaint about passing a non-const this parameter.

In a very small program this saved 12 bytes of code, not a lot. BUT this should have a great positive impact on performance, because now not the full object is copied onto the stack, but just a reference (pointer) to it.

I think it is a lot of work, to change all relevant class member functions, but I think it is worth the effort, if there are no negative side effects. What do you think?

iBeacon advertisement - how to exclude type ( Question / help )

Is it possible to not include the type in the iBeacon advertisement. For example when using the iBeacon example, the advertisement is something like this

Name: , Address: 69:31:32:ea:12:d7 type: 1, manufacturer data: 4c001006351a5e09505b, txPower: 7

Is it possible to not include the type? I mean is there any setting/param to do that?

I should be able to modify the source to achieve this but if there's a existing way I'd prefer that. Thanks.

NOTE: Oops, I haven't checked the receiving end. it could also be a setting on the receiving end - I mean a setting to choose what gets shown from the advertisement.

NimBLE Server - NIMBLE_PROPERTY::READ leads to crash

HI @h2zero I know you are busy with fixing the Client stuff, but something on the Server side broke along the way.
Simple custom characteristic creation using NIMBLE_PROPERTY::READ makes the app crash on pService->start().

Example code:

// Includes for BLE Arduino-NimBLE
#include <NimBLEUtils.h>
#include <NimBLEServer.h>
#include <NimBLEDevice.h>
#include <NimBLEAdvertising.h>

/** Unique device name */
char apName[] = "ESP32-xxxxxxxxxxxx";

// List of Service and Characteristic UUIDs
#define SERVICE_UUID "0000AAAA-EAD2-11E7-80C1-9A214CF093AE"
#define WIFI_UUID "00005555-EAD2-11E7-80C1-9A214CF093AE"

... // skipping the callbacks
/**
 * initBLE
 * Initialize BLE service and characteristic
 * Start BLE server and service advertising
 */
void initBLE()
{
	// Initialize BLE and set output power
	BLEDevice::init(apName);
	BLEDevice::setPower(ESP_PWR_LVL_P7);
	BLEDevice::setMTU(256);

	Serial.printf("BLE advertising using %s\n", apName);

	// Create BLE Server
	pServer = BLEDevice::createServer();

	// Set server callbacks
	pServer->setCallbacks(new MyServerCallbacks());

	// Create BLE Service
	pService = pServer->createService(SERVICE_UUID);

	// Create BLE Characteristic for WiFi settings
	pCharacteristicWiFi = pService->createCharacteristic(
		// BLEUUID(WIFI_UUID),
		WIFI_UUID,
		NIMBLE_PROPERTY::READ |
			NIMBLE_PROPERTY::WRITE);

	/** Add properties the same way as characteristics now **/
	pCharacteristicWiFi->createDescriptor("2902");

	pCharacteristicWiFi->setCallbacks(new MyCallbackHandler());

	// Start the service
	pService->start();

	// Start advertising
	pAdvertising = pServer->getAdvertising();
	pAdvertising->addServiceUUID(WIFI_UUID);
	pAdvertising->start();
}

Serial debug output:

Build: Apr  5 2020 10:15:02
Read from preferences:
primary SSID: XYZ2 password: secret
secondary SSID: XYZ3 password: secret
I NimBLEDevice: "BLE Host Task Started"
I NimBLEDevice: "NimBle host synced."
D NimBLEDevice: ">> setPower: 7"
D NimBLEDevice: "<< setPower"
BLE advertising using ESP32-3C71BF6CE284
Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC      : 0x400e43e3  PS      : 0x00060530  A0      : 0x800d65d8  A1      : 0x3ffcb5c0  
A2      : 0x00000004  A3      : 0x3ffcb600  A4      : 0x3ffc3600  A5      : 0x00000002  
A6      : 0x3ffcb610  A7      : 0x3ffce201  A8      : 0x00002902  A9      : 0x00000000  
A10     : 0x00000000  A11     : 0x40085110  A12     : 0x3ffce444  A13     : 0x3ffcb538  
A14     : 0x3ffcb5a0  A15     : 0xfefefe01  SAR     : 0x00000018  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x00000004  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0x00000000  

Backtrace: 0x400e43e3:0x3ffcb5c0 0x400d65d5:0x3ffcb5e0 0x400d5f2d:0x3ffcb600 0x400d1de1:0x3ffcb690 0x400d233f:0x3ffcb6d0 0x400eb93f:0x3ffcb790 0x4008dadd:0x3ffcb7b0

Decoded backtrace:

PC: 0x400e43e3: ble_uuid_cmp at .pio\libdeps\esp32devmaxapp\NimBLE-Arduino\src\nimble\host\src\ble_uuid.c line 71
EXCVADDR: 0x00000004

Decoding stack results
0x400e43e3: ble_uuid_cmp at .pio\libdeps\esp32devmaxapp\NimBLE-Arduino\src\nimble\host\src\ble_uuid.c line 71
0x400d65d5: NimBLEUUID::equals(NimBLEUUID) at .pio\libdeps\esp32devmaxapp\NimBLE-Arduino\src\NimBLEUUID.cpp line 181
0x400d5f2d: NimBLEService::start() at .pio\libdeps\esp32devmaxapp\NimBLE-Arduino\src\NimBLEService.cpp line 129
0x400d1de1: initBLE() at src\main.cpp line 355
0x400d233f: setup() at src\main.cpp line 531
0x400eb93f: loopTask(void*) at C:\users\beegee\.platformio\packages\framework-arduinoespressif32\cores\esp32\main.cpp line 14
0x4008dadd: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143

I tried as well with the BLE Uart example and it crashes at the same place. Btw. there is an error in the BLE Uart example.

	// Create a BLE Characteristic
	pTxCharacteristic = pService->createCharacteristic(
		CHARACTERISTIC_UUID_TX,
		/******* Enum Type NIMBLE_PROPERTY now *******      
                                        BLECharacteristic::PROPERTY_WRITE
                                        );
                                    **********************************************/
		NIMBLE_PROPERTY::WRITE);

should be

	// Create a BLE Characteristic
	pTxCharacteristic = pService->createCharacteristic(
		CHARACTERISTIC_UUID_TX,
		/******* Enum Type NIMBLE_PROPERTY now *******      
                                        BLECharacteristic::PROPERTY_WRITE
                                        );
                                    **********************************************/
		NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);

(Passive) BLE Scan missing a lot of advertisments

First of all: Thx for this awesome project!
I just migrated my project from the standard lib to NimBLE-Arduino and in general it works fine, but unfortunatelly I noticed that a lot of advertisments are missing.

I'm using the following code to do a endless passive scan and gather data from Xiaomi BLE sensors:

pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MiDeviceCallbacks());
pBLEScan->setActiveScan(false);
pBLEScan->start(0);

Using the standard lib one minute results in this:

Friday, June 26 2020 08:34:51: Wohnzimmer Humid: 57
Friday, June 26 2020 08:34:52: Guave Light: 375
Friday, June 26 2020 08:34:56: Guave Moisture: 41%
Friday, June 26 2020 08:34:56: Wohnzimmer Temp: 24.6
Friday, June 26 2020 08:34:58: Wohnzimmer Temp: 24.6
Friday, June 26 2020 08:35:04: Guave Conductivity: 41
Friday, June 26 2020 08:35:16: Guave Temp: 23.2
Friday, June 26 2020 08:35:16: Wohnzimmer Temp: 24.6
Friday, June 26 2020 08:35:21: Wohnzimmer Humid: 57
Friday, June 26 2020 08:35:22: Wohnzimmer Temp: 24.5
Friday, June 26 2020 08:35:23: Wohnzimmer Humid: 57
Friday, June 26 2020 08:35:24: Guave Light: 356
Friday, June 26 2020 08:35:29: Wohnzimmer Humid: 57
Friday, June 26 2020 08:35:32: Wohnzimmer Temp: 24.6
Friday, June 26 2020 08:35:34: Guave Moisture: 41%
Friday, June 26 2020 08:35:44: Guave Conductivity: 41
Friday, June 26 2020 08:35:44: Wohnzimmer Temp: 24.6
Friday, June 26 2020 08:35:54: Guave Temp: 23.2

while one minute using NimBLE results in:

Friday, June 26 2020 08:38:54: Guave Moisture: 41%
Friday, June 26 2020 08:38:58: Wohnzimmer Temp: 24.5
Friday, June 26 2020 08:39:38: Wohnzimmer Humid: 57
Friday, June 26 2020 08:39:41: Guave Moisture: 41%

Hardware is the same and did not move, so "traffic" should be about the same in both cases.

About 80% of the advertisments seem not to be reported to my callback.

Full source of my Program is available here ( https://github.com/TheNitek/MicroHome/blob/master/MicroHome.ino ).

Is that a problem with NimBLE or did I miss any NimBLE specific parameters that I have to set/change?

Combining long reads

Awesome work on this package.

I am working on implementing BLE for the first time in my project and I'm curious if there is suggested way to deal with "long" reads/writes.

BLE seems to support reads and writes up to 500, but I'm just curious what part o the app should be handling the combining of it into the packets.

If I do a longer read from an phone I notice that it calls onRead repeatedly until it reads the full thing. In some cases I end up updating the value it is reading before it is completely done.

My question for that, is it possible in the onRead callback to see if it is part of an ongoing call so I can make sure that it is not updated in the middle of reading.

Similarly for the onWrite, if I write a large packet from a phone, I just see a bunch of small parts of the whole packet written individually. I could figure out what to do if there was some way just to tell if it is the end of the packet or not.

I can figure out some custom solutions for these problems, but before I spend the time doing that, I was just curious if there are parts of the api I am missing, or if there are more things that need to be implemented before this package is complete.

Shouldn't NimBLEScan::getDevice() be protected by semaphore?

In NimBLEScan::getDevice() here the device to return to the caller is assigned to a temporary variable. Is this unary? In other words, could the background scan update the device halfway copying the device? Or is this impossible? If possible, could / should it be protected by semaphore?

BLE HEAP memory reduction

Hello ,
Please anyone can help with HEAP reduction due to NimBLE.h file in the code.
BLEDevice::deinit - It only clears BLE stack or server or service ?
How to clear out whole memory of NimBLE Stack

Pending v1.0 release and potential sub-moduling.

Most of the todo list has been crossed off and a v1.0 release is coming very soon.

As no news is good news I'm taking the lack of recent issues and PR's as a nod of stability, but I'd like to reach out here to ask if there are any lingering bugs or nags that should be dealt with?

I also would like to ask for feedback regarding using the esp-nimble-cpp repo as a submodule in this repo. Currently I have been keeping the code in both synced together manually but I would prefer to have one repo with the actual C++ library code that would be linked into this for easier maintenance.

In this proposal I would simply have a cpp folder in this repo that links to the esp-nimble-cpp repo, however that would mean all pull requests would need to be made there instead of here and would require the use of git submodule operations when cloning/updating. Probably not the best thing to do for an Arduino library,

The second option is a subtree, which makes the git submodule commands unnecessary but code modifications and PR's more troublesome (and I would have to learn to use them 😄 ) but would effectively work "as is".

The last option is keep doing what I've been doing. Not my favorite due to potential human error and having to recreate the updates in one repo or the other.

If anyone has any thoughts about this I would love to hear them.

Behavior differs from default BLE library during BLE scan when passive mode is set

I had an issue earlier where a subset of BLE iBeacon devices that were showing up in the original ESP32 were not being picked up by my callback when using NimBLE.

From digging through the code, it appears that behavior differs between the two libraries when BLEScan->setActiveScan() is set true thereby disabling passive mode. In the default library the callback still gets triggered regardless of the state of passive mode, whereas in NimBLE the callback does not get triggered when passive mode is set.

This seems like this behavior changed in NimBLE-Arduino after some of the initial commits - if this behavior change was intentional and expected to remain part of the library, it might be helpful to document the change somewhere.

Passive check in the NimBLE Library:

if(pScan->m_scan_params.passive) {

Line /w behavior in the Non-NimBLE Library: https://github.com/espressif/arduino-esp32/blob/1efcd21ba91c08e702a0c6e47e00a2d0a8c06b84/libraries/BLE/src/BLEScan.cpp#L127

Question: meaning advertisedDevice::getAddressType()

Not an issue but a question: how should I interpret the value returned by getAddressType()? I found this post. That post explains that the address type is coded into bits, but I am not sure if this is indeed the value the function returns. If so then the return value is as follows:

  • Public device address: 0
  • Static device address: 111, so 7
  • Non-resolvable device address: 001, so 1
  • Resolvable device address: 101, so 5

Is this actually the value returned?

Why is NIMBLE_MAX_CONNECTIONS defined?

In NimBLEDevice the connections are stored in a dynamic container that can store any number of connections. Why limit it? If the programmer needs more connections than the limit, it can be adapted, so why don't limit it in the first place? I think there is no advantage in this.

Private m_pCharacteristic in NimBLEDescriptor class

Hello @h2zero again

I have a question about the NimBLEDescriptor class.

Is there a particular reason why m_pCharacteristic is private?

In NimBLEDescriptorCallbacks, there is no way to check what characteristic the descriptor is associated with. So you would know that notifications have been enabled for a descriptor (for example), but the server could have many descriptors (because of many characteristics). If m_pCharacteristic had a public property, it would avoid needing to keep a separate lookup of the descriptors that had been added to characteristics during server initialisation.

To look at it another way; I have a server with a handful of 2902 descriptors, so the callback is not that useful at the moment in determining what clients are subscribing to. I just know they are subscribing to something with a 2902 descriptor.

Thanks for your consideration of this!

Crash on BLEDevice::deleteClient(pClient)

I am trying to reuse the client, so I call BLEDevice::deleteClient(pClient). This causes a crash:

Decoding stack results
0x4008e320: invoke_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c line 156
0x4008e59d: abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c line 171
0x400efb6b: __assert_func at ../../../.././newlib/libc/stdlib/assert.c line 63
0x400837cf: heap_caps_free at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/heap/heap_caps.c line 267
0x4008307d: _free_r at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/newlib/syscalls.c line 42
0x4017de81: operator delete(void*) at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/del_op.cc line 46
0x400d6465: NimBLEClientCallbacks::~NimBLEClientCallbacks() at /home/jeroen/Arduino/libraries/NimBLE-Arduino-master/src/NimBLEClient.h line 101
0x400d6be5: NimBLEClient::~NimBLEClient() at /home/jeroen/Arduino/libraries/NimBLE-Arduino-master/src/NimBLEClient.cpp line 78
0x400d73e6: NimBLEDevice::deleteClient(NimBLEClient*) at /home/jeroen/Arduino/libraries/NimBLE-Arduino-master/src/NimBLEDevice.cpp line 160
0x400d2bf1: readBLEClients() at /home/jeroen/Arduino/test_BLE_02/test_BLE02/test_BLE02.ino line 781
0x400d2c4e: loop() at /home/jeroen/Arduino/test_BLE_02/test_BLE02/test_BLE02.ino line 788
0x400ed9c5: loopTask(void*) at /home/jeroen/Downloads/arduino-1.8.10-linux64/arduino-1.8.10/hardware/espressif/esp32/cores/esp32/main.cpp line 19
0x40093555: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143

This is because BLEClient::m_deleteCallbacks is default true and BLEClient::BLEClient() sets the pointer m_pClientCallbacks to &defaultCallbacks. So before deleting this pointer, it should be checked that it does not point to &defaultCallbacks:

NimBLEClient::~NimBLEClient() { 
    // We may have allocated service references associated with this client.  
    // Before we are finished with the client, we must release resources.
    clearServices();
    
    if(m_deleteCallbacks && m_pClientCallbacks != &defaultCallbacks) {
        delete m_pClientCallbacks;
    }

} // ~NimBLEClient

[ServerDev] Some feedback

Just pulled the latest from ServerDev branch and try to compile simple BLE-Uart code.
Using PlatformIO.

Compilation error due to missing #defines

Compilation failes with

C:\users\beegee\.platformio\packages\framework-arduinoespressif32\tools\sdk\include\bt/esp_bt.h:120:24: error:
'CONFIG_BTDM_CONTROLLER_BR_EDR_SCO_DATA_PATH_EFF' undeclared (first use in this function)
     .bt_sco_datapath = CONFIG_BTDM_CONTROLLER_BR_EDR_SCO_DATA_PATH_EFF,    \
                        ^
lib\NimBLE-Arduino\src\esp-hci\src\esp_nimble_hci.c:453:41: note: in expansion of macro 'BT_CONTROLLER_INIT_CONFIG_DEFAULT'
     esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
                                         ^
C:\users\beegee\.platformio\packages\framework-arduinoespressif32\tools\sdk\include\bt/esp_bt.h:120:24: note: each undeclared identifier is reported only once for each function it appears in
     .bt_sco_datapath = CONFIG_BTDM_CONTROLLER_BR_EDR_SCO_DATA_PATH_EFF,    \
                        ^
lib\NimBLE-Arduino\src\esp-hci\src\esp_nimble_hci.c:453:41: note: in expansion of macro 'BT_CONTROLLER_INIT_CONFIG_DEFAULT'
     esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();

sdkconfig.h in NimBLE library is missing some defines that are set in ESP32-Arduino's :
Solution:
in NimBLE-Arduino->src->sdkconfig.h add

#define CONFIG_BTDM_CONTROLLER_BR_EDR_SCO_DATA_PATH_EFF 1
#define CONFIG_ARDUINO_EVENT_RUNNING_CORE 1

SW crash when starting advertise service

After that code compiles but then crashes with

I NimBLEDevice: "BLE Host Task Started"
GAP procedure initiated: stop advertising.
I NimBLEDevice: "NimBle host synced."
E NimBLEAdvertising: "error setting advertisement data; rc=4, The provided buffer is too small."
abort() was called at PC 0x400d7b64 on core 1

Backtrace: 0x400916a8:0x3ffc7290 0x400918d9:0x3ffc72b0 0x400d7b64:0x3ffc72d0 0x400d24a2:0x3ffc7310 0x400d4a50:0x3ffc7360 0x400ec08f:0x3ffc73a0 0x4008dd2d:0x3ffc73c0

Rebooting...
ets Jun  8 2016 00:22:57

Backtrace decoded

Decoding stack results
0x400916a8: invoke_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c line 155
0x400918d9: abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c line 170
0x400d7b64: NimBLEAdvertising::start() at lib\NimBLE-Arduino\src\NimBLEAdvertising.cpp line 269
0x400d24a2: initBLE() at src\BLE\ble_esp32.cpp line 174
0x400d4a50: setup() at src\main.cpp line 107
0x400ec08f: loopTask(void*) at C:\users\beegee\.platformio\packages\framework-arduinoespressif32\cores\esp32\main.cpp line 14
0x4008dd2d: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143

Adverting part of my code:

#include "main.h"
#include <NimBLEUtils.h>
#include <NimBLEServer.h>
#include <NimBLEDevice.h>
#include <NimBLEAdvertising.h>

/** Service UUID for Uart */
#define UART_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
/** Characteristic UUID for receiver */
#define RX_UUID "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
/** Characteristic UUID for transmitter */
#define TX_UUID "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

/** Characteristic for BLE-UART TX */
BLECharacteristic *pCharacteristicUartTX;
/** Characteristic for BLE-UART RX */
BLECharacteristic *pCharacteristicUartRX;
/** BLE Advertiser */
BLEAdvertising *pAdvertising;
/** BLE Service for Uart*/
BLEService *uartService;
/** BLE Server */
BLEServer *pServer;

/** Flag if a device is connected */
bool bleUARTisConnected = false;

/** Flag if client notification is enabled */
bool bleUARTnotifyEnabled = false;

/** RX and TX buffer size */
#define BUFF_SIZE 253

/** Buffer for outgoing data */
uint8_t txData[BUFF_SIZE] = {0};
/** Buffer for incoming data */
uint8_t rxData[BUFF_SIZE] = {0};
/** Number of bytes in the of incoming data buffer */
size_t rxLen = 0;

/** Mutex used to enter critical code part (RX data buffer access) */
SemaphoreHandle_t _mutex;

/**
 * Callbacks for client connection and disconnection
 */
class MyServerCallbacks : public BLEServerCallbacks
{
	void onConnect(BLEServer *pServer)
	{
		myLog_d("BLE client connected");
		pServer->updatePeerMTU(pServer->getConnId(), 260);
		bleUARTisConnected = true;
	};

	void onDisconnect(BLEServer *pServer)
	{
		myLog_d("BLE client disconnected");
		bleUARTisConnected = false;
		bleUARTnotifyEnabled = false;
		pAdvertising->start();
	}
};

/**
 * Callbacks for BLE client read/write requests
 * on BLE UART characteristic
 */
class UartTxCbHandler : public BLECharacteristicCallbacks
{
	void onWrite(BLECharacteristic *pCharacteristic)
	{
		std::string rxValue = pCharacteristic->getValue();
		rxLen = rxValue.size();

		xSemaphoreTake(_mutex, portMAX_DELAY);
		// if ((rxLen > 0) && (dataRcvd == false))
		if (rxLen > 0)
		{
			strncpy((char *)rxData, rxValue.c_str(), 253);

			myLog_d("UART write callback received %s", (char *)rxData);
		}
		xSemaphoreGive(_mutex);
	};
};

/**
 * Initialize nRF52 BLE UART
 */
void initBLE(void)
{
	char apName[] = "EC-xxxxxxxxxxxx";
	// Using ESP32 MAC (48 bytes only, so upper 2 bytes will be 0)
	sprintf(apName, "EC-%08X", deviceID);
	myLog_d("Device name: %s", apName);

	// Create mutex for access to RX data buffer
	_mutex = xSemaphoreCreateMutex();
	xSemaphoreGive(_mutex);

	// Initialize BLE and set output power
	BLEDevice::init(apName);
	BLEDevice::setMTU(260);
	BLEDevice::setPower(ESP_PWR_LVL_P7);

	myLog_d("BLE address: %s", BLEDevice::getAddress().toString().c_str());

	// Create BLE Server
	pServer = BLEDevice::createServer();

	// Set server callbacks
	pServer->setCallbacks(new MyServerCallbacks());

	// Create the UART BLE Service
	uartService = pServer->createService(UART_UUID);

	// Create a BLE Characteristic
	pCharacteristicUartTX = uartService->createCharacteristic(
		TX_UUID,
		BLECharacteristic::PROPERTY_NOTIFY |
			BLECharacteristic::PROPERTY_READ);

	// Register callback for notification enabled
	pCharacteristicUartTX->setNotifyProperty(true);

	pCharacteristicUartRX = uartService->createCharacteristic(
		RX_UUID,
		BLECharacteristic::PROPERTY_WRITE);

	pCharacteristicUartRX->setCallbacks(new UartTxCbHandler());

	// Start the service
	uartService->start();

	// Start advertising
	pAdvertising = pServer->getAdvertising();
	pAdvertising->addServiceUUID(UART_UUID);
	pAdvertising->start();
}

Maybe I am missing something in the setup of the advertising service???

Missing feature

Maybe I did miss it, but I used to set a callback on the characteristic descriptor to get a callback if the client enables notifications.
What I used was

...
#include <BLE2902.h>
#include <esp_bt_device.h>
...
/** Descriptor for the BLE-UART TX characteristic */
BLEDescriptor *txDescriptor;
 ...
/**
 * Callbacks for BLE client descriptor changes
 * on BLE UART characteristic
 */
class DescriptorCallbacks : public BLEDescriptorCallbacks
{
	void onWrite(BLEDescriptor *pDescriptor)
	{
		uint8_t *descrValue;
		descrValue = pDescriptor->getValue();
		if (descrValue[0] & (1 << 0))
		{
			bleUARTnotifyEnabled = true;
		}
		else
		{
			bleUARTnotifyEnabled = false;
		}
	};
};
...
void initBLE(void)
{
...
	// Create a BLE Characteristic
	pCharacteristicUartTX = uartService->createCharacteristic(
		TX_UUID,
		BLECharacteristic::PROPERTY_NOTIFY |
			BLECharacteristic::PROPERTY_READ);

	pCharacteristicUartTX->addDescriptor(new BLE2902());
	txDescriptor = pCharacteristicUartTX->getDescriptorByUUID("2902");
	if (txDescriptor != NULL)
	{
		txDescriptor->setCallbacks(new DescriptorCallbacks());
	}
...
}

Not sure how to do this with NimBLE.

I think the use of std::string as a container for data is wrong

Everywhere in the library a std::string is used to store data as some kind of buffer, e.g service data, remote characteristic values, manufacturer data, etc. I believe that this data is binary, and so may include bytes of 0x00. But if a std::string is created with a zero somewhere in the middle, it is truncated at this zero as demonstrated by below sketch:

#include <string>

void setup() {
  Serial.begin(115200);
  Serial.println("\n\nStarted");

  std::string demonstrate("\x35\x34\x33\x32\x31\x00\x31\x32\x33\x34\x35");
  Serial.printf("The length of the string is %u, it's size is %u and it's value is '%s'\n", demonstrate.length(), demonstrate.size(), demonstrate.c_str());
}

void loop() {
  // put your main code here, to run repeatedly:

}

The output of this small program is:

Started
The length of the string is 5, it's size is 5 and it's value is '54321'

It is fully logical that length() == 5. If size() would be 11, then the underlying data could be fully retrieved. But since this is also 5, the zero byte and the 5 bytes following the zero will be truncated, if such data was sent by a device.

I think there are two options:

  • Use a uint8_t buffer[] everywhere. Also return a (const) uint8_t * pointer for e.g. the readValue() functions. Pro: easy, con: memory mgt is needed
  • Use a vector<uint8_t> everywhere. Also return a (const) vector<uint8_t> & for e.g. readValue(). Pro: no memory mgt is needed, the getSize() functions can be removed because the vector::size() can be used. Con: a STL container is used instead of a plain array.
    Both options will break @h2zero's strategy to remain compatible with the original BLE library. But if I am right I think this is needed!

[NimBLEClient] When connecting multiple devices, a Panic error occurs on the third device

I am testing with multiple BLE Buttons with Bluetooth HID profile.
Pressing the button shows the equivalent behavior of pressing a key on the keyboard.

It seems to be very very stable compared to the original BLEClient !!

In simultaneous connection, if the number of BLE Buttons is one or two, no problem has been found, but if it is three, a Panic error will occur immediately after pairing.

#include <NimBLEDevice.h>

static void notifyCallback(BLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify)  {
  Serial.printf("notifyCallback: %s %s handle: %02x value:", pRemoteCharacteristic->getRemoteService()->getClient()->getPeerAddress().toString().c_str(), pRemoteCharacteristic->getUUID().toString().c_str(), pRemoteCharacteristic->getHandle());
  for (int i=0; i<length; i++)
    Serial.printf(" %02x", pData[i]);
  Serial.println();
}

void setup() {
  Serial.begin(115200);

  NimBLEDevice::init("");
  auto* pBLEScan = NimBLEDevice::getScan();
  pBLEScan->setActiveScan(true);

  Serial.println("wait 10 secs..");
  auto pScanResults = pBLEScan->start(10);

  for (int i = 0; i < pScanResults.getCount(); i++) {
    auto advertisedDevice = pScanResults.getDevice(i);
    if (advertisedDevice.haveServiceUUID())  {
      Serial.print("Found Device ");
      Serial.print(advertisedDevice.toString().c_str());
      auto pClient = NimBLEDevice::createClient();
      if(pClient && pClient->connect(&advertisedDevice)) {
        auto* pRemoteServiceMap = pClient->getServices();
        for (auto itr : *pRemoteServiceMap)  {
          auto *pCharacteristicMap = itr.second->getCharacteristicsByHandle();
          for (auto itr : *pCharacteristicMap)
            if(itr.second->canNotify())
              if(itr.second->registerForNotify(notifyCallback)) {
                Serial.printf("registerForNotify: %s %s handle:%02x", pClient->getPeerAddress().toString().c_str(), itr.second->getUUID().toString().c_str(), itr.second->getHandle());
                Serial.println();
              }
        }
      }
    }
  }
}

void loop() {
  delay(1);
}

The log is too long, so here is the most recent panic error:

06:22:14.081 -> D NimBLERemoteCharacteristic: ">> registerForNotify(): Characteristic: uuid: 0x2a4d, handle: 23 0x0017, props:  0x12
06:22:14.081 -> Descriptor: uuid: 0x2902, handle: 24
06:22:14.128 -> Descriptor: uuid: 0x2908, handle: 25"
06:22:14.128 -> D NimBLERemoteCharacteristic: ">> getDescriptor: uuid: 0x2902"
06:22:14.128 -> D NimBLERemoteCharacteristic: "<< getDescriptor: found"
06:22:14.128 -> D NimBLERemoteCharacteristic: "<< registerForNotify()"
06:22:14.128 -> D NimBLERemoteDescriptor: ">> Descriptor writeValue: Descriptor: uuid: 0x2902, handle: 24"
06:22:14.128 -> D FreeRTOS: "Semaphore taking: name: WriteDescEvt (0x3ffd2178), owner: <N/A> for WriteDescriptor"
06:22:14.128 -> D FreeRTOS: "Semaphore taken:  name: WriteDescEvt (0x3ffd2178), owner: WriteDescriptor"
06:22:14.128 -> D FreeRTOS: ">> wait: Semaphore waiting: name: WriteDescEvt (0x3ffd2178), owner: WriteDescriptor for WriteDescriptor"
06:22:14.221 -> D NimBLERemoteDescriptor: "Write complete; status=0 conn_handle=2"
06:22:14.221 -> D FreeRTOS: "Semaphore giving: name: WriteDescEvt (0x3ffd2178), owner: WriteDescriptor"
06:22:14.221 -> D FreeRTOS: "<< wait: Semaphore released: name: WriteDescEvt (0x3ffd2178), owner: <N/A>"
06:22:14.221 -> D NimBLERemoteDescriptor: "<< Descriptor writeValue, rc: 0"
06:22:14.221 -> registerForNotify: ff:ff:c5:05:f5:2a 0x2a4d handle:17
06:22:15.066 -> D NimBLEClient: "Got Client event BLE_GAP_EVENT_L2CAP_UPDATE_REQ"
06:22:15.066 -> D NimBLEClient: "Peer requesting to update connection parameters"
06:22:15.066 -> D NimBLEClient: "MinInterval: 16, MaxInterval: 32, Latency: 2, Timeout: 100, min_ce_len:16,max_ce_len:768"
06:22:15.066 -> Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.
06:22:15.066 -> Core 0 register dump:
06:22:15.066 -> PC      : 0x401184d6  PS      : 0x00060130  A0      : 0x80049b9c  A1      : 0x3ffb5d40  
06:22:15.066 -> A2      : 0x07ffffff  A3      : 0x00009660  A4      : 0x000000a8  A5      : 0x00000001  
06:22:15.113 -> A6      : 0x3ffb5da0  A7      : 0x00000000  A8      : 0x3ffb2ec4  A9      : 0x3ffb5d20  
06:22:15.113 -> A10     : 0x0030bb00  A11     : 0x00000001  A12     : 0x00000000  A13     : 0x3ffafd68  
06:22:15.113 -> A14     : 0x00000000  A15     : 0x3ffb8360  SAR     : 0x00000016  EXCCAUSE: 0x0000001c  
06:22:15.113 -> EXCVADDR: 0x00000008  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0x00000000  
06:22:15.113 -> 
06:22:15.113 -> ELF file SHA256: 0000000000000000000000000000000000000000000000000000000000000000
06:22:15.113 -> 
06:22:15.113 -> Backtrace: 0x401184d6:0x3ffb5d40 0x40049b99:0x3ffb5da0 0x400457cd:0x3ffb5dd0 0x4001a637:0x3ffb5e10 0x40019d11:0x3ffb5e40 0x40055b4d:0x3ffb5e60 0x40112ddf:0x3ffb5e80 0x40113331:0x3ffb5ea0 0x4009066d:0x3ffb5ed0
06:22:15.113 -> 
06:22:15.113 -> Rebooting...
06:22:15.160 -> ets Jun  8 2016 00:22:57

I don't know how to look at the backtrace, but it seems that an error occurs immediately after NimBLEClient :: handleGapEvent receives BLE_GAP_EVENT_L2CAP_UPDATE_REQ generated by the device and returns rc = 0 indicating normality.

Forcing the device to reject the request does not cause the Panic error, albeit with a different problem.

        case BLE_GAP_EVENT_CONN_UPDATE_REQ:
        case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: {
            if(client->m_conn_id != event->conn_update_req.conn_handle){
                return 0; //BLE_HS_ENOTCONN BLE_ATT_ERR_INVALID_HANDLE
            }
            return BLE_ERR_CONN_PARMS;   // Adding this line will avoid Panic errors, but ... 

Is there anything you can think of ?
I'm just getting started with JTAG, but I'm glad if I can tell you what to try.

Possibility to identify the client accessing a characteristic

I am in the process of migrating from bluedroid stack to NimBLE. However, there is one feature I have been unable to achieve in the old stack, and it seems that thanks to the feature parity, the same problem exists in NimBLE.

Assuming BLEServer multiconnect, I need to determine the address of the device that is currently writing to the characteristic I exposed with BLEServer.

It seems that all that is needed is to pass the conn_handle parameter of NimBLECharacteristic::handleGapEvent in the onWrite callback. Is this correct or am I missing something?

I envision an approach analogous to NimBLEServer dual callback call:

server->m_pServerCallbacks->onConnect(server);
server->m_pServerCallbacks->onConnect(server, &desc); 

Since in the onConnect callback I can retrieve the conn_handle from ble_gap_conn_desc passed as &desc I could either keep the map of conn_handles and addresses, or use ble_gap_conn_find to find what the peer address for the given conn_handle is (assuming that the onWrite callback will receive the conn_handle as the second parameter).

Please be so kind to point any shortcomings of my reasoning, and if it should indeed work, let me know if I should create a PR for this.

Migrating ESP32-BLECollector

hello and thank you for this great library!

It totally removed the burden of having to deal with "does not fit in ram" situations.

So after migrating my code to the new NimBLE syntax, I found out I was initially using a modified version of the official BLE library and manually applied a few patches.

I was pleasantly surprised to see that most of those changes are already adressed in your library 👍

However I couldn't find a matching method for one missing method pChar->getDataLength().

In my project getDataLength() is used for file transfer situations with variable MTU.

In order to get my sketch working and go on with more tests, I added this to src/NimBLECharacteristic.h.

size_t getDataLength() { return m_value.getLength(); }

So my question is: do I really need to modify src/NimBLECharacteristic.h to get the lenght of the data or is there a way to do that more elegantly ?

Can not connect a second time to a re-created client

MVCE

#include <NimBLEDevice.h>


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("\n\nStarted");

  BLEDevice::init("ESP32");

  Serial.println("Create");
  NimBLEClient *pClient = BLEDevice::createClient();
  Serial.println("Connecting...");
  bool success = pClient->connect(NimBLEAddress("a4:c1:38:5d:ef:16"));
  if(success) {
    Serial.println("Connected");
    pClient->disconnect();
    Serial.println("Disconnected");

    BLEDevice::deleteClient(pClient);
    Serial.println("Create");
    pClient = BLEDevice::createClient();
    
    Serial.println("Connecting...");
    success = pClient->connect(NimBLEAddress("a4:c1:38:5d:ef:16"));
    if(success) {
      Serial.println("Connected");
      pClient->disconnect();
      Serial.println("Disconnected");
    }
  }
}

void loop() {
  // put your main code here, to run repeatedly:

}

Logging:

Started
I NimBLEDevice: "BLE Host Task Started"
I NimBLEDevice: "NimBle host synced."
Create
Connecting...
D NimBLEClient: ">> connect(a4:c1:38:5d:ef:16)"
D FreeRTOS: "Semaphore taking: name: OpenEvt (0x3ffc8870), owner: <N/A> for connect"
D FreeRTOS: "Semaphore taken:  name: OpenEvt (0x3ffc8870), owner: connect"
D FreeRTOS: ">> wait: Semaphore waiting: name: OpenEvt (0x3ffc8870), owner: connect for connect"
D NimBLEClient: "Got Client event "
D NimBLEClient: "Connection established"
D FreeRTOS: "Semaphore giving: name: OpenEvt (0x3ffc8870), owner: connect"
D FreeRTOS: "<< wait: Semaphore released: name: OpenEvt (0x3ffc8870), owner: <N/A>"
D NimBLEClient: "Refreshing Services for: (a4:c1:38:5d:ef:16)"
D NimBLEClient: ">> deleteServices"
D NimBLEClient: "<< deleteServices"
D NimBLEClientCallbacks: "onConnect: default"
D NimBLEClient: "<< connect()"
Connected
D NimBLEClient: ">> disconnect()"
D NimBLEClient: "<< disconnect()"
Disconnected
D NimBLEClient: ">> deleteServices"
D NimBLEClient: "<< deleteServices"
Create
Connecting...
D NimBLEClient: ">> connect(a4:c1:38:5d:ef:16)"
D FreeRTOS: "Semaphore taking: name: OpenEvt (0x3ffc8870), owner: <N/A> for connect"
D FreeRTOS: "Semaphore taken:  name: OpenEvt (0x3ffc8870), owner: connect"
D FreeRTOS: ">> wait: Semaphore waiting: name: OpenEvt (0x3ffc8870), owner: connect for connect"
D NimBLEClient: "Got Client event "
D NimBLEClient: "Got Client event "

... and then just "hangs"

Undefined reference to 'ble_uuid_cmp'

Very excited about this port!

I've hit a weird snag trying to compile this. I'm running ESP-IDF 3.2 and trying to replace an existing BLE implementation. Compiling works, then I hit this during the GNU linker: (some paths snipped for line length)

LD build/soulmate-example.elf
build/nimble/libnimble.a(NimBLECharacteristic.o):(.literal._ZN20NimBLECharacteristic14handleGapEventEttP20ble_gatt_access_ctxtPv+0x0): undefined reference to `ble_uuid_cmp'
build/nimble/libnimble.a(NimBLECharacteristic.o):(.literal._ZN20NimBLECharacteristic14handleGapEventEttP20ble_gatt_access_ctxtPv+0x4): undefined reference to `os_mbuf_append'
build/nimble/libnimble.a(NimBLECharacteristic.o):(.literal._ZN20NimBLECharacteristic6notifyEb+0x14): undefined reference to `ble_hs_mbuf_from_flat'
build/nimble/libnimble.a(NimBLECharacteristic.o):(.literal._ZN20NimBLECharacteristic6notifyEb+0x18): undefined reference to `ble_gattc_indicate_custom'
build/nimble/libnimble.a(NimBLECharacteristic.o):(.literal._ZN20NimBLECharacteristic6notifyEb+0x1c): undefined reference to `ble_gattc_notify_custom'
build/nimble/libnimble.a(NimBLECharacteristic.o): In function `NimBLECharacteristic::handleGapEvent(unsigned short, unsigned short, ble_gatt_access_ctxt*, void*)':
nimble/src/NimBLECharacteristic.cpp:144: undefined reference to `ble_uuid_cmp'
nimble/src/NimBLECharacteristic.cpp:144: undefined reference to `os_mbuf_append'
build/nimble/libnimble.a(NimBLECharacteristic.o): In function `std::map<unsigned short, unsigned short, std::less<unsigned short>, std::allocator<std::pair<unsigned short const, unsigned short> > >::erase(unsigned short const&)':
nimble/src/NimBLECharacteristic.cpp:144: undefined reference to `ble_hs_mbuf_from_flat'
build/nimble/libnimble.a(NimBLECharacteristic.o): In function `NimBLECharacteristic::notify(bool)':
nimble/src/NimBLECharacteristic.cpp:144: undefined reference to `ble_gattc_indicate_custom'
build/nimble/libnimble.a(NimBLECharacteristic.o): In function `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()':
nimble/src/NimBLECharacteristic.cpp:144: undefined reference to `ble_gattc_notify_custom'
build/nimble/libnimble.a(NimBLEDescriptor.o): In function `NimBLEDescriptor::handleGapEvent(unsigned short, unsigned short, ble_gatt_access_ctxt*, void*)':
nimble/src/NimBLEDescriptor.cpp:134: undefined reference to `ble_uuid_cmp'
nimble/src/NimBLEDescriptor.cpp:138: undefined reference to `os_mbuf_append'
build/nimble/libnimble.a(NimBLEDevice.o):(.literal._ZN12NimBLEDevice9host_taskEPv+0x0): undefined reference to `nimble_port_run'
build/nimble/libnimble.a(NimBLEDevice.o):(.literal._ZN12NimBLEDevice9host_taskEPv+0x4): undefined reference to `nimble_port_freertos_deinit'
build/nimble/libnimble.a(NimBLEDevice.o):(.literal._ZN12NimBLEDevice6onSyncEv+0x10): undefined reference to `ble_hs_util_ensure_addr'
build/nimble/libnimble.a(NimBLEDevice.o):(.literal._ZN12NimBLEDevice12createServerEv+0x4): undefined reference to `ble_gatts_reset'
build/nimble/libnimble.a(NimBLEDevice.o):(.literal._ZN12NimBLEDevice12createServerEv+0x8): undefined reference to `ble_svc_gap_init'
build/nimble/libnimble.a(NimBLEDevice.o):(.literal._ZN12NimBLEDevice12createServerEv+0xc): undefined reference to `ble_svc_gatt_init'
build/nimble/libnimble.a(NimBLEDevice.o):(.literal._ZN12NimBLEDevice4initENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+0x18): undefined reference to `ble_hs_cfg'
build/nimble/libnimble.a(NimBLEDevice.o):(.literal._ZN12NimBLEDevice4initENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+0x24): undefined reference to `ble_store_util_status_rr'
build/nimble/libnimble.a(NimBLEDevice.o):(.literal._ZN12NimBLEDevice4initENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+0x30): undefined reference to `esp_nimble_hci_and_controller_init'
build/nimble/libnimble.a(NimBLEDevice.o):(.literal._ZN12NimBLEDevice4initENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+0x34): undefined reference to `nimble_port_init'
build/nimble/libnimble.a(NimBLEDevice.o):(.literal._ZN12NimBLEDevice4initENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+0x38): undefined reference to `ble_svc_gap_device_name_set'
build/nimble/libnimble.a(NimBLEDevice.o):(.literal._ZN12NimBLEDevice4initENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+0x3c): undefined reference to `ble_store_config_init'
build/nimble/libnimble.a(NimBLEDevice.o):(.literal._ZN12NimBLEDevice4initENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+0x40): undefined reference to `nimble_port_freertos_init'
build/nimble/libnimble.a(NimBLEDevice.o): In function `NimBLEDevice::host_task(void*)':
nimble/src/NimBLEDevice.cpp:659: undefined reference to `nimble_port_run'
nimble/src/NimBLEDevice.cpp:659: undefined reference to `nimble_port_freertos_deinit'
build/nimble/libnimble.a(NimBLEDevice.o): In function `NimBLEDevice::onSync()':
nimble/src/NimBLEDevice.cpp:659: undefined reference to `ble_hs_util_ensure_addr'
build/nimble/libnimble.a(NimBLEDevice.o): In function `NimBLEDevice::createServer()':
nimble/src/NimBLEDevice.cpp:659: undefined reference to `ble_gatts_reset'
nimble/src/NimBLEDevice.cpp:659: undefined reference to `ble_svc_gap_init'
nimble/src/NimBLEDevice.cpp:659: undefined reference to `ble_svc_gatt_init'
build/nimble/libnimble.a(NimBLEDevice.o): In function `NimBLEDevice::init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
nimble/src/NimBLEDevice.cpp:659: undefined reference to `esp_nimble_hci_and_controller_init'
nimble/src/NimBLEDevice.cpp:659: undefined reference to `nimble_port_init'
nimble/src/NimBLEDevice.cpp:659: undefined reference to `ble_svc_gap_device_name_set'
nimble/src/NimBLEDevice.cpp:659: undefined reference to `ble_store_config_init'

[Feature proposal] Purpose of facilitating client reconnection process

As I wrote the issue before, I mainly use BLEClient.
Issue at the time #7

In the process, it would be useful to have the following features.

What I really want:

  1. uint8_t NimBLEClient::getPeerType()
    With getPeerAddress, I can get the most recently used BLE-Address(m_peerAddress), but can't get PeerType.
    I want to implement m_peerType as well as m_peerAddress
uint8_t NimBLEClient::getPeerType() {
    return m_peerType;
} // getPeerType
  1. Change the operation when the argument is omitted
    -NimBLEClient::getServices(bool refresh = false)
    -NimBLERemoteService::getCharacteristics(bool refresh = false)
    -NimBLERemoteCharacteristic::getDescriptors(bool refresh = false)
    Although it is (bool refresh = false), it is better to use (bool refresh = true) only for the first time.
std::vector<NimBLERemoteService*>* NimBLEClient::getServices() {
	return getServices(m_servicesVector.size() == 0);
} // getServices
std::vector<NimBLERemoteCharacteristic*>* NimBLERemoteService::getCharacteristics() {
    return getCharacteristics(m_characteristicVector.size() == 0);
} // getCharacteristics
std::vector<NimBLERemoteDescriptor*>* NimBLERemoteCharacteristic::getDescriptors() {
	return getDescriptors(m_descriptorVector.size() == 0);
} // getDescriptors

What I want:

  1. Specify the connection destination at the time of NimBLEDevice::createClient()
    Since I can't connect during scan, I want to createClient in advance and connect after scan.
static NimBLEClient*    createClient(NimBLEAdvertisedDevice* device = nullptr);
/* STATIC */ NimBLEClient* NimBLEDevice::createClient(NimBLEAdvertisedDevice* device) {
    if(m_cList.size() >= NIMBLE_MAX_CONNECTIONS) {
        NIMBLE_LOGW("Number of clients exceeds Max connections. Max=(%d)",
                                            NIMBLE_MAX_CONNECTIONS);
    	return nullptr;
    }
	
    NimBLEClient* pClient;
    if(device == nullptr)
        pClient = new NimBLEClient();
    else
        pClient = new NimBLEClient(device);
    
    m_cList.push_back(pClient);

    return pClient;
} // createClient
NimBLEClient::NimBLEClient(NimBLEAdvertisedDevice* device) : NimBLEClient()
{
    m_peerAddress = device->getAddress();
    m_peerType = device->getAddressType();
} // NimBLEClient

Then connect to the destination specified in createClient or the previous destination

bool NimBLEClient::connect(bool refreshServices) {
    return connect(m_peerAddress, m_peerType, refreshServices);
}

What do you think ?
I'll create a branch for PullRequest if needed.

A quick question - Set Mac address (iBeacon)

A quick one; Is it possible to set the mac address when using this iBeacon example?

I have a peculiar case where I have no choice but to change the mac address. In short the other scanners should see the mac address that I have set rather than the real mac address of the iBeacon. Any pointers? Thanks.

[Feature Request] Ability to clean up memory

In my situation I am only using ble to do setup, so after my device is set up I would like to be able to completely clean up the memory and move on. So it would be great if there was a method to clean up the singletons, or some way for me to delete.

I have found I can do most with client code, but the singleton objects are impossible to fix up without library changes.

Here is what I was thinking


void NimBLEDevice::cleanup() {
  if(NimBLEDevice::m_pServer == nullptr) {
      delete NimBLEDevice::m_pServer;
      NimBLEDevice::m_pServer = nullptr;
   }
  if(NimBLEDevice::m_bleAdvertising== nullptr) {
      delete NimBLEDevice::m_bleAdvertising;
      NimBLEDevice::m_bleAdvertising= nullptr;
   }
  if(NimBLEDevice::m_pScan== nullptr) {
      delete NimBLEDevice::m_pScan;
      NimBLEDevice::m_pScan= nullptr;
   }
   for(auto it = m_cList.cbegin(); it != m_cList.cend(); ++it)
   {
      deleteClient(*it);
   }
   // Whatever other clean up needs to be done.
  
}

Any idea why it crashes?

I have a too complicated sketch to publish, but I create clients, connect, read, disconnect and delete clients in a loop with 3 peripherals. I need to analyse it better myself, but maybe @h2zero has an idea already?

I get every now and then crashes like:

0x400961ed: multi_heap_free at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/heap/multi_heap_poisoning.c line 214
0x400837b6: heap_caps_free at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/heap/heap_caps.c line 268
0x4008307d: _free_r at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/newlib/syscalls.c line 42
0x4015a0f9: operator delete(void*) at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/del_op.cc line 46
0x400d6d26: NimBLEDevice::removeIgnored(NimBLEAddress const&) at /home/jeroen/Downloads/arduino-1.8.10-linux64/arduino-1.8.10/hardware/espressif/esp32/tools/xtensa-esp32-elf/xtensa-esp32-elf/include/c++/5.2.0/ext/new_allocator.h line 110
0x400d5e44: NimBLEClient::handleGapEvent(ble_gap_event*, void*) at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/NimBLEClient.cpp line 641
0x400dbdc9: ble_gap_call_event_cb at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/nimble/host/src/ble_gap.c line 628
0x400dcb8a: ble_gap_conn_broken at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/nimble/host/src/ble_gap.c line 1086
0x400dcbb8: ble_gap_rx_disconn_complete at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/nimble/host/src/ble_gap.c line 1113
0x400e17ea: ble_hs_hci_evt_disconn_complete at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/nimble/host/src/ble_hs_hci_evt.c line 157
0x400e1b58: ble_hs_hci_evt_process at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/nimble/host/src/ble_hs_hci_evt.c line 889
0x400df939: ble_hs_event_rx_hci_ev at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/nimble/host/src/ble_hs.c line 520
0x400e772a: nimble_port_run at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/nimble/nimble_npl_os.h line 121
0x400d696f: NimBLEDevice::host_task(void*) at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/NimBLEDevice.cpp line 429
0x40093535: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143

and like

0x40092ea9: xQueueGenericSend at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/queue.c line 720
0x400d4a15: FreeRTOS::Semaphore::give() at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/FreeRTOS.cpp line 153
0x400d4a35: FreeRTOS::Semaphore::give(unsigned int) at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/FreeRTOS.cpp line 169
0x400d5e6c: NimBLEClient::handleGapEvent(ble_gap_event*, void*) at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/NimBLEClient.cpp line 666
0x400dbdc9: ble_gap_call_event_cb at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/nimble/host/src/ble_gap.c line 628
0x400dcb8a: ble_gap_conn_broken at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/nimble/host/src/ble_gap.c line 1086
0x400dcbb8: ble_gap_rx_disconn_complete at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/nimble/host/src/ble_gap.c line 1113
0x400e17ea: ble_hs_hci_evt_disconn_complete at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/nimble/host/src/ble_hs_hci_evt.c line 157
0x400e1b58: ble_hs_hci_evt_process at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/nimble/host/src/ble_hs_hci_evt.c line 889
0x400df939: ble_hs_event_rx_hci_ev at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/nimble/host/src/ble_hs.c line 520
0x400e772a: nimble_port_run at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/nimble/nimble_npl_os.h line 121
0x400d696f: NimBLEDevice::host_task(void*) at /home/jeroen/Arduino/libraries/NimBLE-Arduino/src/NimBLEDevice.cpp line 429
0x40093535: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143

Any idea why?

Just want to thank you all!

i just want to thank you guys for giving life to ESP32 BLE

@h2zero for pickup up the pieces on the old stale repository
@Jeroen88 for all the performance/memory improvements

(i'm using the non Arduino version, but the core the same)

thanks,
Mitch

Upcoming major update.

I'd like to thank all of you who have taken an interest in this library and I hope it's working well for you, and if not, please report an issue and/or PR, they are always welcome!

I have been working on "finalizing" a v1.0 release and been involved with sorting out a few issues upstream. Some of you may have noticed I have changed my stance slightly by modifying the main NimBLE files when necessary to fix an issue. These changes have mostly been merged upstream in the mynewt/nimble repo and there is still one, possibly a second in the works in the espressif/esp-nimble repo.

The nature of this library, essentially, is it is a CPP wrapper on a fork of a fork and originally I didn't want to change too much from the official esp-nimble fork. However the development of this library has exposed some issues in the upstream repos and your posted issues have helped make significant improvements!

That said I would like to encourage anyone who is interested to checkout the resync-to-esp-nimble-master+patches and or client-long-read-write branches and post any issues you encounter.

Minor feature requests are also encouraged as the goal is to make this library as useful and stable as possible. Major features, such as BLE mesh will be on the todo list for future updates, hopefully not too far in the future.

Again, thank you all for your contributions!

Unable to add binary data with '\0' in the advertisement. [patch code inside]

Good morning,
i had to add an overload to the function addData of NinBLEAdvertising class in order to bypass the problem caused by the using of std::string as raw binary buffer.

Here the overload:

/**
 * @brief Add data to the payload to be advertised.
 * @param [in] data The data to be added to the payload.
 * @param [in] length The size of data to be added to the payload.
 */
void NimBLEAdvertisementData::addData(char * data, size_t length){
    if ((m_payload.length() + length) > BLE_HS_ADV_MAX_SZ) {
        return;
    }
    m_payload.append(data,length);
} // addData

You can test this case with the eddystone beacon example by changing the url with one that start with "http://www.", because this match eddystone_url_prefix_subs at 0 index.

Best regards and good job

only BLE server liberary

For some application need only BLE server library. Can free more heap. Please guide me to remove other functionalities apart from the basic ble serverl

Problems connecting during an infinite scan

If I start an infinite scan and next try to connect to an available address or a non existing address, it seems that the stack is busy scanning, but the connection process does not time-out, nor connects.

MVCE:

#include <Arduino.h>
#include <NimBLEDevice.h>

BLEClient *pClient = nullptr;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(230400);
  Serial.println("/n/nStarted");

  BLEDevice::init("ESP32");

  Serial.println("Start background scan forever...");
  static BLEScan *pBLEScan = BLEDevice::getScan(); //create new scan
  pBLEScan->setActiveScan(false);
  pBLEScan->setInterval(256);
  pBLEScan->setWindow(255);

  pBLEScan->start(0, nullptr, false);
  Serial.println("Background scan started");

  pClient = BLEDevice::createClient();

//  BLEAddress address("a4:c1:38:5d:ef:16");
  BLEAddress address("01:02:03:04:05:06");
  Serial.println("Connecting...");
  pClient = BLEDevice::createClient();
  bool success = pClient->connect(address);
  if(!success) {
    Serial.println("Failed to connect");
  } else {
    Serial.println("Connected!");
    pClient->disconnect();
  }
  BLEDevice::deleteClient(pClient);
}

void loop() {
  // put your main code here, to run repeatedly:

}

If I limit the scan for e.g. 10s and do the same test after the scan everything works as expected. Below is about 1 minute logging for the invalid address. No timeouts occur. The logging for the existing address is similar.

I NimBLEDevice: "BLE Host Task Started"
I NimBLEDevice: "NimBle host synced."
Start background scan forever...
D NimBLEScan: ">> start(duration=0)"
D FreeRTOS: "Semaphore taking: name: ScanEnd (0x3ffc88cc), owner: <N/A> for start"
D FreeRTOS: "Semaphore taken:  name: ScanEnd (0x3ffc88cc), owner: start"
D NimBLEScan: "<< start()"
Background scan started
Connecting...
D NimBLEClient: ">> connect(01:02:03:04:05:06)"
D FreeRTOS: "Semaphore taking: name: OpenEvt (0x3ffc8c4c), owner: <N/A> for connect"
D FreeRTOS: "Semaphore taken:  name: OpenEvt (0x3ffc8c4c), owner: connect"
I NimBLEScan: "NEW DEVICE FOUND: 70:56:81:df:dd:15"
D NimBLEAdvertisedDevice: "- setRSSI(): rssi: -80"
D NimBLEAdvertisedDevice: "- manufacturer data: 4c0009060202c0a8b2dc"
I NimBLEScan: "NEW DEVICE FOUND: a4:c1:38:5d:ef:16"
D NimBLEAdvertisedDevice: "- setRSSI(): rssi: -59"
I NimBLEScan: "NEW DEVICE FOUND: 58:2d:34:39:22:58"
D NimBLEAdvertisedDevice: "- setRSSI(): rssi: -72"
I NimBLEScan: "NEW DEVICE FOUND: 9c:20:7b:de:4c:ad"
D NimBLEAdvertisedDevice: "- setRSSI(): rssi: -94"
D NimBLEAdvertisedDevice: "- manufacturer data: 4c0009060201c0a8b20a"
I NimBLEScan: "NEW DEVICE FOUND: ac:9a:22:cd:12:91"
D NimBLEAdvertisedDevice: "- setRSSI(): rssi: -75"
D NimBLEAdvertisedDevice: "- setName(): name: iSensor "
D NimBLEAdvertisedDevice: "- manufacturer data: 00db974642027e7a"
I NimBLEScan: "UPDATING PREVIOUSLY FOUND DEVICE: a4:c1:38:5d:ef:16"
D NimBLEAdvertisedDevice: "- setRSSI(): rssi: -59"
I NimBLEScan: "UPDATING PREVIOUSLY FOUND DEVICE: 70:56:81:df:dd:15"
D NimBLEAdvertisedDevice: "- setRSSI(): rssi: -83"
D NimBLEAdvertisedDevice: "- manufacturer data: 4c0009060202c0a8b2dc"
I NimBLEScan: "UPDATING PREVIOUSLY FOUND DEVICE: 9c:20:7b:de:4c:ad"
D NimBLEAdvertisedDevice: "- setRSSI(): rssi: -96"
D NimBLEAdvertisedDevice: "- manufacturer data: 4c0009060201c0a8b20a"
I NimBLEScan: "UPDATING PREVIOUSLY FOUND DEVICE: 58:2d:34:39:22:58"
D NimBLEAdvertisedDevice: "- setRSSI(): rssi: -77"
I NimBLEScan: "NEW DEVICE FOUND: 69:e3:79:98:b6:9f"
D NimBLEAdvertisedDevice: "- setRSSI(): rssi: -96"
D NimBLEAdvertisedDevice: "- manufacturer data: 4c000c0e005ff8cdad20b24d1254087e38461005471c99c674"
I NimBLEScan: "UPDATING PREVIOUSLY FOUND DEVICE: ac:9a:22:cd:12:91"
D NimBLEAdvertisedDevice: "- setRSSI(): rssi: -76"
D NimBLEAdvertisedDevice: "- setName(): name: iSensor "
D NimBLEAdvertisedDevice: "- manufacturer data: 00db97464202807c"

Thank you for library

I don't know where send message to project, I wrote here.
if its not good, pls delete.

I connected BLE HID device with ESP32(M5StickC) by using this library.
I cannot connect with NimBLE included ESP-IDF.

I wrote an aticle(In Japanese)

NimBLEでESP32(M5StickC)にBLE HIDデバイスを接続する - Qiita
https://qiita.com/coppercele/items/4ce0e8858a92410c81e3

Thank you!

Question

@h2zero I am new to BLE, and I think this is more a question than an issue, but maybe you can help.

When I read a remote characteristic with the notify callback everything is okay, but if I try to read it directly, I do not get the right values, while using the same address, service UUID and characteristic UUID. Am I forgetting something? This is the snippet:

void readBLEClient() {
  BLEClient * pClient = BLEDevice::createClient();

  Serial.println("Connecting...");
  bool success = pClient->connect(BLEAddress("a4:c1:38:5d:ef:16"));
  if(!success) {
    BLEDevice::deleteClient(pClient);

    Serial.println("Failed to connect");
    return;
  }
  Serial.println("Connected");
  BLERemoteService * pRemoteService = pClient->getService(BLEUUID(0xebe0ccb0, 0x7a0a, 0x4b0c, 0x8a1a6ff2997da3a6));
  if(pRemoteService == nullptr) {
    Serial.print("Failed to find our service UUID: ");
    pClient->disconnect();
  } else {
    Serial.println(" - Found our service");  
    // Obtain a reference to the characteristic in the service of the remote BLE server.
    BLERemoteCharacteristic * pRemoteCharacteristic = pRemoteService->getCharacteristic(BLEUUID(0xebe0ccc1, 0x7a0a, 0x4b0c, 0x8a1a6ff2997da3a6));
    if(pRemoteCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
    } else {
      Serial.println(" - Found our characteristic");
      if(pRemoteCharacteristic->canRead()) {
        Serial.println("Can read");
        Serial.printf("string value is '%s'\n", pRemoteCharacteristic->readValue().c_str());
        Serial.printf("uint8_t value is %u\n", pRemoteCharacteristic->readUInt8());
        Serial.printf("uint16_t value is %u\n", pRemoteCharacteristic->readUInt16());
        const uint8_t * pData = pRemoteCharacteristic->readRawData();
        float temperature = (pData[0] | (pData[1] << 8)) * 0.01; //little endian 
        uint8_t humidity = pData[2];
        Serial.printf("Temperature = %.2f : humidity = %u\n", temperature, humidity);    
      }
    }
  }
  pClient->disconnect();
  BLEDevice::deleteClient(pClient);
}

The output is an empty string. If I test the length() and the contents of string returned by readValue(), it is 3 long all 0x00. In the notify callback pData is 5 long, containing 2 bytes temperature, 1 byte humidity and two (for me) unknown bytes.

Any suggestions?

Feature request on NimBLEUUID

Could you please add to NimBLEUUID.h:

    NimBLEUUID(uint32_t first, uint16_t second, uint16_t third, uint64_t fourth);

and to NimBLEUUID.cpp:

NimBLEUUID::NimBLEUUID(uint32_t first, uint16_t second, uint16_t third, uint64_t fourth) {
    m_uuid.u.type        = BLE_UUID_TYPE_128;
    memcpy(m_uuid.u128.value + 12, &first,  4);
    memcpy(m_uuid.u128.value + 10, &second, 2);
    memcpy(m_uuid.u128.value + 8,  &third,  2);
    memcpy(m_uuid.u128.value,      &fourth, 8);
    m_valueSet = true;
}

This does not save any library memory, but is does save sketch memory. In stead of

BLEUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6")

you can do

BLEUUID(0xebe0ccb0, 0x7a0a, 0x4b0c, 0x8a1a6ff2997da3a6)

thus trading 37 bytes of the string literal for 16 bytes uint literals, saving 21 bytes per UUID literal!

NimBLE implementation of Server-Client scheduling

Hi, I will like to first thank you for your amazing work on the NimBLE libraries for Arduino IDE.
I want to ask if this library supports Server-Client scheduling, such that I can run a NimBLEDevice::init one time and then switch between NimBLEScan and NimBLEAdvertising, or if the same end is met with a different implementation.

Cheers, KW

Typo in include

I just took a quick look into your lib and got stuck due to a case sensitivity error.
In file
NimBLE-Arduino/src/NimBLEDevice.h, line 20 has to be written as
#include "NimBLEScan.h"
instead of
#include "NimbleScan.h"
to work in case sensitive operating systems like Linux.

Thanks,
Josef

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.