diff --git a/gap_darwin.go b/gap_darwin.go index 51ba7ed..3153cb5 100644 --- a/gap_darwin.go +++ b/gap_darwin.go @@ -256,3 +256,20 @@ func (pd *peripheralDelegate) DidWriteValueForCharacteristic(_ cbgo.Peripheral, } } } + +// DidUpdateNotificationState is called when the notification state for a characteristic +// has been updated. It reports whether enabling/disabling notifications succeeded. +func (pd *peripheralDelegate) DidUpdateNotificationState(prph cbgo.Peripheral, chr cbgo.Characteristic, err error) { + uuid, _ := ParseUUID(chr.UUID().String()) + svcuuid, _ := ParseUUID(chr.Service().UUID().String()) + + if svc, ok := pd.d.services[svcuuid]; ok { + for _, char := range svc.characteristics { + if char.characteristic == chr && uuid == char.UUID() { + if char.notifyChan != nil { + char.notifyChan <- err + } + } + } + } +} diff --git a/gattc_darwin.go b/gattc_darwin.go index 0362117..664e92e 100644 --- a/gattc_darwin.go +++ b/gattc_darwin.go @@ -8,7 +8,10 @@ import ( "github.com/tinygo-org/cbgo" ) -var errCannotSendWriteWithoutResponse = errors.New("bluetooth: cannot send write without response (buffer full)") +var ( + errCannotSendWriteWithoutResponse = errors.New("bluetooth: cannot send write without response (buffer full)") + errTimeoutEnableNotifications = errors.New("timeout on EnableNotifications") +) var ( _ GATTCService = (*DeviceService)(nil) @@ -208,6 +211,7 @@ type deviceCharacteristic struct { callback func(buf []byte) readChan chan error writeChan chan error + notifyChan chan error } // UUID returns the UUID for this DeviceCharacteristic. @@ -256,15 +260,35 @@ func (c DeviceCharacteristic) WriteWithoutResponse(p []byte) (int, error) { // changes. // Users may call EnableNotifications with a nil callback to disable notifications. func (c DeviceCharacteristic) EnableNotifications(callback func(buf []byte)) error { - // If callback is nil, disable notifications + c.notifyChan = make(chan error) + if callback == nil { c.service.device.prph.SetNotify(false, c.characteristic) - c.callback = nil // Clear notification callback } else { - // Enable notifications and set notification callback c.callback = callback c.service.device.prph.SetNotify(true, c.characteristic) } + + // Wait for CoreBluetooth to confirm the notification state change. + var err error + select { + case err = <-c.notifyChan: + case <-time.After(10 * time.Second): + err = errTimeoutEnableNotifications + } + + c.notifyChan = nil + + if err != nil { + c.callback = nil + return err + } + + // Clear callback after confirmed disable. + if callback == nil { + c.callback = nil + } + return nil }