Skip to content

Commit

Permalink
cyw43439: HCI implementation
Browse files Browse the repository at this point in the history
Signed-off-by: deadprogram <[email protected]>
  • Loading branch information
deadprogram committed Jun 11, 2024
1 parent 9905abd commit 457af75
Show file tree
Hide file tree
Showing 14 changed files with 201 additions and 21 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ smoketest-tinygo:
@md5sum test.hex
$(TINYGO) build -o test.uf2 -size=short -target=circuitplay-express -tags="hci hci_uart" ./examples/advertisement
@md5sum test.hex
$(TINYGO) build -o test.uf2 -size=short -target=pico-w ./examples/discover
@md5sum test.hex
$(TINYGO) build -o test.uf2 -size=short -target=badger2040-w ./examples/advertisement
@md5sum test.hex

smoketest-linux:
# Test on Linux.
Expand Down
116 changes: 116 additions & 0 deletions adapter_cyw43439.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//go:build cyw43439

package bluetooth

import (
"machine"

"log/slog"

"github.com/soypat/cyw43439"
)

const maxConnections = 1

// Adapter represents a SPI connection to the HCI controller on an attached CYW4349 module.
type Adapter struct {
hciAdapter
}

// DefaultAdapter is the default adapter on the current system.
//
// Make sure to call Enable() before using it to initialize the adapter.
var DefaultAdapter = &Adapter{
hciAdapter: hciAdapter{
isDefault: true,
connectHandler: func(device Device, connected bool) {
return
},
connectedDevices: make([]Device, 0, maxConnections),
},
}

// Enable configures the BLE stack. It must be called before any
// Bluetooth-related calls (unless otherwise indicated).
func (a *Adapter) Enable() error {
if debug {
println("Initializing CYW43439 device")
}

dev := cyw43439.NewPicoWDevice()
cfg := cyw43439.DefaultBluetoothConfig()
if debug {
cfg.Logger = slog.New(slog.NewTextHandler(machine.USBCDC, &slog.HandlerOptions{
Level: slog.LevelDebug - 2,
}))
}

err := dev.Init(cfg)
if err != nil {
if debug {
println("Error initializing CYW43439 device", err.Error())
}
return err
}

transport := &hciSPI{dev: dev}

a.hci, a.att = newBLEStack(transport)
if debug {
println("Enabling CYW43439 device")
}

a.enable()

if debug {
println("Enabled CYW43439 device")
}

return nil
}

type hciSPI struct {
dev *cyw43439.Device
}

func (h *hciSPI) startRead() {
}

func (h *hciSPI) endRead() {
}

func (h *hciSPI) Buffered() int {
return h.dev.BufferedHCI()
}

func (h *hciSPI) ReadByte() (byte, error) {
var buf [1]byte

r, err := h.dev.HCIReadWriter()
if err != nil {
return 0, err
}
if _, err := r.Read(buf[:]); err != nil {
return 0, err
}

return buf[0], nil
}

func (h *hciSPI) Read(buf []byte) (int, error) {
r, err := h.dev.HCIReadWriter()
if err != nil {
return 0, err
}

return r.Read(buf)
}

func (h *hciSPI) Write(buf []byte) (int, error) {
w, err := h.dev.HCIReadWriter()
if err != nil {
return 0, err
}

return w.Write(buf)
}
13 changes: 11 additions & 2 deletions adapter_hci.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build hci || ninafw
//go:build hci || ninafw || cyw43439

package bluetooth

Expand All @@ -25,9 +25,18 @@ type hciAdapter struct {
}

