Skip to content

Commit 926aeb4

Browse files
committed
hci: refactor to separate HCI transport implementation from interface to not always assume UART.
Signed-off-by: deadprogram <[email protected]>
1 parent d46f2cc commit 926aeb4

File tree

5 files changed

+144
-67
lines changed

5 files changed

+144
-67
lines changed

adapter_hci.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@
33
package bluetooth
44

55
import (
6-
"machine"
76
"runtime"
87

98
"time"
109
)
1110

12-
// hciAdapter represents the implementation for the UART connection to the HCI controller.
11+
// hciAdapter represents the implementation for the connection to the HCI controller.
1312
type hciAdapter struct {
14-
uart *machine.UART
15-
hci *hci
16-
att *att
13+
hciport hciTransport
14+
hci *hci
15+
att *att
1716

1817
isDefault bool
1918
scanning bool
@@ -49,8 +48,8 @@ func (a *hciAdapter) Address() (MACAddress, error) {
4948
return MACAddress{MAC: makeAddress(a.hci.address)}, nil
5049
}
5150

52-
func newBLEStack(uart *machine.UART) (*hci, *att) {
53-
h := newHCI(uart)
51+
func newBLEStack(port hciTransport) (*hci, *att) {
52+
h := newHCI(port)
5453
a := newATT(h)
5554
h.att = a
5655

adapter_hci_uart.go

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ import (
88

99
const maxConnections = 1
1010

11-
// Adapter represents the UART connection to the HCI controller.
11+
// Adapter represents a "plain" UART connection to the HCI controller.
1212
type Adapter struct {
1313
hciAdapter
1414

15+
uart *machine.UART
16+
1517
// used for software flow control
1618
cts, rts machine.Pin
1719
}
@@ -20,11 +22,13 @@ type Adapter struct {
2022
//
2123
// Make sure to call Enable() before using it to initialize the adapter.
2224
var DefaultAdapter = &Adapter{
23-
isDefault: true,
24-
connectHandler: func(device Device, connected bool) {
25-
return
25+
hciAdapter: hciAdapter{
26+
isDefault: true,
27+
connectHandler: func(device Device, connected bool) {
28+
return
29+
},
30+
connectedDevices: make([]Device, 0, maxConnections),
2631
},
27-
connectedDevices: make([]Device, 0, maxConnections),
2832
}
2933

3034
// SetUART sets the UART to use for the HCI connection.
@@ -49,16 +53,66 @@ func (a *Adapter) SetSoftwareFlowControl(cts, rts machine.Pin) error {
4953
// Enable configures the BLE stack. It must be called before any
5054
// Bluetooth-related calls (unless otherwise indicated).
5155
func (a *Adapter) Enable() error {
52-
a.hci, a.att = newBLEStack(a.uart)
53-
56+
transport := &hciUART{uart: a.uart}
5457
if a.cts != 0 && a.rts != 0 {
55-
a.hci.softRTS = a.rts
56-
a.hci.softRTS.Configure(machine.PinConfig{Mode: machine.PinOutput})
57-
a.hci.softRTS.High()
58+
transport.rts = a.rts
59+
a.rts.Configure(machine.PinConfig{Mode: machine.PinOutput})
60+
a.rts.High()
5861

59-
a.hci.softCTS = a.cts
62+
transport.cts = a.cts
6063
a.cts.Configure(machine.PinConfig{Mode: machine.PinInput})
6164
}
6265

66+
a.hci, a.att = newBLEStack(transport)
6367
a.enable()
68+
69+
return nil
70+
}
71+
72+
type hciUART struct {
73+
uart *machine.UART
74+
75+
// used for software flow control
76+
cts, rts machine.Pin
77+
}
78+
79+
func (h *hciUART) startRead() {
80+
if h.rts != machine.NoPin {
81+
h.rts.Low()
82+
}
83+
}
84+
85+
func (h *hciUART) endRead() {
86+
if h.rts != machine.NoPin {
87+
h.rts.High()
88+
}
89+
}
90+
91+
func (h *hciUART) Buffered() int {
92+
return h.uart.Buffered()
93+
}
94+
95+
func (h *hciUART) ReadByte() (byte, error) {
96+
return h.uart.ReadByte()
97+
}
98+
99+
const writeAttempts = 200
100+
101+
func (h *hciUART) Write(buf []byte) (int, error) {
102+
if h.cts != machine.NoPin {
103+
retries := writeAttempts
104+
for h.cts.Get() {
105+
retries--
106+
if retries == 0 {
107+
return 0, ErrHCITimeout
108+
}
109+
}
110+
}
111+
112+
n, err := h.uart.Write(buf)
113+
if err != nil {
114+
return 0, err
115+
}
116+
117+
return n, nil
64118
}

adapter_ninafw.go

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
const maxConnections = 1
1111

12-
// Adapter represents the HCI connection to the NINA fw.
12+
// Adapter represents the HCI connection to the NINA fw using the hardware UART.
1313
type Adapter struct {
1414
hciAdapter
1515
}
@@ -54,16 +54,15 @@ func (a *Adapter) Enable() error {
5454

5555
uart.Configure(cfg)
5656

57-
a.hci, a.att = newBLEStack(uart)
57+
transport := &hciUART{uart: uart}
5858
if machine.NINA_SOFT_FLOWCONTROL {
59-
a.hci.softRTS = machine.NINA_RTS
60-
a.hci.softRTS.Configure(machine.PinConfig{Mode: machine.PinOutput})
61-
a.hci.softRTS.High()
59+
machine.NINA_RTS.Configure(machine.PinConfig{Mode: machine.PinOutput})
60+
machine.NINA_RTS.High()
6261

63-
a.hci.softCTS = machine.NINA_CTS
6462
machine.NINA_CTS.Configure(machine.PinConfig{Mode: machine.PinInput})
6563
}
6664

65+
a.hci, a.att = newBLEStack(transport)
6766
return a.enable()
6867
}
6968

@@ -84,3 +83,48 @@ func resetNINAInverted() {
8483
machine.NINA_RESETN.High()
8584
time.Sleep(1000 * time.Millisecond)
8685
}
86+
87+
type hciUART struct {
88+
uart *machine.UART
89+
}
90+
91+
func (h *hciUART) startRead() {
92+
if machine.NINA_SOFT_FLOWCONTROL {
93+
machine.NINA_RTS.Low()
94+
}
95+
}
96+
97+
func (h *hciUART) endRead() {
98+
if machine.NINA_SOFT_FLOWCONTROL {
99+
machine.NINA_RTS.High()
100+
}
101+
}
102+
103+
func (h *hciUART) Buffered() int {
104+
return h.uart.Buffered()
105+
}
106+
107+
func (h *hciUART) ReadByte() (byte, error) {
108+
return h.uart.ReadByte()
109+
}
110+
111+
const writeAttempts = 200
112+
113+
func (h *hciUART) Write(buf []byte) (int, error) {
114+
if machine.NINA_SOFT_FLOWCONTROL {
115+
retries := writeAttempts
116+
for machine.NINA_CTS.Get() {
117+
retries--
118+
if retries == 0 {
119+
return 0, ErrHCITimeout
120+
}
121+
}
122+
}
123+
124+
n, err := h.uart.Write(buf)
125+
if err != nil {
126+
return 0, err
127+
}
128+
129+
return n, nil
130+
}

hci.go

Lines changed: 22 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
//go:build ninafw
1+
//go:build ninafw || hci
22

33
package bluetooth
44

55
import (
66
"encoding/binary"
77
"encoding/hex"
88
"errors"
9-
"machine"
109
"time"
1110
)
1211

@@ -122,10 +121,16 @@ type leConnectData struct {
122121
timeout uint16
123122
}
124123

124+
type hciTransport interface {
125+
startRead()
126+
endRead()
127+
Buffered() int
128+
ReadByte() (byte, error)
129+
Write(buf []byte) (int, error)
130+
}
131+
125132
type hci struct {
126-
uart *machine.UART
127-
softCTS machine.Pin
128-
softRTS machine.Pin
133+
transport hciTransport
129134
att *att
130135
l2cap *l2cap
131136
buf []byte
@@ -140,24 +145,19 @@ type hci struct {
140145
pendingPkt uint16
141146
}
142147

143-
func newHCI(uart *machine.UART) *hci {
148+
func newHCI(t hciTransport) *hci {
144149
return &hci{
145-
uart: uart,
146-
softCTS: machine.NoPin,
147-
softRTS: machine.NoPin,
148-
buf: make([]byte, 256),
150+
transport: t,
151+
buf: make([]byte, 256),
149152
}
150153
}
151154

152155
func (h *hci) start() error {
153-
if h.softRTS != machine.NoPin {
154-
h.softRTS.Low()
155-
156-
defer h.softRTS.High()
157-
}
156+
h.transport.startRead()
157+
defer h.transport.endRead()
158158

159-
for h.uart.Buffered() > 0 {
160-
h.uart.ReadByte()
159+
for h.transport.Buffered() > 0 {
160+
h.transport.ReadByte()
161161
}
162162

163163
return nil
@@ -172,15 +172,12 @@ func (h *hci) reset() error {
172172
}
173173

174174
func (h *hci) poll() error {
175-
if h.softRTS != machine.NoPin {
176-
h.softRTS.Low()
177-
178-
defer h.softRTS.High()
179-
}
175+
h.transport.startRead()
176+
defer h.transport.endRead()
180177

181178
i := 0
182-
for h.uart.Buffered() > 0 {
183-
data, _ := h.uart.ReadByte()
179+
for h.transport.Buffered() > 0 {
180+
data, _ := h.transport.ReadByte()
184181
h.buf[i] = data
185182

186183
done, err := h.processPacket(i)
@@ -487,25 +484,8 @@ func (h *hci) sendAclPkt(handle uint16, cid uint8, data []byte) error {
487484
return nil
488485
}
489486

490-
const writeAttempts = 200
491-
492487
func (h *hci) write(buf []byte) (int, error) {
493-
if h.softCTS != machine.NoPin {
494-
retries := writeAttempts
495-
for h.softCTS.Get() {
496-
retries--
497-
if retries == 0 {
498-
return 0, ErrHCITimeout
499-
}
500-
}
501-
}
502-
503-
n, err := h.uart.Write(buf)
504-
if err != nil {
505-
return 0, err
506-
}
507-
508-
return n, nil
488+
return h.transport.Write(buf)
509489
}
510490

511491
type aclDataHeader struct {

l2cap_hci.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:build ninafw
1+
//go:build ninafw || hci
22

33
package bluetooth
44

0 commit comments

Comments
 (0)