@@ -14,6 +14,10 @@ import (
1414 "github.com/muka/go-bluetooth/bluez/profile/gatt"
1515)
1616
17+ var (
18+ errDupNotif = errors .New ("unclosed notifications" )
19+ )
20+
1721// UUIDWrapper is a type alias for UUID so we ensure no conflicts with
1822// struct method of the same name.
1923type uuidWrapper = UUID
@@ -133,6 +137,7 @@ type DeviceCharacteristic struct {
133137 uuidWrapper
134138
135139 characteristic * gatt.GattCharacteristic1
140+ property chan * bluez.PropertyChanged // channel where notifications are reported
136141}
137142
138143// UUID returns the UUID for this DeviceCharacteristic.
@@ -238,19 +243,60 @@ func (c DeviceCharacteristic) WriteWithoutResponse(p []byte) (n int, err error)
238243// Configuration Descriptor (CCCD). This means that most peripherals will send a
239244// notification with a new value every time the value of the characteristic
240245// changes.
241- func (c DeviceCharacteristic ) EnableNotifications (callback func (buf []byte )) error {
242- ch , err := c .characteristic .WatchProperties ()
243- if err != nil {
244- return err
245- }
246- go func () {
247- for update := range ch {
248- if update .Interface == "org.bluez.GattCharacteristic1" && update .Name == "Value" {
249- callback (update .Value .([]byte ))
246+ //
247+ // Users may call EnableNotifications with a nil callback to disable notifications.
248+ func (c * DeviceCharacteristic ) EnableNotifications (callback func (buf []byte )) error {
249+ switch callback {
250+ default :
251+ if c .property != nil {
252+ return errDupNotif
253+ }
254+
255+ ch , err := c .characteristic .WatchProperties ()
256+ if err != nil {
257+ return err
258+ }
259+
260+ err = c .characteristic .StartNotify ()
261+ if err != nil {
262+ _ = c .characteristic .UnwatchProperties (ch )
263+ return err
264+ }
265+ c .property = ch
266+
267+ go func () {
268+ for update := range ch {
269+ if update == nil {
270+ continue
271+ }
272+ if update .Interface == "org.bluez.GattCharacteristic1" && update .Name == "Value" {
273+ callback (update .Value .([]byte ))
274+ }
250275 }
276+ }()
277+
278+ return nil
279+
280+ case nil :
281+ if c .property == nil {
282+ return nil
283+ }
284+
285+ e1 := c .characteristic .StopNotify ()
286+ e2 := c .characteristic .UnwatchProperties (c .property )
287+ c .property = nil
288+
289+ // FIXME(sbinet): use errors.Join(e1, e2)
290+ if e1 != nil {
291+ return e1
292+ }
293+
294+ if e2 != nil {
295+ return e2
251296 }
252- }()
253- return c .characteristic .StartNotify ()
297+
298+ return nil
299+ }
254300}
255301
256302// GetMTU returns the MTU for the characteristic.
0 commit comments