func (a *hciAdapter) enable() error {
a.hci.start()
if err := a.hci.start(); err != nil {
if debug {
println("error starting HCI:", err.Error())
}
return err
}

if err := a.hci.reset(); err != nil {
if debug {
println("error resetting HCI:", err.Error())
}

return err
}

Expand Down
4 changes: 4 additions & 0 deletions adapter_hci_uart.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ func (h *hciUART) ReadByte() (byte, error) {
return h.uart.ReadByte()
}

func (h *hciUART) Read(buf []byte) (int, error) {
return h.uart.Read(buf)
}

const writeAttempts = 200

func (h *hciUART) Write(buf []byte) (int, error) {
Expand Down
4 changes: 4 additions & 0 deletions adapter_ninafw.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ func (h *hciUART) ReadByte() (byte, error) {
return h.uart.ReadByte()
}

func (h *hciUART) Read(buf []byte) (int, error) {
return h.uart.Read(buf)
}

const writeAttempts = 200

func (h *hciUART) Write(buf []byte) (int, error) {
Expand Down
2 changes: 1 addition & 1 deletion att_hci.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build hci || ninafw
//go:build hci || ninafw || cyw43439

package bluetooth

Expand Down
2 changes: 1 addition & 1 deletion gap_hci.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build hci || ninafw
//go:build hci || ninafw || cyw43439

package bluetooth

Expand Down
2 changes: 1 addition & 1 deletion gattc_hci.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build hci || ninafw
//go:build hci || ninafw || cyw43439

package bluetooth

Expand Down
2 changes: 1 addition & 1 deletion gatts_hci.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build hci || ninafw
//go:build hci || ninafw || cyw43439

package bluetooth

Expand Down
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
module tinygo.org/x/bluetooth

go 1.18
go 1.20

require (
github.com/go-ole/go-ole v1.2.6
github.com/godbus/dbus/v5 v5.1.0
github.com/saltosystems/winrt-go v0.0.0-20240509164145-4f7860a3bd2b
github.com/soypat/cyw43439 v0.0.0-20240521202811-13f2f2d46d64
github.com/tinygo-org/cbgo v0.0.4
golang.org/x/crypto v0.12.0
tinygo.org/x/drivers v0.26.1-0.20230922160320-ed51435c2ef6
Expand All @@ -16,6 +17,9 @@ require (
require (
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/soypat/seqs v0.0.0-20240509190925-a6350cee83a7 // indirect
github.com/tinygo-org/pio v0.0.0-20231216154340-cd888eb58899 // indirect
golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/term v0.11.0 // indirect
)
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,22 @@ github.com/saltosystems/winrt-go v0.0.0-20240509164145-4f7860a3bd2b/go.mod h1:CI
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/soypat/cyw43439 v0.0.0-20240521202811-13f2f2d46d64 h1:dNmjx0DMk6H1RdVhmfQudggSDjlayX0G0fOC8SxfAW8=
github.com/soypat/cyw43439 v0.0.0-20240521202811-13f2f2d46d64/go.mod h1:2c95aUfGi2f0oDceIIeozc8ZtVz4NJiZMwkyEGv6q/Y=
github.com/soypat/seqs v0.0.0-20240509190925-a6350cee83a7 h1:0AQR/zVYjgF5TPrjc/bfDdydWApSUyUgbM08kbm+FdQ=
github.com/soypat/seqs v0.0.0-20240509190925-a6350cee83a7/go.mod h1:oCVCNGCHMKoBj97Zp9znLbQ1nHxpkmOY9X+UAGzOxc8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
github.com/tinygo-org/cbgo v0.0.4 h1:3D76CRYbH03Rudi8sEgs/YO0x3JIMdyq8jlQtk/44fU=
github.com/tinygo-org/cbgo v0.0.4/go.mod h1:7+HgWIHd4nbAz0ESjGlJ1/v9LDU1Ox8MGzP9mah/fLk=
github.com/tinygo-org/pio v0.0.0-20231216154340-cd888eb58899 h1:/DyaXDEWMqoVUVEJVJIlNk1bXTbFs8s3Q4GdPInSKTQ=
github.com/tinygo-org/pio v0.0.0-20231216154340-cd888eb58899/go.mod h1:LU7Dw00NJ+N86QkeTGjMLNkYcEYMor6wTDpTCu0EaH8=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 h1:/yRP+0AN7mf5DkD3BAI6TOFnd51gEoDEb8o35jIFtgw=
golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
55 changes: 43 additions & 12 deletions hci.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build ninafw || hci
//go:build ninafw || hci || cyw43439

package bluetooth

Expand Down Expand Up @@ -66,10 +66,11 @@ const (
leMetaEventEnhancedConnectionComplete = 0x0A
leMetaEventDirectAdvertisingReport = 0x0B

hciCommandPkt = 0x01
hciACLDataPkt = 0x02
hciEventPkt = 0x04
hciSecurityPkt = 0x06
hciCommandPkt = 0x01
hciACLDataPkt = 0x02
hciSynchronousDataPkt = 0x03
hciEventPkt = 0x04
hciSecurityPkt = 0x06

evtDisconnComplete = 0x05
evtEncryptionChange = 0x08
Expand Down Expand Up @@ -126,6 +127,7 @@ type hciTransport interface {
endRead()
Buffered() int
ReadByte() (byte, error)
Read(buf []byte) (int, error)
Write(buf []byte) (int, error)
}

Expand Down Expand Up @@ -156,8 +158,19 @@ func (h *hci) start() error {
h.transport.startRead()
defer h.transport.endRead()

for h.transport.Buffered() > 0 {
h.transport.ReadByte()
var data [32]byte
for {
if i := h.transport.Buffered(); i > 0 {
if i > len(data) {
i = len(data)
}
if _, err := h.transport.Read(data[:i]); err != nil {
return err
}

continue
}
return nil
}

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

i := 0
for h.transport.Buffered() > 0 {
data, _ := h.transport.ReadByte()
h.buf[i] = data
sz := h.transport.Buffered()
c := sz + 4 - (sz % 4)
_, err := h.transport.Read(h.buf[i : i+c])
if err != nil {
return err
}
i += sz

done, err := h.processPacket(i)
switch {
case err == ErrHCIUnknown || err == ErrHCIInvalidPacket || err == ErrHCIUnknownEvent:
if debug {
println("hci error:", err.Error())
println("hci error:", err.Error(), hex.EncodeToString(h.buf[:i]))
}
i = 0
time.Sleep(5 * time.Millisecond)
Expand All @@ -199,7 +217,6 @@ func (h *hci) poll() error {
i = 0
time.Sleep(5 * time.Millisecond)
default:
i++
time.Sleep(1 * time.Millisecond)
}
}
Expand Down Expand Up @@ -238,9 +255,19 @@ func (h *hci) processPacket(i int) (bool, error) {
}
}

case hciSynchronousDataPkt:
// not supported by BLE, so ignore
if i > 3 {
pktlen := int(h.buf[3])
if debug {
println("hci synchronous data:", i, pktlen, hex.EncodeToString(h.buf[:1+3+pktlen]))
}
return true, nil
}

default:
if debug {
println("unknown packet data:", h.buf[0])
println("unknown packet data:", hex.EncodeToString(h.buf[0:i]))
}
return true, ErrHCIUnknown
}
Expand Down Expand Up @@ -725,6 +752,10 @@ func (h *hci) handleEventData(buf []byte) error {
return ErrHCIUnknownEvent
}
case evtHardwareError:
if debug {
println("evtHardwareError", hex.EncodeToString(buf))
}

return ErrHCIUnknownEvent
}

Expand Down
2 changes: 1 addition & 1 deletion l2cap_hci.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build ninafw || hci
//go:build ninafw || hci || cyw43439

package bluetooth

Expand Down
2 changes: 1 addition & 1 deletion uuid_hci.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build hci || ninafw
//go:build hci || ninafw || cyw43439

package bluetooth

Expand Down

0 comments on commit 457af75

Please sign in to comment.