func newCCCD(c *ble.Characteristic) *ble.Descriptor { d := ble.NewDescriptor(ble.ClientCharacteristicConfigUUID) d.HandleRead(ble.ReadHandlerFunc(func(req ble.Request, rsp ble.ResponseWriter) { cccs := req.Conn().(*conn).cccs ccc := cccs[c.Handle] binary.Write(rsp, binary.LittleEndian, ccc) })) d.HandleWrite(ble.WriteHandlerFunc(func(req ble.Request, rsp ble.ResponseWriter) { cn := req.Conn().(*conn) old := cn.cccs[c.Handle] ccc := binary.LittleEndian.Uint16(req.Data()) oldNotify := old&cccNotify != 0 oldIndicate := old&cccIndicate != 0 newNotify := ccc&cccNotify != 0 newIndicate := ccc&cccIndicate != 0 if newNotify && !oldNotify { if c.Property&ble.CharNotify == 0 { rsp.SetStatus(ble.ErrUnlikely) return } send := func(b []byte) (int, error) { return cn.svr.notify(c.ValueHandle, b) } cn.nn[c.Handle] = ble.NewNotifier(send) go c.NotifyHandler.ServeNotify(req, cn.nn[c.Handle]) } if !newNotify && oldNotify { cn.nn[c.Handle].Close() } if newIndicate && !oldIndicate { if c.Property&ble.CharIndicate == 0 { rsp.SetStatus(ble.ErrUnlikely) return } send := func(b []byte) (int, error) { return cn.svr.indicate(c.ValueHandle, b) } cn.in[c.Handle] = ble.NewNotifier(send) go c.IndicateHandler.ServeNotify(req, cn.in[c.Handle]) } if !newIndicate && oldIndicate { cn.in[c.Handle].Close() } cn.cccs[c.Handle] = ccc })) return d }
// server (peripheral) func (c *conn) subscribed(char *ble.Characteristic) { h := char.Handle if _, found := c.notifiers[h]; found { return } send := func(b []byte) (int, error) { c.dev.sendCmd(c.dev.pm, 15, xpc.Dict{ "kCBMsgArgUUIDs": [][]byte{}, "kCBMsgArgAttributeID": h, "kCBMsgArgData": b, }) return len(b), nil } n := ble.NewNotifier(send) c.notifiers[h] = n req := ble.NewRequest(c, nil, 0) // convey *conn to user handler. go char.NotifyHandler.ServeNotify(req, n) }