457af7571a
Signed-off-by: deadprogram <ron@hybridgroup.com>
157 lines
3.5 KiB
Go
157 lines
3.5 KiB
Go
//go:build ninafw || hci || cyw43439
|
|
|
|
package bluetooth
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
)
|
|
|
|
const (
|
|
connectionParamUpdateRequest = 0x12
|
|
connectionParamUpdateResponse = 0x13
|
|
)
|
|
|
|
type l2capConnectionParamReqPkt struct {
|
|
minInterval uint16
|
|
maxInterval uint16
|
|
latency uint16
|
|
timeout uint16
|
|
}
|
|
|
|
func (l *l2capConnectionParamReqPkt) Write(buf []byte) (int, error) {
|
|
l.minInterval = binary.LittleEndian.Uint16(buf[0:])
|
|
l.maxInterval = binary.LittleEndian.Uint16(buf[2:])
|
|
l.latency = binary.LittleEndian.Uint16(buf[4:])
|
|
l.timeout = binary.LittleEndian.Uint16(buf[6:])
|
|
|
|
return 8, nil
|
|
}
|
|
|
|
func (l *l2capConnectionParamReqPkt) Read(p []byte) (int, error) {
|
|
binary.LittleEndian.PutUint16(p[0:], l.minInterval)
|
|
binary.LittleEndian.PutUint16(p[2:], l.maxInterval)
|
|
binary.LittleEndian.PutUint16(p[4:], l.latency)
|
|
binary.LittleEndian.PutUint16(p[6:], l.timeout)
|
|
|
|
return 8, nil
|
|
}
|
|
|
|
type l2capConnectionParamResponsePkt struct {
|
|
code uint8
|
|
identifier uint8
|
|
length uint16
|
|
value uint16
|
|
}
|
|
|
|
func (l *l2capConnectionParamResponsePkt) Read(p []byte) (int, error) {
|
|
p[0] = l.code
|
|
p[1] = l.identifier
|
|
binary.LittleEndian.PutUint16(p[2:], l.length)
|
|
binary.LittleEndian.PutUint16(p[4:], l.value)
|
|
|
|
return 6, nil
|
|
}
|
|
|
|
type l2cap struct {
|
|
hci *hci
|
|
}
|
|
|
|
func newL2CAP(hci *hci) *l2cap {
|
|
return &l2cap{
|
|
hci: hci,
|
|
}
|
|
}
|
|
|
|
func (l *l2cap) addConnection(handle uint16, role uint8, interval, timeout uint16) error {
|
|
if role != 0x01 {
|
|
return nil
|
|
}
|
|
|
|
var b [12]byte
|
|
b[0] = connectionParamUpdateRequest
|
|
b[1] = 0x01
|
|
binary.LittleEndian.PutUint16(b[2:], 8)
|
|
binary.LittleEndian.PutUint16(b[4:], interval)
|
|
binary.LittleEndian.PutUint16(b[6:], interval)
|
|
binary.LittleEndian.PutUint16(b[8:], 0)
|
|
binary.LittleEndian.PutUint16(b[10:], timeout)
|
|
|
|
return l.sendReq(handle, b[:])
|
|
}
|
|
|
|
func (l *l2cap) removeConnection(handle uint16) error {
|
|
return nil
|
|
}
|
|
|
|
func (l *l2cap) handleData(handle uint16, buf []byte) error {
|
|
code := buf[0]
|
|
identifier := buf[1]
|
|
//length := binary.LittleEndian.Uint16(buf[2:4])
|
|
|
|
if debug {
|
|
println("l2cap.handleData:", handle, "data:", hex.EncodeToString(buf))
|
|
}
|
|
|
|
// TODO: check length
|
|
|
|
switch code {
|
|
case connectionParamUpdateRequest:
|
|
return l.handleParameterUpdateRequest(handle, identifier, buf[4:])
|
|
|
|
case connectionParamUpdateResponse:
|
|
return l.handleParameterUpdateResponse(handle, identifier, buf[4:])
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (l *l2cap) handleParameterUpdateRequest(connectionHandle uint16, identifier uint8, data []byte) error {
|
|
if debug {
|
|
println("l2cap.handleParameterUpdateRequest:", connectionHandle, "data:", hex.EncodeToString(data))
|
|
}
|
|
|
|
req := l2capConnectionParamReqPkt{}
|
|
req.Write(data)
|
|
|
|
// TODO: check against min/max
|
|
|
|
resp := l2capConnectionParamResponsePkt{
|
|
code: connectionParamUpdateResponse,
|
|
identifier: identifier,
|
|
length: 2,
|
|
value: 0,
|
|
}
|
|
|
|
var b [6]byte
|
|
resp.Read(b[:])
|
|
|
|
if err := l.sendReq(connectionHandle, b[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
// valid so update connection parameters
|
|
if resp.value == 0 {
|
|
return l.hci.leConnUpdate(connectionHandle, req.minInterval, req.maxInterval, req.latency, req.timeout)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (l *l2cap) handleParameterUpdateResponse(connectionHandle uint16, identifier uint8, data []byte) error {
|
|
if debug {
|
|
println("l2cap.handleParameterUpdateResponse:", connectionHandle, "data:", hex.EncodeToString(data))
|
|
}
|
|
|
|
// for now do nothing
|
|
return nil
|
|
}
|
|
|
|
func (l *l2cap) sendReq(handle uint16, data []byte) error {
|
|
if debug {
|
|
println("l2cap.sendReq:", handle, "data:", hex.EncodeToString(data))
|
|
}
|
|
|
|
return l.hci.sendAclPkt(handle, signalingCID, data)
|
|
}
|