deviceplug / btleplug

Rust Cross-Platform Host-Side Bluetooth LE Access Library
Other
826 stars 151 forks source link

Got descriptors for a characteristic we don't know about #397

Open vyeevani opened 3 months ago

vyeevani commented 3 months ago

Describe the bug "Got descriptors for a characteristic we don't know" about while connecting to an iRobot Create 3.

Expected behavior able to connect to peripheral

Actual behavior the connect fails with error: "Got descriptors for a characteristic we don't know"

Additional context error is coming from: pub fn set_characteristic_descriptors( &mut self, service_uuid: Uuid, characteristic_uuid: Uuid, descriptors: HashMap<Uuid, StrongPtr>, ) { in corebluetooth internal

vyeevani commented 3 months ago

Seeing the following sequence of events: delegate_peripheral_diddiscovercharacteristicsforservice_error CBPeripheral(iRobotCreate3, 6F18E7F1-76E0-F57F-4A46-E588ED87545A) CBService(180A) delegate_peripheral_diddiscoverincludedservicesforservice_error CBPeripheral(iRobotCreate3, 6F18E7F1-76E0-F57F-4A46-E588ED87545A) CBService(180A) delegate_peripheral_diddiscovercharacteristicsforservice_error CBPeripheral(iRobotCreate3, 6F18E7F1-76E0-F57F-4A46-E588ED87545A) CBService(180A) delegate_peripheral_diddiscoverincludedservicesforservice_error CBPeripheral(iRobotCreate3, 6F18E7F1-76E0-F57F-4A46-E588ED87545A) CBService(180A) delegate_peripheral_diddiscovercharacteristicsforservice_error CBPeripheral(iRobotCreate3, 6F18E7F1-76E0-F57F-4A46-E588ED87545A) CBService(48C5D828-AC2A-442D-97A3-0C9822B04979) delegate_peripheral_diddiscoverincludedservicesforservice_error CBPeripheral(iRobotCreate3, 6F18E7F1-76E0-F57F-4A46-E588ED87545A) CBService(48C5D828-AC2A-442D-97A3-0C9822B04979) delegate_peripheral_diddiscovercharacteristicsforservice_error CBPeripheral(iRobotCreate3, 6F18E7F1-76E0-F57F-4A46-E588ED87545A) CBService(6E400001-B5A3-F393-E0A9-E50E24DCCA9E) delegate_peripheral_diddiscoverincludedservicesforservice_error CBPeripheral(iRobotCreate3, 6F18E7F1-76E0-F57F-4A46-E588ED87545A) CBService(6E400001-B5A3-F393-E0A9-E50E24DCCA9E) delegate_peripheral_diddiscoverdescriptorsforcharacteristic_error CBPeripheral(iRobotCreate3, 6F18E7F1-76E0-F57F-4A46-E588ED87545A) CBCharacteristic(2A50) delegate_peripheral_diddiscoverdescriptorsforcharacteristic_error CBPeripheral(iRobotCreate3, 6F18E7F1-76E0-F57F-4A46-E588ED87545A) CBCharacteristic(8BB6) Found descriptors for peripheral 6f18e7f1-76e0-f57f-4a46-e588ed87545a service 0000180a-0000-1000-8000-00805f9b34fb characteristic 00002a50-0000-1000-8000-00805f9b34fb: delegate_peripheral_diddiscoverdescriptorsforcharacteristic_error CBPeripheral(iRobotCreate3, 6F18E7F1-76E0-F57F-4A46-E588ED87545A) CBCharacteristic(2A26) Failed to get characteristic with UUID: 00002a50-0000-1000-8000-00805f9b34fb for service UUID: 0000180a-0000-1000-8000-00805f9b34fb

Still trying to work out what the uuid conversions are here.

I should also mention I'm on the latest macOS 15.1 developer beta. Not sure if that has some bluetooth bugs or mb the uuid conversion scheme has changed in the latest os?

vyeevani commented 3 months ago

It seems that: set_characteristics will overwrite all the prior characteristics of the service which may not be the right behavior here. If not overwriting all prior characteristics is the desired behavior, then there is a race condition between the characteristic storage and descriptor storage.

vyeevani commented 3 months ago

I ended up doing this for both the set_characteristics and set_characteristic_descriptors because it seemed like both had the same style of overwrite behavior.

pub fn set_characteristics(
        &mut self,
        service_uuid: Uuid,
        characteristics: HashMap<Uuid, StrongPtr>,
    ) {
        let service = self
            .services
            .get_mut(&service_uuid)
            .expect("Got characteristics for a service we don't know about");

        for (characteristic_uuid, characteristic) in characteristics {
            service.characteristics.insert(characteristic_uuid, CBCharacteristic::new(characteristic));
        }

        if service.characteristics.is_empty() {
            service.discovered = true;
            self.check_discovered();
        }
    }

    pub fn set_characteristic_descriptors(
        &mut self,
        service_uuid: Uuid,
        characteristic_uuid: Uuid,
        new_descriptors: HashMap<Uuid, StrongPtr>,
    ) {
        let service = self
            .services
            .get_mut(&service_uuid)
            .expect("Got descriptors for a service we don't know about");
        let characteristic = service
            .characteristics
            .get_mut(&characteristic_uuid)
            .expect("Got descriptors for a characteristic we don't know about");

        for (descriptor_uuid, descriptor) in new_descriptors {
            characteristic
                .descriptors
                .entry(descriptor_uuid)
                .or_insert_with(|| CBDescriptor::new(descriptor));
        }
        characteristic.discovered = true;

        if !service
            .characteristics
            .values()
            .any(|characteristic| !characteristic.discovered)
        {
            service.discovered = true;
            self.check_discovered()
        }
    }