Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ type Conn interface {
// SetTxMTU sets the ATT_MTU which the remote device is capable of accepting.
SetTxMTU(mtu int)

// ReadRSSI retrieves the current RSSI value of remote peripheral. [Vol 2, Part E, 7.5.4]
ReadRSSI() int

// Disconnected returns a receiving channel, which is closed when the connection disconnects.
Disconnected() <-chan struct{}
}
41 changes: 41 additions & 0 deletions examples/basic/rssi/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package main

import (
"context"
"flag"
"fmt"
"log"
"strings"
"time"

"github.com/go-ble/ble"
"github.com/go-ble/ble/examples/lib/dev"
)

func main() {
macAddr := flag.String("addr", "", "peripheral MAC address")
flag.Parse()
hciDevice, err := dev.NewDevice("default")
if err != nil {
panic(err)
}
ble.SetDefaultDevice(hciDevice)

filter := func(a ble.Advertisement) bool {
return strings.ToUpper(a.Addr().String()) == strings.ToUpper(*macAddr)
}

// Scan for device
log.Printf("Scanning for %s\n", *macAddr)
ctx := ble.WithSigHandler(context.WithTimeout(context.Background(), time.Second*300))
client, err := ble.Connect(ctx, filter)
if err != nil {
panic(err)
}

for {
fmt.Printf("Client side RSSI: %d\n", client.ReadRSSI())
time.Sleep(time.Second)
}

}
71 changes: 71 additions & 0 deletions linux/att/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,18 @@ func (c *Client) Loop() {
b := make([]byte, n)
copy(b, c.rxBuf)

// TODO: better request identification
if b[0] == ExchangeMTURequestCode {
// Schedule this to be taken care of
select {
case ch <- asyncWork{handle: c.handleRequest, data: b}:
default:
// If this really happens, especially on a slow machine, enlarge the channel buffer.
_ = logger.Error("client", "req", "can't enqueue incoming request.")
}
continue
}

if (b[0] != HandleValueNotificationCode) && (b[0] != HandleValueIndicationCode) {
c.rspc <- b
continue
Expand All @@ -558,3 +570,62 @@ func (c *Client) Loop() {
}
}
}

func (c *Client) handleRequest(b []byte) {
switch b[0] {
case ExchangeMTURequestCode:
resp := c.handleExchangeMTURequest(b)
if len(resp) != 0 {
err := c.sendCmd(resp)
if err != nil {
_ = logger.Error("client", "req", fmt.Sprintf("error sending MTU response: %s", err.Error()))
}
}
default:
errRsp := newErrorResponse(b[0], 0x0000, ble.ErrReqNotSupp)
_ = c.sendCmd(errRsp)
_ = logger.Warn("client", "req", fmt.Sprintf("Received unhandled request [0x%X]", b))
}
}

// handle MTU Exchange request. [Vol 3, Part F, 3.4.2]
// ExchangeMTU informs the server of the client’s maximum receive MTU size and
// request the server to respond with its maximum receive MTU size. [Vol 3, Part F, 3.4.2.1]
func (c *Client) handleExchangeMTURequest(r ExchangeMTURequest) []byte {
// Acquire and reuse the txBuf, and release it after usage.
// The same txBuf, or a newly allocate one, if the txMTU is changed,
// will be released back to the channel.

// We do this first to prevent races with ExchangeMTURequest
txBuf := <-c.chTxBuf

// Validate the request.
switch {
case len(r) != 3:
fallthrough
case r.ClientRxMTU() < 23:
return newErrorResponse(r.AttributeOpcode(), 0x0000, ble.ErrInvalidPDU)
}

txMTU := int(r.ClientRxMTU())
// Our rxMTU for the response
rxMTU := c.l2c.RxMTU()

// Update transmit MTU to max supported by the other side
logger.Debug("client", "req", fmt.Sprintf("server requested an MTU change to TX:%d RX:%d", txMTU, rxMTU))
c.l2c.SetTxMTU(txMTU)

defer func() {
// Update the tx buffer if needed
if len(txBuf) != txMTU {
c.chTxBuf <- make([]byte, txMTU, txMTU)
} else {
c.chTxBuf <- txBuf
}
}()

rsp := ExchangeMTUResponse(txBuf)
rsp.SetAttributeOpcode()
rsp.SetServerRxMTU(uint16(rxMTU))
return rsp[:3]
}
3 changes: 1 addition & 2 deletions linux/gatt/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,7 @@ func (p *Client) WriteDescriptor(d *ble.Descriptor, v []byte) error {
func (p *Client) ReadRSSI() int {
p.Lock()
defer p.Unlock()
// TODO:
return 0
return p.conn.ReadRSSI()
}

// ExchangeMTU informs the server of the client’s maximum receive MTU size and
Expand Down
9 changes: 9 additions & 0 deletions linux/hci/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,15 @@ func (c *Conn) Disconnected() <-chan struct{} {
return c.chDone
}

// ReadRSSI retrieves the current RSSI value of remote peripheral. [Vol 2, Part E, 7.5.4]
func (c *Conn) ReadRSSI() int {
rp := new(cmd.ReadRSSIRP)
c.hci.Send(&cmd.ReadRSSI{
Handle: c.param.ConnectionHandle(),
}, rp)
return int(rp.RSSI)
}

// Close disconnects the connection by sending hci disconnect command to the device.
func (c *Conn) Close() error {
select {
Expand Down