blob: 597f186ec50ab8b4e1f1f659b0834af4969f58fb [file] [log] [blame]
package darwin
import (
"context"
"log"
"sync"
"github.com/go-ble/ble"
"github.com/raff/goble/xpc"
)
func newConn(d *Device, a ble.Addr, rxMTU int) *conn {
return &conn{
dev: d,
rxMTU: rxMTU,
txMTU: 23,
addr: a,
done: make(chan struct{}),
notifiers: make(map[uint16]ble.Notifier),
subs: make(map[uint16]*sub),
rspc: make(chan msg),
}
}
type conn struct {
sync.RWMutex
dev *Device
ctx context.Context
rxMTU int
txMTU int
addr ble.Addr
done chan struct{}
rspc chan msg
connInterval int
connLatency int
supervisionTimeout int
notifiers map[uint16]ble.Notifier // central connection only
subs map[uint16]*sub
isConnected bool
}
func (c *conn) Context() context.Context {
return c.ctx
}
func (c *conn) SetContext(ctx context.Context) {
c.ctx = ctx
}
func (c *conn) LocalAddr() ble.Addr {
// return c.dev.Address()
return c.addr // FIXME
}
func (c *conn) RemoteAddr() ble.Addr {
return c.addr
}
func (c *conn) RxMTU() int {
return c.rxMTU
}
func (c *conn) SetRxMTU(mtu int) {
c.rxMTU = mtu
}
func (c *conn) TxMTU() int {
return c.txMTU
}
func (c *conn) SetTxMTU(mtu int) {
c.Lock()
c.txMTU = mtu
c.Unlock()
}
func (c *conn) Read(b []byte) (int, error) {
return 0, nil
}
func (c *conn) Write(b []byte) (int, error) {
return 0, nil
}
func (c *conn) Close() error {
return nil
}
// Disconnected returns a receiving channel, which is closed when the connection disconnects.
func (c *conn) Disconnected() <-chan struct{} {
return c.done
}
// 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) {
err := c.dev.sendCmd(c.dev.pm, cmdSubscribed, xpc.Dict{
"kCBMsgArgUUIDs": [][]byte{},
"kCBMsgArgAttributeID": h,
"kCBMsgArgData": b,
})
return len(b), err
}
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)
}
// server (peripheral)
func (c *conn) unsubscribed(char *ble.Characteristic) {
if n, found := c.notifiers[char.Handle]; found {
if err := n.Close(); err != nil {
log.Printf("failed to clone notifier: %v", err)
}
delete(c.notifiers, char.Handle)
}
}
func (c *conn) sendReq(id int, args xpc.Dict) (msg, error) {
err := c.dev.sendCmd(c.dev.cm, id, args)
if err != nil {
return msg{}, err
}
m := <-c.rspc
return msg(m.args()), nil
}
func (c *conn) sendCmd(id int, args xpc.Dict) error {
return c.dev.sendCmd(c.dev.pm, id, args)
}