From bed7e8579136b11ad7373bd9a279ba58f61c1fe9 Mon Sep 17 00:00:00 2001 From: Eric Stutzenberger Date: Thu, 7 Jul 2022 13:45:19 -0700 Subject: [PATCH 01/12] some additional hci debug --- linux/hci/hci.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux/hci/hci.go b/linux/hci/hci.go index 6412e4b..a6dd345 100644 --- a/linux/hci/hci.go +++ b/linux/hci/hci.go @@ -400,6 +400,7 @@ func (h *HCI) send(c Command) ([]byte, error) { h.sent[oc] = p //use oc here due to swap to 0xff for vendor events h.muSent.Unlock() + h.Debugf("tx op: %v - %v", c.OpCode(), hex.EncodeToString(b)) if !h.isOpen() { return nil, fmt.Errorf("hci closed") } else if n, err := h.skt.Write(b[:4+c.Len()]); err != nil { @@ -522,6 +523,7 @@ func (h *HCI) close(err error) error { func (h *HCI) handlePkt(b []byte) error { // Strip the 1-byte HCI header and pass down the rest of the packet. + h.Debugf("hci rx: %v", hex.EncodeToString(b)) t, b := b[0], b[1:] switch t { case pktTypeACLData: From dad44c7ce141e25d808288024855ebf65f87bc8a Mon Sep 17 00:00:00 2001 From: Eric Stutzenberger Date: Thu, 7 Jul 2022 15:32:43 -0700 Subject: [PATCH 02/12] only debug log rx acl packets --- linux/hci/hci.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/hci/hci.go b/linux/hci/hci.go index a6dd345..b109d2f 100644 --- a/linux/hci/hci.go +++ b/linux/hci/hci.go @@ -523,10 +523,10 @@ func (h *HCI) close(err error) error { func (h *HCI) handlePkt(b []byte) error { // Strip the 1-byte HCI header and pass down the rest of the packet. - h.Debugf("hci rx: %v", hex.EncodeToString(b)) t, b := b[0], b[1:] switch t { case pktTypeACLData: + h.Debugf("hci rx acl: %v", hex.EncodeToString(b)) return h.handleACL(b) case pktTypeEvent: return h.handleEvt(b) From 2604cd97ddface9cc35292aa1fd10a1e9e66ddb5 Mon Sep 17 00:00:00 2001 From: Eric Stutzenberger Date: Fri, 8 Jul 2022 10:17:05 -0700 Subject: [PATCH 03/12] additional logging and logging cleanup --- examples/basic/advertiser/main.go | 11 ++++--- linux/att/client.go | 48 ++++++++++++++++--------------- linux/gatt/client.go | 2 +- linux/hci/conn.go | 4 ++- linux/hci/hci.go | 2 +- 5 files changed, 37 insertions(+), 30 deletions(-) diff --git a/examples/basic/advertiser/main.go b/examples/basic/advertiser/main.go index ed2f63b..d4f63dd 100644 --- a/examples/basic/advertiser/main.go +++ b/examples/basic/advertiser/main.go @@ -4,23 +4,26 @@ import ( "context" "flag" "fmt" + "github.com/rigado/ble/linux" "log" "time" - "github.com/rigado/ble" - "github.com/rigado/ble/examples/lib/dev" "github.com/pkg/errors" + "github.com/rigado/ble" ) var ( device = flag.String("device", "default", "implementation of ble") du = flag.Duration("du", 5*time.Second, "advertising duration, 0 for indefinitely") + name = flag.String("name", "Cascade", "name of the peripheral device") ) func main() { flag.Parse() - d, err := dev.NewDevice("default") + opt := ble.OptTransportHCISocket(0) + + d, err := linux.NewDeviceWithNameAndHandler("", nil, opt) if err != nil { log.Fatalf("can't new device : %s", err) } @@ -29,7 +32,7 @@ func main() { // Advertise for specified durantion, or until interrupted by user. fmt.Printf("Advertising for %s...\n", *du) ctx := ble.WithSigHandler(context.WithTimeout(context.Background(), *du)) - chkErr(ble.AdvertiseNameAndServices(ctx, "Gopher")) + chkErr(ble.AdvertiseNameAndServices(ctx, *name, ble.BatteryUUID, ble.DeviceInfoUUID)) } func chkErr(err error) { diff --git a/linux/att/client.go b/linux/att/client.go index b6e9213..3d03c04 100644 --- a/linux/att/client.go +++ b/linux/att/client.go @@ -2,7 +2,9 @@ package att import ( "encoding/binary" + "encoding/hex" "errors" + "fmt" "io" "time" @@ -60,7 +62,7 @@ func (c *Client) WithServer(db *DB) *Client { var err error c.server, err = NewServer(db, c.l2c, c.Logger) if err != nil { - c.Errorf("client: failed to create server") + c.Errorf("failed to create server") } return c @@ -511,7 +513,7 @@ func (c *Client) sendCmd(b []byte) error { } func (c *Client) sendReq(b []byte) (rsp []byte, err error) { - c.Debugf("client: req % X", b) + c.Debugf("req: %v", hex.EncodeToString(b)) if _, err := c.l2c.Write(b); err != nil { return nil, fmt.Errorf("send ATT request failed: %w", err) } @@ -526,7 +528,7 @@ func (c *Client) sendReq(b []byte) (rsp []byte, err error) { // returns an ErrReqNotSupp response, and continue to wait // the response to our request. errRsp := newErrorResponse(rsp[0], 0x0000, ble.ErrReqNotSupp) - c.Debugf("client: rsp % X", b) + c.Debugf("rsp: % X", b) _, err := c.l2c.Write(errRsp) if err != nil { return nil, fmt.Errorf("unexpected ATT response received: %w", err) @@ -559,14 +561,14 @@ func (c *Client) asyncReqLoop() { // keep trying? select { case <-c.done: - c.Debug("[BLE ATT]: exited client async loop: done") + c.Debug("exited async loop: done") return case <-c.connClosed: - c.Debug("[BLE ATT]: exited client async loop: conn closed") + c.Debug("exited async loop: conn closed") return default: if c.l2c == nil { - c.Debug("[BLE ATT] exited client async loop: l2c nil") + c.Debug("exited async loop: l2c nil") return } //ok @@ -579,7 +581,7 @@ func (c *Client) asyncReqLoop() { } err := c.sendResp(rsp) if err != nil { - c.Errorf("client: failed to send async att response for: %X", in[0]) + c.Errorf("failed to send async att response for: %X", in[0]) } } } @@ -613,14 +615,14 @@ func (c *Client) Loop() { // keep trying? select { case <-c.done: - c.Debug("exited client loop: done") + c.Debug("exited async loop: done") return case <-c.connClosed: - c.Debug("exited client async loop: conn closed") + c.Debug("exited async loop: conn closed") return default: if c.l2c == nil { - c.Debug("exited client loop: l2c nil") + c.Debug("exited async loop: l2c nil") return } //ok @@ -630,14 +632,14 @@ func (c *Client) Loop() { // keep trying? select { case <-c.done: - c.Debug("exited client loop: done") + c.Debug("exited async loop: done") return case <-c.connClosed: - c.Debug("exited client async loop: conn closed") + c.Debug("exited async loop: conn closed") return default: if c.l2c == nil { - c.Debug("exited client loop: l2c nil") + c.Debug("exited async loop: l2c nil") return } else if err != nil { if errors.Is(err, io.ErrClosedPipe) { @@ -657,28 +659,28 @@ func (c *Client) Loop() { b := make([]byte, n) copy(b, c.rxBuf) - c.Debugf("client: data rx % X", b) + c.Debugf("rx: %v", hex.EncodeToString(b)) //all incoming requests are even numbered //which means the last bit should be 0 if b[0]&0x01 == 0x00 { select { case <-c.done: - c.Info("exited client loop: closed after async req rx") + c.Info("exited async loop: closed after async req rx") return case <-c.connClosed: - c.Debug("exited client async loop: conn closed") + c.Debug("exited async loop: conn closed") return case c.inc <- b: continue default: - c.Errorf("client: failed to enqueue request for", fmt.Sprintf("%x", b[0])) + c.Errorf("failed to enqueue request for %x", b[0]) continue } } if (b[0] != HandleValueNotificationCode) && (b[0] != HandleValueIndicationCode) { - c.Debugf("client: rsp % X", c.rxBuf[:n]) + c.Debugf("a rx: %v", hex.EncodeToString(c.rxBuf[:n])) select { case <-c.done: c.Info("exited client loop: closed after rsp rx") @@ -692,24 +694,24 @@ func (c *Client) Loop() { } // Deliver the full request to upper layer. - c.Debugf("client: notif % X", b) + c.Debugf("notif: %v", hex.EncodeToString(b)) select { case <-c.done: - c.Info("exited client loop: closed after rx") + c.Info("exited async loop: closed after rx") return case <-c.connClosed: - c.Debug("exited client async loop: conn closed") + c.Debug("exited async loop: conn closed") return case ch <- asyncWork{handle: c.handler.HandleNotification, data: b}: // ok default: // If this really happens, especially on a slow machine, enlarge the channel buffer. - c.Error("client: req - can't enqueue incoming notification.") + c.Error("can't enqueue incoming notification.") } // Always write aknowledgement for an indication, even it was an invalid request. if b[0] == HandleValueIndicationCode { - c.Debugf("client: req % X", b) + c.Debugf("write confirmation for indication") _, _ = c.l2c.Write(confirmation) } } diff --git a/linux/gatt/client.go b/linux/gatt/client.go index bac0c76..9511129 100644 --- a/linux/gatt/client.go +++ b/linux/gatt/client.go @@ -42,7 +42,7 @@ type sub struct { // NewClient returns a GATT Client. func NewClient(conn ble.Conn, cache ble.GattCache, done chan bool, l ble.Logger) (*Client, error) { - cl := l.ChildLogger(map[string]interface{}{"client": hex.EncodeToString(conn.RemoteAddr().Bytes())}) + cl := l.ChildLogger(map[string]interface{}{"gatt": hex.EncodeToString(conn.RemoteAddr().Bytes())}) p := &Client{ subs: make(map[uint16]*sub), conn: conn, diff --git a/linux/hci/conn.go b/linux/hci/conn.go index 541e9c1..ec08e89 100644 --- a/linux/hci/conn.go +++ b/linux/hci/conn.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/binary" + "encoding/hex" "fmt" "io" "net" @@ -352,6 +353,7 @@ func (c *Conn) writePDU(pdu []byte) (int, error) { default: } + c.Debugf("tx: %v", hex.EncodeToString(pkt.Bytes())) if _, err := c.hci.skt.Write(pkt.Bytes()); err != nil { return sent, err } @@ -377,7 +379,7 @@ func (c *Conn) recombine() error { } p := pdu(pkt.data()) - c.Debugf("recombine: pdu in - % X", pkt.data()) + c.Debugf("recombine: pdu in - %v", hex.EncodeToString(pkt.data())) // Currently, check for LE-U only. For channels that we don't recognizes, // re-combine them anyway, and discard them later when we dispatch the PDU // according to CID. diff --git a/linux/hci/hci.go b/linux/hci/hci.go index b109d2f..9b40057 100644 --- a/linux/hci/hci.go +++ b/linux/hci/hci.go @@ -931,7 +931,7 @@ func (h *HCI) handleEncryptionKeyRefreshComplete(b []byte) error { func (h *HCI) handleNumberOfCompletedPackets(b []byte) error { e := evt.NumberOfCompletedPackets(b) - h.Debugf("numberOfCompletedPackets: % X", b) + h.Debugf("numberOfCompletedPackets: %v", hex.EncodeToString(b)) h.muConns.Lock() defer h.muConns.Unlock() for i := 0; i < int(e.NumberOfHandles()); i++ { From 131a50cd179c78e1de365ebe7bd97a01fbc71048 Mon Sep 17 00:00:00 2001 From: Eric Stutzenberger Date: Mon, 25 Jul 2022 11:20:02 -0700 Subject: [PATCH 04/12] add command for setting default tx data length for connections; send new command to radio during init --- linux/hci/cmd/cmd_gen.go | 31 +++++++++++++++++++++++++++++++ linux/hci/hci.go | 3 +++ linux/tools/codegen/cmd.json | 23 +++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/linux/hci/cmd/cmd_gen.go b/linux/hci/cmd/cmd_gen.go index 8b10a15..d08d718 100644 --- a/linux/hci/cmd/cmd_gen.go +++ b/linux/hci/cmd/cmd_gen.go @@ -1560,3 +1560,34 @@ type LERemoteConnectionParameterRequestNegativeReplyRP struct { func (c *LERemoteConnectionParameterRequestNegativeReplyRP) Unmarshal(b []byte) error { return unmarshal(c, b) } + +// LEWriteSuggestedDefaultDataLength implements LE Write Suggested Default Data Length (0x08|0x0024) [Vol 2, Part E, 7.8.35] +type LEWriteSuggestedDefaultDataLength struct { + SuggestedMaxTxOctets uint16 + SuggestedMaxTxTime uint16 +} + +func (c *LEWriteSuggestedDefaultDataLength) String() string { + return "LE Write Suggested Default Data Length (0x08|0x0024)" +} + +// OpCode returns the opcode of the command. +func (c *LEWriteSuggestedDefaultDataLength) OpCode() int { return 0x08<<10 | 0x0024 } + +// Len returns the length of the command. +func (c *LEWriteSuggestedDefaultDataLength) Len() int { return 4 } + +// Marshal serializes the command parameters into binary form. +func (c *LEWriteSuggestedDefaultDataLength) Marshal(b []byte) error { + return marshal(c, b) +} + +// LEWriteSuggestedDefaultDataLengthRP returns the return parameter of LE Write Suggested Default Data Length +type LEWriteSuggestedDefaultDataLengthRP struct { + Status uint8 +} + +// Unmarshal de-serializes the binary data and stores the result in the receiver. +func (c *LEWriteSuggestedDefaultDataLengthRP) Unmarshal(b []byte) error { + return unmarshal(c, b) +} diff --git a/linux/hci/hci.go b/linux/hci/hci.go index 9b40057..eac8ec5 100644 --- a/linux/hci/hci.go +++ b/linux/hci/hci.go @@ -302,6 +302,9 @@ func (h *HCI) init() error { WriteLEHostSupportRP := cmd.WriteLEHostSupportRP{} h.Send(&cmd.WriteLEHostSupport{LESupportedHost: 1, SimultaneousLEHost: 0}, &WriteLEHostSupportRP) + WriteDefaultDataLengthRP := cmd.LEWriteSuggestedDefaultDataLengthRP{} + h.Send(&cmd.LEWriteSuggestedDefaultDataLength{SuggestedMaxTxOctets: 251, SuggestedMaxTxTime: 2120}, &WriteDefaultDataLengthRP) + return h.err } diff --git a/linux/tools/codegen/cmd.json b/linux/tools/codegen/cmd.json index 73e4cce..ed75b94 100644 --- a/linux/tools/codegen/cmd.json +++ b/linux/tools/codegen/cmd.json @@ -1241,6 +1241,29 @@ "Events": [ "Command Complete" ] + }, + { + "Name": "LE Write Suggested Default Data Length", + "Spec": "Vol 2, Part E, 7.8.35", + "OGF": "0x08", + "OCF": "0x0024", + "Len": 4, + "Param": [ + { + "SuggestedMaxTxOctets": "uint16" + }, + { + "SuggestedMaxTxTime": "uint16" + } + ], + "Return": [ + { + "Status": "uint8" + } + ], + "Events": [ + "Command Complete" + ] } ] } From 8e5ccc1e9da519890e284967779972eb6108d043 Mon Sep 17 00:00:00 2001 From: Eric Stutzenberger Date: Wed, 19 Oct 2022 15:03:59 -0700 Subject: [PATCH 05/12] ignore error for empty pdu since that is allowed by the spec --- linux/adv/packet.go | 10 ++++++++-- parser/parser.go | 10 ++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/linux/adv/packet.go b/linux/adv/packet.go index c05fde9..585e2dc 100644 --- a/linux/adv/packet.go +++ b/linux/adv/packet.go @@ -2,8 +2,9 @@ package adv import ( "encoding/binary" + "fmt" - "github.com/pkg/errors" + "errors" "github.com/rigado/ble" "github.com/rigado/ble/parser" ) @@ -68,7 +69,12 @@ func NewRawPacket(bytes ...[]byte) (*Packet, error) { //decode the bytes m, err := parser.Parse(b) - err = errors.Wrapf(err, "pdu decode") + if !errors.Is(err, parser.EmptyOrNilPdu) { + err = fmt.Errorf("pdu decode: %w", err) + } else { + err = nil + } + switch { case err == nil: // ok diff --git a/parser/parser.go b/parser/parser.go index 51f0594..4eb475e 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -3,10 +3,12 @@ package parser import ( "fmt" - "github.com/pkg/errors" + "errors" "github.com/rigado/ble" ) +var EmptyOrNilPdu = errors.New("nil/empty pdu") + // https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile var types = struct { flags byte @@ -207,7 +209,7 @@ func getArray(size int, bytes []byte) ([]ble.UUID, error) { func Parse(pdu []byte) (map[string]interface{}, error) { if len(pdu) == 0 { - return nil, fmt.Errorf("nil/empty pdu") + return nil, EmptyOrNilPdu } m := make(map[string]interface{}) @@ -225,7 +227,7 @@ func Parse(pdu []byte) (map[string]interface{}, error) { //do we have all the bytes for the payload? if (i + length) >= len(pdu) { - return m, fmt.Errorf("buffer overflow: want %v, have %v, idx %v", (i + length), len(pdu), i) + return m, fmt.Errorf("buffer overflow: want %v, have %v, idx %v", i+length, len(pdu), i) } start := i + 2 @@ -245,7 +247,7 @@ func Parse(pdu []byte) (map[string]interface{}, error) { //is this fatal? if err != nil { - return m, errors.Wrapf(err, "adv type %v, idx %v", typ, i) + return m, fmt.Errorf("adv type %v, idx %v: %w", typ, i, err) } v, ok := m[dec.key].([]ble.UUID) From 446310e56c6216e2cc1ba55c39b17969462b80c5 Mon Sep 17 00:00:00 2001 From: Eric Stutzenberger Date: Wed, 19 Oct 2022 17:19:13 -0700 Subject: [PATCH 06/12] clean up debug messages --- linux/att/client.go | 4 ++-- linux/hci/conn.go | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/linux/att/client.go b/linux/att/client.go index 3d03c04..942274a 100644 --- a/linux/att/client.go +++ b/linux/att/client.go @@ -528,7 +528,7 @@ func (c *Client) sendReq(b []byte) (rsp []byte, err error) { // returns an ErrReqNotSupp response, and continue to wait // the response to our request. errRsp := newErrorResponse(rsp[0], 0x0000, ble.ErrReqNotSupp) - c.Debugf("rsp: % X", b) + c.Debugf("rsp: %x", b) _, err := c.l2c.Write(errRsp) if err != nil { return nil, fmt.Errorf("unexpected ATT response received: %w", err) @@ -659,7 +659,7 @@ func (c *Client) Loop() { b := make([]byte, n) copy(b, c.rxBuf) - c.Debugf("rx: %v", hex.EncodeToString(b)) + c.Debugf("rx: %x", b) //all incoming requests are even numbered //which means the last bit should be 0 diff --git a/linux/hci/conn.go b/linux/hci/conn.go index ec08e89..c62c1dd 100644 --- a/linux/hci/conn.go +++ b/linux/hci/conn.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "encoding/binary" - "encoding/hex" "fmt" "io" "net" @@ -353,7 +352,7 @@ func (c *Conn) writePDU(pdu []byte) (int, error) { default: } - c.Debugf("tx: %v", hex.EncodeToString(pkt.Bytes())) + c.Debugf("tx: %x", pkt.Bytes()) if _, err := c.hci.skt.Write(pkt.Bytes()); err != nil { return sent, err } @@ -379,7 +378,7 @@ func (c *Conn) recombine() error { } p := pdu(pkt.data()) - c.Debugf("recombine: pdu in - %v", hex.EncodeToString(pkt.data())) + c.Debugf("recombine: pdu in - %x", pkt.data()) // Currently, check for LE-U only. For channels that we don't recognizes, // re-combine them anyway, and discard them later when we dispatch the PDU // according to CID. From e800551bc25ed6cbe48db90d4175db519a1b1563 Mon Sep 17 00:00:00 2001 From: Eric Stutzenberger Date: Wed, 19 Oct 2022 17:24:45 -0700 Subject: [PATCH 07/12] more clean up --- linux/att/client.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/linux/att/client.go b/linux/att/client.go index 942274a..f9e162c 100644 --- a/linux/att/client.go +++ b/linux/att/client.go @@ -2,7 +2,6 @@ package att import ( "encoding/binary" - "encoding/hex" "errors" "fmt" @@ -513,7 +512,7 @@ func (c *Client) sendCmd(b []byte) error { } func (c *Client) sendReq(b []byte) (rsp []byte, err error) { - c.Debugf("req: %v", hex.EncodeToString(b)) + c.Debugf("req: %x", b) if _, err := c.l2c.Write(b); err != nil { return nil, fmt.Errorf("send ATT request failed: %w", err) } @@ -680,7 +679,7 @@ func (c *Client) Loop() { } if (b[0] != HandleValueNotificationCode) && (b[0] != HandleValueIndicationCode) { - c.Debugf("a rx: %v", hex.EncodeToString(c.rxBuf[:n])) + c.Debugf("a rx: %x", c.rxBuf[:n]) select { case <-c.done: c.Info("exited client loop: closed after rsp rx") @@ -694,7 +693,7 @@ func (c *Client) Loop() { } // Deliver the full request to upper layer. - c.Debugf("notif: %v", hex.EncodeToString(b)) + c.Debugf("notif: %x", b) select { case <-c.done: c.Info("exited async loop: closed after rx") From dff90bc299e893a519beccec6791ef5a7df554ca Mon Sep 17 00:00:00 2001 From: Eric Stutzenberger Date: Thu, 20 Oct 2022 14:54:01 -0700 Subject: [PATCH 08/12] adjust error handling --- linux/adv/packet.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/linux/adv/packet.go b/linux/adv/packet.go index 585e2dc..49315eb 100644 --- a/linux/adv/packet.go +++ b/linux/adv/packet.go @@ -69,10 +69,12 @@ func NewRawPacket(bytes ...[]byte) (*Packet, error) { //decode the bytes m, err := parser.Parse(b) - if !errors.Is(err, parser.EmptyOrNilPdu) { - err = fmt.Errorf("pdu decode: %w", err) - } else { - err = nil + if err != nil { + if !errors.Is(err, parser.EmptyOrNilPdu) { + err = fmt.Errorf("pdu decode: %w", err) + } else { + err = nil + } } switch { From 866901f33a04a277d5eda1b50a3d21540f7caa1f Mon Sep 17 00:00:00 2001 From: Eric Stutzenberger Date: Thu, 20 Oct 2022 15:58:39 -0700 Subject: [PATCH 09/12] spiff up encryption changed handling --- linux/hci/conn.go | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/linux/hci/conn.go b/linux/hci/conn.go index c62c1dd..d857386 100644 --- a/linux/hci/conn.go +++ b/linux/hci/conn.go @@ -70,6 +70,7 @@ type Conn struct { encryptionEnabled bool smp SmpManager + encInfo ble.EncryptionChangedInfo encChanged chan ble.EncryptionChangedInfo ble.Logger } @@ -145,8 +146,23 @@ func (c *Conn) Pair(authData ble.AuthData, to time.Duration) error { func (c *Conn) StartEncryption(ch chan ble.EncryptionChangedInfo) error { if c.encryptionEnabled { + //we already have the encryption changed info, send it to the channel if possible + if ch != nil { + go func(conn *Conn, c chan ble.EncryptionChangedInfo) { + select { + case ch <- conn.encInfo: + //ok + default: + conn.Errorf("encryptionChanged: failed to send encryption update to channel: %v", conn.encInfo) + } + }(c, ch) + return nil + } + + //if a nil channel is passed in, then return the already enabled error return ble.ErrEncryptionAlreadyEnabled } + c.encChanged = ch err := c.smp.StartEncryption() if err != nil { @@ -436,13 +452,13 @@ func (c *Conn) handleEncryptionChanged(status uint8, enabled uint8) { c.encryptionEnabled = enabled == 0x01 - info := ble.EncryptionChangedInfo{Status: int(status), Err: err, Enabled: c.encryptionEnabled} + c.encInfo = ble.EncryptionChangedInfo{Status: int(status), Err: err, Enabled: c.encryptionEnabled} if c.encChanged != nil { select { - case c.encChanged <- info: + case c.encChanged <- c.encInfo: return default: - c.Errorf("encryptionChanged: failed to send encryption update to channel: %v", info) + c.Errorf("encryptionChanged: failed to send encryption update to channel: %v", c.encInfo) } } else { c.Infof("encryptionChanged: status %v", status) From c23bb1a0650fa6dc85e3747409f88cfc215c30a3 Mon Sep 17 00:00:00 2001 From: Eric Stutzenberger Date: Thu, 20 Oct 2022 16:26:22 -0700 Subject: [PATCH 10/12] allow for timeout on encryption changed info when pushing to channel from start encryption func --- linux/hci/conn.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/hci/conn.go b/linux/hci/conn.go index d857386..5d1f1a8 100644 --- a/linux/hci/conn.go +++ b/linux/hci/conn.go @@ -152,7 +152,7 @@ func (c *Conn) StartEncryption(ch chan ble.EncryptionChangedInfo) error { select { case ch <- conn.encInfo: //ok - default: + case <-time.After(1 * time.Second): conn.Errorf("encryptionChanged: failed to send encryption update to channel: %v", conn.encInfo) } }(c, ch) From e4ce688b76fe7e4cc62bdfb0528055d79ca21d54 Mon Sep 17 00:00:00 2001 From: Eric Stutzenberger Date: Fri, 21 Oct 2022 09:28:42 -0700 Subject: [PATCH 11/12] check for disconnection before posting warning about no notif handler --- linux/gatt/client.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/linux/gatt/client.go b/linux/gatt/client.go index 9511129..b7171af 100644 --- a/linux/gatt/client.go +++ b/linux/gatt/client.go @@ -456,7 +456,12 @@ func (p *Client) HandleNotification(req []byte) { case sub.nHandler != nil: sub.nHandler(sub.id, nd) default: - p.Warnf("no handler, dropping data vh 0x%x, indication %v, id %v, %x", vh, indication, sub.id, nd) + select { + case <-p.Disconnected(): + //ok + default: + p.Warnf("no handler, dropping data vh 0x%x, indication %v, id %v, %x", vh, indication, sub.id, nd) + } } sub.id++ } From 936a973bd6311156ba8cc715b3de8636b3d9b8fe Mon Sep 17 00:00:00 2001 From: Eric Stutzenberger Date: Fri, 21 Oct 2022 10:26:01 -0700 Subject: [PATCH 12/12] use connection disconnected function rather than current struct --- linux/gatt/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/gatt/client.go b/linux/gatt/client.go index b7171af..1230249 100644 --- a/linux/gatt/client.go +++ b/linux/gatt/client.go @@ -457,7 +457,7 @@ func (p *Client) HandleNotification(req []byte) { sub.nHandler(sub.id, nd) default: select { - case <-p.Disconnected(): + case <-p.conn.Disconnected(): //ok default: p.Warnf("no handler, dropping data vh 0x%x, indication %v, id %v, %x", vh, indication, sub.id, nd)