arduino-libraries / ArduinoBLE

ArduinoBLE library for Arduino
GNU Lesser General Public License v2.1
291 stars 198 forks source link

`BLE.central().connected()` is `true` when a disconnect has happened #334

Open cab938 opened 7 months ago

cab938 commented 7 months ago

This bug seems to be similar to the closed issue #33 and is referenced in this forum thread: https://forum.arduino.cc/t/nano-33-ble-arduinoble-library-handling-loss-of-connection/620170

I'm using Arduino IDE 2.2.1 with ArduinoBLE 1.3.6 and the Seeed XIAO BLUE - nRF52840.

I've got example code below, the first is the arduino sketch I'm using which just sets up the BLE with a single characteristic and then waits for a connection. The central is a python script using bleak. It should just listen for updates to the characteristic then get the notify. This works fine, but when I kill the python script the arduino device still thinks it is connected and thus needs to be reset.

Am I missing something conceptual? I expected that central.connected() would be false and thus break out of the data acquisition loop.

// For IMU support
#include "LSM6DS3.h"
#include "Wire.h"

// For BLE support for the nRF52840
#include <ArduinoBLE.h>

// Unique identifier for this service
BLEService imuService("544e708a-8e16-11ee-b9d1-0242ac120002");

// Data are 6 signed int16's (2 bytes each, int16_t) which will be packed into
// a character array for xyz accelerometer data + xyz gyro data
BLECharacteristic accelerometerCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, 6*2 , true);

//Create a instance of class LSM6DS3
LSM6DS3 myIMU(I2C_MODE, 0x6A);    //I2C device address 0x6A

void setup() {
  // Connect to terminal if available
  Serial.begin(9600);

  // Block waiting for serial output setup 
  while (!Serial);

  // Set up bluetooth service
  Serial.println("Setting up bluetooth");
  if (!BLE.begin()) {
    Serial.println("Bluetooth failed to start");
    while (1);
  }

  // Set bluetooth advertising details, configure service, and being advertising
  BLE.setLocalName("IMU");
  BLE.setAdvertisedService(imuService);
  imuService.addCharacteristic(accelerometerCharacteristic);
  BLE.addService(imuService);
  BLE.advertise();

  // Print out MAC address
  Serial.println("Our MAC address is:");
  Serial.println(BLE.address());

  // Set up IMU service
  Serial.println("Setting up IMU");
  if (myIMU.begin() != 0) {
      Serial.println("IMU failed to start");
      while (1);
  }
}

void loop() {
  // Check for bluetooth connections
  BLEDevice central = BLE.central();
  if (central && central.connected()) {
    Serial.println("Connected with:");
    Serial.println(central.address());
    while( central.connected()){
      // Acquire data from IMU sensor as float array
      int16_t data[6] = {myIMU.readRawAccelX(), myIMU.readRawAccelY(), myIMU.readRawAccelZ(), myIMU.readRawGyroX(), myIMU.readRawGyroY(), myIMU.readRawGyroZ() };
      // Write data to the characteristic
      accelerometerCharacteristic.writeValue(reinterpret_cast<char*>(data));
      Serial.println((data[2]));
      // delay(100);
    }
    Serial.println("Disconnected from bluetooth client");
  }
  else{
    Serial.println("No bluetooth connection, skipping data acquisition.");
  }
  delay(1000);
}
import asyncio
import struct
from bleak import BleakClient, BleakScanner, BleakGATTCharacteristic

address = "a5:65:df:64:f8:fb"

def process_imu_data(sender: BleakGATTCharacteristic, data: bytearray) -> None:
    x,y,z,xg,y,zg = struct.unpack('hhhhhh', data)
    print(z)

async def main(address):
    imu = await BleakScanner.find_device_by_name("IMU",timeout=30)
    if (imu != None):
        print(f"Found device {imu}")

    async with BleakClient(imu) as client:
        # wait until we are connected
        if (not client.is_connected):
            await client.connect()

        # register for notifications from our characteristic
        await client.start_notify("19B10001-E8F2-537E-4F6C-D104768A1214", process_imu_data)
        while( client.is_connected):
            await asyncio.sleep(0.01)

asyncio.run(main(address))
cab938 commented 7 months ago

I'm happy to add debug info or the like fwiw, just need a couple of pointers to docs/repos where this might have been done to better understand how to debug into libraries in arduino ide, as I'm not an embedded systems person...