Skip to content

Commit 457af75

Browse files
committed
cyw43439: HCI implementation
Signed-off-by: deadprogram <[email protected]>
1 parent 9905abd commit 457af75

14 files changed

+201
-21
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ smoketest-tinygo:
4444
@md5sum test.hex
4545
$(TINYGO) build -o test.uf2 -size=short -target=circuitplay-express -tags="hci hci_uart" ./examples/advertisement
4646
@md5sum test.hex
47+
$(TINYGO) build -o test.uf2 -size=short -target=pico-w ./examples/discover
48+
@md5sum test.hex
49+
$(TINYGO) build -o test.uf2 -size=short -target=badger2040-w ./examples/advertisement
50+
@md5sum test.hex
4751

4852
smoketest-linux:
4953
# Test on Linux.

adapter_cyw43439.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//go:build cyw43439
2+
3+
package bluetooth
4+
5+
import (
6+
"machine"
7+
8+
"log/slog"
9+
10+
"github.com/soypat/cyw43439"
11+
)
12+
13+
const maxConnections = 1
14+
15+
// Adapter represents a SPI connection to the HCI controller on an attached CYW4349 module.
16+
type Adapter struct {
17+
hciAdapter
18+
}
19+
20+
// DefaultAdapter is the default adapter on the current system.
21+
//
22+
// Make sure to call Enable() before using it to initialize the adapter.
23+
var DefaultAdapter = &Adapter{
24+
hciAdapter: hciAdapter{
25+
isDefault: true,
26+
connectHandler: func(device Device, connected bool) {
27+
return
28+
},
29+
connectedDevices: make([]Device, 0, maxConnections),
30+
},
31+
}
32+
33+
// Enable configures the BLE stack. It must be called before any
34+
// Bluetooth-related calls (unless otherwise indicated).
35+
func (a *Adapter) Enable() error {
36+
if debug {
37+
println("Initializing CYW43439 device")
38+
}
39+
40+
dev := cyw43439.NewPicoWDevice()
41+
cfg := cyw43439.DefaultBluetoothConfig()
42+
if debug {
43+
cfg.Logger = slog.New(slog.NewTextHandler(machine.USBCDC, &slog.HandlerOptions{
44+
Level: slog.LevelDebug - 2,
45+
}))
46+
}
47+
48+
err := dev.Init(cfg)
49+
if err != nil {
50+
if debug {
51+
println("Error initializing CYW43439 device", err.Error())
52+
}
53+
return err
54+
}
55+
56+
transport := &hciSPI{dev: dev}
57+
58+
a.hci, a.att = newBLEStack(transport)
59+
if debug {
60+
println("Enabling CYW43439 device")
61+
}
62+
63+
a.enable()
64+
65+
if debug {
66+
println("Enabled CYW43439 device")
67+
}
68+
69+
return nil
70+
}
71+
72+
type hciSPI struct {
73+
dev *cyw43439.Device
74+
}
75+
76+
func (h *hciSPI) startRead() {
77+
}
78+
79+
func (h *hciSPI) endRead() {
80+
}
81+
82+
func (h *hciSPI) Buffered() int {
83+
return h.dev.BufferedHCI()
84+
}
85+
86+
func (h *hciSPI) ReadByte() (byte, error) {
87+
var buf [1]byte
88+
89+
r, err := h.dev.HCIReadWriter()
90+
if err != nil {
91+
return 0, err
92+
}
93+
if _, err := r.Read(buf[:]); err != nil {
94+
return 0, err
95+
}
96+
97+
return buf[0], nil
98+
}
99+
100+
func (h *hciSPI) Read(buf []byte) (int, error) {
101+
r, err := h.dev.HCIReadWriter()
102+
if err != nil {
103+
return 0, err
104+
}
105+
106+
return r.Read(buf)
107+
}
108+
109+
func (h *hciSPI) Write(buf []byte) (int, error) {
110+
w, err := h.dev.HCIReadWriter()
111+
if err != nil {
112+
return 0, err
113+
}
114+
115+
return w.Write(buf)
116+
}

adapter_hci.go

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

33
package bluetooth
44

@@ -25,9 +25,18 @@ type hciAdapter struct {
2525
}
2626

