fermentord/vendor/github.com/JuulLabs-OSS/ble/darwin/pmgprdlg.go

137 lines
3.3 KiB
Go
Raw Normal View History

// pmgrdlg.go: Implements the PeripheralManagerDelegate interface.
// CoreBluetooth communicates events asynchronously via callbacks. This file
// implements a synchronous interface by translating these callbacks into
// channel operations.
package darwin
import (
"bytes"
"fmt"
"log"
"github.com/JuulLabs-OSS/ble"
"github.com/JuulLabs-OSS/cbgo"
)
func (d *Device) PeripheralManagerDidUpdateState(pmgr cbgo.PeripheralManager) {
d.evl.stateChanged.RxSignal(struct{}{})
}
func (d *Device) DidAddService(pmgr cbgo.PeripheralManager, svc cbgo.Service, err error) {
d.evl.svcAdded.RxSignal(err)
}
func (d *Device) DidStartAdvertising(pmgr cbgo.PeripheralManager, err error) {
d.evl.advStarted.RxSignal(err)
}
func (d *Device) DidReceiveReadRequest(pmgr cbgo.PeripheralManager, cbreq cbgo.ATTRequest) {
chr, _ := d.pc.findChr(cbreq.Characteristic())
if chr == nil || chr.ReadHandler == nil {
return
}
c := d.findConn(cbreq.Central().Identifier())
if c == nil {
var err error
c, err = newPeripheralConn(d, cbreq.Central())
if err != nil {
log.Printf("failed to process read response: %v", err)
return
}
}
req := ble.NewRequest(c, nil, cbreq.Offset())
buf := bytes.NewBuffer(make([]byte, 0, c.txMTU-1))
rsp := ble.NewResponseWriter(buf)
chr.ReadHandler.ServeRead(req, rsp)
cbreq.SetValue(buf.Bytes())
pmgr.RespondToRequest(cbreq, cbgo.ATTError(rsp.Status()))
}
func (d *Device) DidReceiveWriteRequests(pmgr cbgo.PeripheralManager, cbreqs []cbgo.ATTRequest) {
serveOne := func(cbreq cbgo.ATTRequest) {
chr, _ := d.pc.findChr(cbreq.Characteristic())
if chr == nil || chr.WriteHandler == nil {
return
}
c := d.findConn(cbreq.Central().Identifier())
if c == nil {
var err error
c, err = newPeripheralConn(d, cbreq.Central())
if err != nil {
log.Printf("failed to process write response: %v", err)
return
}
}
req := ble.NewRequest(c, cbreq.Value(), cbreq.Offset())
rsp := ble.NewResponseWriter(nil)
chr.WriteHandler.ServeWrite(req, rsp)
pmgr.RespondToRequest(cbreq, cbgo.ATTError(rsp.Status()))
}
for _, cbreq := range cbreqs {
serveOne(cbreq)
}
}
func (d *Device) CentralDidSubscribe(pmgr cbgo.PeripheralManager, cent cbgo.Central, cbchr cbgo.Characteristic) {
c := d.findConn(cent.Identifier())
if c == nil {
var err error
c, err = newPeripheralConn(d, cent)
if err != nil {
log.Printf("failed to process subscribe request: %v", err)
return
}
}
if c.notifiers[cbchr] != nil {
return
}
chr, _ := d.pc.findChr(cbchr)
if chr == nil {
return
}
send := func(b []byte) (int, error) {
sent := d.pm.UpdateValue(b, cbchr, nil)
if !sent {
return len(b), fmt.Errorf("failed to send notification: tx queue full")
}
return len(b), nil
}
n := ble.NewNotifier(send)
c.notifiers[cbchr] = n
req := ble.NewRequest(c, nil, 0) // convey *conn to user handler.
go chr.NotifyHandler.ServeNotify(req, n)
}
func (d *Device) CentralDidUnsubscribe(pmgr cbgo.PeripheralManager, cent cbgo.Central, chr cbgo.Characteristic) {
c := d.findConn(cent.Identifier())
if c == nil {
var err error
c, err = newPeripheralConn(d, cent)
if err != nil {
log.Printf("failed to process unsubscribe request: %v", err)
return
}
}
n := c.notifiers[chr]
if n != nil {
if err := n.Close(); err != nil {
log.Printf("failed to close notifier: %v", err)
}
delete(c.notifiers, chr)
}
}