hci: refactor to separate HCI transport implementation from interface to not always assume UART.
Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
parent
d46f2cc206
commit
926aeb43f6
5 changed files with 144 additions and 67 deletions
|
@ -3,17 +3,16 @@
|
|||
package bluetooth
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"runtime"
|
||||
|
||||
"time"
|
||||
)
|
||||
|
||||
// hciAdapter represents the implementation for the UART connection to the HCI controller.
|
||||
// hciAdapter represents the implementation for the connection to the HCI controller.
|
||||
type hciAdapter struct {
|
||||
uart *machine.UART
|
||||
hci *hci
|
||||
att *att
|
||||
hciport hciTransport
|
||||
hci *hci
|
||||
att *att
|
||||
|
||||
isDefault bool
|
||||
scanning bool
|
||||
|
@ -49,8 +48,8 @@ func (a *hciAdapter) Address() (MACAddress, error) {
|
|||
return MACAddress{MAC: makeAddress(a.hci.address)}, nil
|
||||
}
|
||||
|
||||
func newBLEStack(uart *machine.UART) (*hci, *att) {
|
||||
h := newHCI(uart)
|
||||
func newBLEStack(port hciTransport) (*hci, *att) {
|
||||
h := newHCI(port)
|
||||
a := newATT(h)
|
||||
h.att = a
|
||||
|
||||
|
|
|
@ -8,10 +8,12 @@ import (
|
|||
|
||||
const maxConnections = 1
|
||||
|
||||
// Adapter represents the UART connection to the HCI controller.
|
||||
// Adapter represents a "plain" UART connection to the HCI controller.
|
||||
type Adapter struct {
|
||||
hciAdapter
|
||||
|
||||
uart *machine.UART
|
||||
|
||||
// used for software flow control
|
||||
cts, rts machine.Pin
|
||||
}
|
||||
|
@ -20,11 +22,13 @@ type Adapter struct {
|
|||
//
|
||||
// Make sure to call Enable() before using it to initialize the adapter.
|
||||
var DefaultAdapter = &Adapter{
|
||||
isDefault: true,
|
||||
connectHandler: func(device Device, connected bool) {
|
||||
return
|
||||
hciAdapter: hciAdapter{
|
||||
isDefault: true,
|
||||
connectHandler: func(device Device, connected bool) {
|
||||
return
|
||||
},
|
||||
connectedDevices: make([]Device, 0, maxConnections),
|
||||
},
|
||||
connectedDevices: make([]Device, 0, maxConnections),
|
||||
}
|
||||
|
||||
// SetUART sets the UART to use for the HCI connection.
|
||||
|
@ -49,16 +53,66 @@ func (a *Adapter) SetSoftwareFlowControl(cts, rts machine.Pin) error {
|
|||
// Enable configures the BLE stack. It must be called before any
|
||||
// Bluetooth-related calls (unless otherwise indicated).
|
||||
func (a *Adapter) Enable() error {
|
||||
a.hci, a.att = newBLEStack(a.uart)
|
||||
|
||||
transport := &hciUART{uart: a.uart}
|
||||
if a.cts != 0 && a.rts != 0 {
|
||||
a.hci.softRTS = a.rts
|
||||
a.hci.softRTS.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
a.hci.softRTS.High()
|
||||
transport.rts = a.rts
|
||||
a.rts.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
a.rts.High()
|
||||
|
||||
a.hci.softCTS = a.cts
|
||||
transport.cts = a.cts
|
||||
a.cts.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||
}
|
||||
|
||||
a.hci, a.att = newBLEStack(transport)
|
||||
a.enable()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type hciUART struct {
|
||||
uart *machine.UART
|
||||
|
||||
// used for software flow control
|
||||
cts, rts machine.Pin
|
||||
}
|
||||
|
||||
func (h *hciUART) startRead() {
|
||||
if h.rts != machine.NoPin {
|
||||
h.rts.Low()
|
||||
}
|
||||
}
|
||||
|
||||
func (h *hciUART) endRead() {
|
||||
if h.rts != machine.NoPin {
|
||||
h.rts.High()
|
||||
}
|
||||
}
|
||||
|
||||
func (h *hciUART) Buffered() int {
|
||||
return h.uart.Buffered()
|
||||
}
|
||||
|
||||
func (h *hciUART) ReadByte() (byte, error) {
|
||||
return h.uart.ReadByte()
|
||||
}
|
||||
|
||||
const writeAttempts = 200
|
||||
|
||||
func (h *hciUART) Write(buf []byte) (int, error) {
|
||||
if h.cts != machine.NoPin {
|
||||
retries := writeAttempts
|
||||
for h.cts.Get() {
|
||||
retries--
|
||||
if retries == 0 {
|
||||
return 0, ErrHCITimeout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n, err := h.uart.Write(buf)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
const maxConnections = 1
|
||||
|
||||
// Adapter represents the HCI connection to the NINA fw.
|
||||
// Adapter represents the HCI connection to the NINA fw using the hardware UART.
|
||||
type Adapter struct {
|
||||
hciAdapter
|
||||
}
|
||||
|
@ -54,16 +54,15 @@ func (a *Adapter) Enable() error {
|
|||
|
||||
uart.Configure(cfg)
|
||||
|
||||
a.hci, a.att = newBLEStack(uart)
|
||||
transport := &hciUART{uart: uart}
|
||||
if machine.NINA_SOFT_FLOWCONTROL {
|
||||
a.hci.softRTS = machine.NINA_RTS
|
||||
a.hci.softRTS.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
a.hci.softRTS.High()
|
||||
machine.NINA_RTS.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
machine.NINA_RTS.High()
|
||||
|
||||
a.hci.softCTS = machine.NINA_CTS
|
||||
machine.NINA_CTS.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||
}
|
||||
|
||||
a.hci, a.att = newBLEStack(transport)
|
||||
return a.enable()
|
||||
}
|
||||
|
||||
|
@ -84,3 +83,48 @@ func resetNINAInverted() {
|
|||
machine.NINA_RESETN.High()
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
}
|
||||
|
||||
type hciUART struct {
|
||||
uart *machine.UART
|
||||
}
|
||||
|
||||
func (h *hciUART) startRead() {
|
||||
if machine.NINA_SOFT_FLOWCONTROL {
|
||||
machine.NINA_RTS.Low()
|
||||
}
|
||||
}
|
||||
|
||||
func (h *hciUART) endRead() {
|
||||
if machine.NINA_SOFT_FLOWCONTROL {
|
||||
machine.NINA_RTS.High()
|
||||
}
|
||||
}
|
||||
|
||||
func (h *hciUART) Buffered() int {
|
||||
return h.uart.Buffered()
|
||||
}
|
||||
|
||||
func (h *hciUART) ReadByte() (byte, error) {
|
||||
return h.uart.ReadByte()
|
||||
}
|
||||
|
||||
const writeAttempts = 200
|
||||
|
||||
func (h *hciUART) Write(buf []byte) (int, error) {
|
||||
if machine.NINA_SOFT_FLOWCONTROL {
|
||||
retries := writeAttempts
|
||||
for machine.NINA_CTS.Get() {
|
||||
retries--
|
||||
if retries == 0 {
|
||||
return 0, ErrHCITimeout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n, err := h.uart.Write(buf)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
|
64
hci.go
64
hci.go
|
@ -1,4 +1,4 @@
|
|||
//go:build ninafw
|
||||
//go:build ninafw || hci
|
||||
|
||||
package bluetooth
|
||||
|
||||
|
@ -6,7 +6,6 @@ import (
|
|||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -122,10 +121,16 @@ type leConnectData struct {
|
|||
timeout uint16
|
||||
}
|
||||
|
||||
type hciTransport interface {
|
||||
startRead()
|
||||
endRead()
|
||||
Buffered() int
|
||||
ReadByte() (byte, error)
|
||||
Write(buf []byte) (int, error)
|
||||
}
|
||||
|
||||
type hci struct {
|
||||
uart *machine.UART
|
||||
softCTS machine.Pin
|
||||
softRTS machine.Pin
|
||||
transport hciTransport
|
||||
att *att
|
||||
l2cap *l2cap
|
||||
buf []byte
|
||||
|
@ -140,24 +145,19 @@ type hci struct {
|
|||
pendingPkt uint16
|
||||
}
|
||||
|
||||
func newHCI(uart *machine.UART) *hci {
|
||||
func newHCI(t hciTransport) *hci {
|
||||
return &hci{
|
||||
uart: uart,
|
||||
softCTS: machine.NoPin,
|
||||
softRTS: machine.NoPin,
|
||||
buf: make([]byte, 256),
|
||||
transport: t,
|
||||
buf: make([]byte, 256),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *hci) start() error {
|
||||
if h.softRTS != machine.NoPin {
|
||||
h.softRTS.Low()
|
||||
h.transport.startRead()
|
||||
defer h.transport.endRead()
|
||||
|
||||
defer h.softRTS.High()
|
||||
}
|
||||
|
||||
for h.uart.Buffered() > 0 {
|
||||
h.uart.ReadByte()
|
||||
for h.transport.Buffered() > 0 {
|
||||
h.transport.ReadByte()
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -172,15 +172,12 @@ func (h *hci) reset() error {
|
|||
}
|
||||
|
||||
func (h *hci) poll() error {
|
||||
if h.softRTS != machine.NoPin {
|
||||
h.softRTS.Low()
|
||||
|
||||
defer h.softRTS.High()
|
||||
}
|
||||
h.transport.startRead()
|
||||
defer h.transport.endRead()
|
||||
|
||||
i := 0
|
||||
for h.uart.Buffered() > 0 {
|
||||
data, _ := h.uart.ReadByte()
|
||||
for h.transport.Buffered() > 0 {
|
||||
data, _ := h.transport.ReadByte()
|
||||
h.buf[i] = data
|
||||
|
||||
done, err := h.processPacket(i)
|
||||
|
@ -487,25 +484,8 @@ func (h *hci) sendAclPkt(handle uint16, cid uint8, data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
const writeAttempts = 200
|
||||
|
||||
func (h *hci) write(buf []byte) (int, error) {
|
||||
if h.softCTS != machine.NoPin {
|
||||
retries := writeAttempts
|
||||
for h.softCTS.Get() {
|
||||
retries--
|
||||
if retries == 0 {
|
||||
return 0, ErrHCITimeout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n, err := h.uart.Write(buf)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return n, nil
|
||||
return h.transport.Write(buf)
|
||||
}
|
||||
|
||||
type aclDataHeader struct {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//go:build ninafw
|
||||
//go:build ninafw || hci
|
||||
|
||||
package bluetooth
|
||||
|
||||
|
|
Loading…
Reference in a new issue