2727
func (a *hciAdapter) enable() error {
28-
a.hci.start()
28+
if err := a.hci.start(); err != nil {
29+
if debug {
30+
println("error starting HCI:", err.Error())
31+
}
32+
return err
33+
}
2934

3035
if err := a.hci.reset(); err != nil {
36+
if debug {
37+
println("error resetting HCI:", err.Error())
38+
}
39+
3140
return err
3241
}
3342

adapter_hci_uart.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ func (h *hciUART) ReadByte() (byte, error) {
9696
return h.uart.ReadByte()
9797
}
9898

99+
func (h *hciUART) Read(buf []byte) (int, error) {
100+
return h.uart.Read(buf)
101+
}
102+
99103
const writeAttempts = 200
100104

101105
func (h *hciUART) Write(buf []byte) (int, error) {

adapter_ninafw.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ func (h *hciUART) ReadByte() (byte, error) {
108108
return h.uart.ReadByte()
109109
}
110110

111+
func (h *hciUART) Read(buf []byte) (int, error) {
112+
return h.uart.Read(buf)
113+
}
114+
111115
const writeAttempts = 200
112116

113117
func (h *hciUART) Write(buf []byte) (int, error) {

att_hci.go

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

33
package bluetooth
44

gap_hci.go

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

33
package bluetooth
44

gattc_hci.go

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

33
package bluetooth
44

gatts_hci.go

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

33
package bluetooth
44

go.mod

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
module tinygo.org/x/bluetooth
22

3-
go 1.18
3+
go 1.20
44

55
require (
66
github.com/go-ole/go-ole v1.2.6
77
github.com/godbus/dbus/v5 v5.1.0
88
github.com/saltosystems/winrt-go v0.0.0-20240509164145-4f7860a3bd2b
9+
github.com/soypat/cyw43439 v0.0.0-20240521202811-13f2f2d46d64
910
github.com/tinygo-org/cbgo v0.0.4
1011
golang.org/x/crypto v0.12.0
1112
tinygo.org/x/drivers v0.26.1-0.20230922160320-ed51435c2ef6
@@ -16,6 +17,9 @@ require (
1617
require (
1718
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
1819
github.com/sirupsen/logrus v1.9.3 // indirect
20+
github.com/soypat/seqs v0.0.0-20240509190925-a6350cee83a7 // indirect
21+
github.com/tinygo-org/pio v0.0.0-20231216154340-cd888eb58899 // indirect
22+
golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 // indirect
1923
golang.org/x/sys v0.11.0 // indirect
2024
golang.org/x/term v0.11.0 // indirect
2125
)

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,22 @@ github.com/saltosystems/winrt-go v0.0.0-20240509164145-4f7860a3bd2b/go.mod h1:CI
1515
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
1616
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
1717
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
18+
github.com/soypat/cyw43439 v0.0.0-20240521202811-13f2f2d46d64 h1:dNmjx0DMk6H1RdVhmfQudggSDjlayX0G0fOC8SxfAW8=
19+
github.com/soypat/cyw43439 v0.0.0-20240521202811-13f2f2d46d64/go.mod h1:2c95aUfGi2f0oDceIIeozc8ZtVz4NJiZMwkyEGv6q/Y=
20+
github.com/soypat/seqs v0.0.0-20240509190925-a6350cee83a7 h1:0AQR/zVYjgF5TPrjc/bfDdydWApSUyUgbM08kbm+FdQ=
21+
github.com/soypat/seqs v0.0.0-20240509190925-a6350cee83a7/go.mod h1:oCVCNGCHMKoBj97Zp9znLbQ1nHxpkmOY9X+UAGzOxc8=
1822
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
1923
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
2024
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
2125
github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
2226
github.com/tinygo-org/cbgo v0.0.4 h1:3D76CRYbH03Rudi8sEgs/YO0x3JIMdyq8jlQtk/44fU=
2327
github.com/tinygo-org/cbgo v0.0.4/go.mod h1:7+HgWIHd4nbAz0ESjGlJ1/v9LDU1Ox8MGzP9mah/fLk=
28+
github.com/tinygo-org/pio v0.0.0-20231216154340-cd888eb58899 h1:/DyaXDEWMqoVUVEJVJIlNk1bXTbFs8s3Q4GdPInSKTQ=
29+
github.com/tinygo-org/pio v0.0.0-20231216154340-cd888eb58899/go.mod h1:LU7Dw00NJ+N86QkeTGjMLNkYcEYMor6wTDpTCu0EaH8=
2430
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
2531
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
32+
golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 h1:/yRP+0AN7mf5DkD3BAI6TOFnd51gEoDEb8o35jIFtgw=
33+
golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
2634
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
2735
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
2836
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

hci.go

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

33
package bluetooth
44

@@ -66,10 +66,11 @@ const (
6666
leMetaEventEnhancedConnectionComplete = 0x0A
6767
leMetaEventDirectAdvertisingReport = 0x0B
6868

69-
hciCommandPkt = 0x01
70-
hciACLDataPkt = 0x02
71-
hciEventPkt = 0x04
72-
hciSecurityPkt = 0x06
69+
hciCommandPkt = 0x01
70+
hciACLDataPkt = 0x02
71+
hciSynchronousDataPkt = 0x03
72+
hciEventPkt = 0x04
73+
hciSecurityPkt = 0x06
7374

7475
evtDisconnComplete = 0x05
7576
evtEncryptionChange = 0x08
@@ -126,6 +127,7 @@ type hciTransport interface {
126127
endRead()
127128
Buffered() int
128129
ReadByte() (byte, error)
130+
Read(buf []byte) (int, error)
129131
Write(buf []byte) (int, error)
130132
}
131133

@@ -156,8 +158,19 @@ func (h *hci) start() error {
156158
h.transport.startRead()
157159
defer h.transport.endRead()
158160

159-
for h.transport.Buffered() > 0 {
160-
h.transport.ReadByte()
161+
var data [32]byte
162+
for {
163+
if i := h.transport.Buffered(); i > 0 {
164+
if i > len(data) {
165+
i = len(data)
166+
}
167+
if _, err := h.transport.Read(data[:i]); err != nil {
168+
return err
169+
}
170+
171+
continue
172+
}
173+
return nil
161174
}
162175

163176
return nil
@@ -177,14 +190,19 @@ func (h *hci) poll() error {
177190

178191
i := 0
179192
for h.transport.Buffered() > 0 {
180-
data, _ := h.transport.ReadByte()
181-
h.buf[i] = data
193+
sz := h.transport.Buffered()
194+
c := sz + 4 - (sz % 4)
195+
_, err := h.transport.Read(h.buf[i : i+c])
196+
if err != nil {
197+
return err
198+
}
199+
i += sz
182200

183201
done, err := h.processPacket(i)
184202
switch {
185203
case err == ErrHCIUnknown || err == ErrHCIInvalidPacket || err == ErrHCIUnknownEvent:
186204
if debug {
187-
println("hci error:", err.Error())
205+
println("hci error:", err.Error(), hex.EncodeToString(h.buf[:i]))
188206
}
189207
i = 0
190208
time.Sleep(5 * time.Millisecond)
@@ -199,7 +217,6 @@ func (h *hci) poll() error {
199217
i = 0
200218
time.Sleep(5 * time.Millisecond)
201219
default:
202-
i++
203220
time.Sleep(1 * time.Millisecond)
204221
}
205222
}
@@ -238,9 +255,19 @@ func (h *hci) processPacket(i int) (bool, error) {
238255
}
239256
}
240257

258+
case hciSynchronousDataPkt:
259+
// not supported by BLE, so ignore
260+
if i > 3 {
261+
pktlen := int(h.buf[3])
262+
if debug {
263+
println("hci synchronous data:", i, pktlen, hex.EncodeToString(h.buf[:1+3+pktlen]))
264+
}
265+
return true, nil
266+
}
267+
241268
default:
242269
if debug {
243-
println("unknown packet data:", h.buf[0])
270+
println("unknown packet data:", hex.EncodeToString(h.buf[0:i]))
244271
}
245272
return true, ErrHCIUnknown
246273
}
@@ -725,6 +752,10 @@ func (h *hci) handleEventData(buf []byte) error {
725752
return ErrHCIUnknownEvent
726753
}
727754
case evtHardwareError:
755+
if debug {
756+
println("evtHardwareError", hex.EncodeToString(buf))
757+
}
758+
728759
return ErrHCIUnknownEvent
729760
}
730761

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 || hci
1+
//go:build ninafw || hci || cyw43439
22

33
package bluetooth
44

uuid_hci.go

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

33
package bluetooth
44

0 commit comments

Comments
 (0)