cyw43439: HCI implementation
Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
parent
9905abd00e
commit
457af7571a
14 changed files with 201 additions and 21 deletions
4
Makefile
4
Makefile
|
@ -44,6 +44,10 @@ smoketest-tinygo:
|
||||||
@md5sum test.hex
|
@md5sum test.hex
|
||||||
$(TINYGO) build -o test.uf2 -size=short -target=circuitplay-express -tags="hci hci_uart" ./examples/advertisement
|
$(TINYGO) build -o test.uf2 -size=short -target=circuitplay-express -tags="hci hci_uart" ./examples/advertisement
|
||||||
@md5sum test.hex
|
@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:
|
smoketest-linux:
|
||||||
# Test on Linux.
|
# Test on Linux.
|
||||||
|
|
116
adapter_cyw43439.go
Normal file
116
adapter_cyw43439.go
Normal file
|
@ -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)
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build hci || ninafw
|
//go:build hci || ninafw || cyw43439
|
||||||
|
|
||||||
package bluetooth
|
package bluetooth
|
||||||
|
|
||||||
|
@ -25,9 +25,18 @@ type hciAdapter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *hciAdapter) enable() error {
|
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 err := a.hci.reset(); err != nil {
|
||||||
|
if debug {
|
||||||
|
println("error resetting HCI:", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,10 @@ func (h *hciUART) ReadByte() (byte, error) {
|
||||||
return h.uart.ReadByte()
|
return h.uart.ReadByte()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *hciUART) Read(buf []byte) (int, error) {
|
||||||
|
return h.uart.Read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
const writeAttempts = 200
|
const writeAttempts = 200
|
||||||
|
|
||||||
func (h *hciUART) Write(buf []byte) (int, error) {
|
func (h *hciUART) Write(buf []byte) (int, error) {
|
||||||
|
|
|
@ -108,6 +108,10 @@ func (h *hciUART) ReadByte() (byte, error) {
|
||||||
return h.uart.ReadByte()
|
return h.uart.ReadByte()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *hciUART) Read(buf []byte) (int, error) {
|
||||||
|
return h.uart.Read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
const writeAttempts = 200
|
const writeAttempts = 200
|
||||||
|
|
||||||
func (h *hciUART) Write(buf []byte) (int, error) {
|
func (h *hciUART) Write(buf []byte) (int, error) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build hci || ninafw
|
//go:build hci || ninafw || cyw43439
|
||||||
|
|
||||||
package bluetooth
|
package bluetooth
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build hci || ninafw
|
//go:build hci || ninafw || cyw43439
|
||||||
|
|
||||||
package bluetooth
|
package bluetooth
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build hci || ninafw
|
//go:build hci || ninafw || cyw43439
|
||||||
|
|
||||||
package bluetooth
|
package bluetooth
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build hci || ninafw
|
//go:build hci || ninafw || cyw43439
|
||||||
|
|
||||||
package bluetooth
|
package bluetooth
|
||||||
|
|
||||||
|
|
6
go.mod
6
go.mod
|
@ -1,11 +1,12 @@
|
||||||
module tinygo.org/x/bluetooth
|
module tinygo.org/x/bluetooth
|
||||||
|
|
||||||
go 1.18
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-ole/go-ole v1.2.6
|
github.com/go-ole/go-ole v1.2.6
|
||||||
github.com/godbus/dbus/v5 v5.1.0
|
github.com/godbus/dbus/v5 v5.1.0
|
||||||
github.com/saltosystems/winrt-go v0.0.0-20240509164145-4f7860a3bd2b
|
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
|
github.com/tinygo-org/cbgo v0.0.4
|
||||||
golang.org/x/crypto v0.12.0
|
golang.org/x/crypto v0.12.0
|
||||||
tinygo.org/x/drivers v0.26.1-0.20230922160320-ed51435c2ef6
|
tinygo.org/x/drivers v0.26.1-0.20230922160320-ed51435c2ef6
|
||||||
|
@ -16,6 +17,9 @@ require (
|
||||||
require (
|
require (
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // 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/sys v0.11.0 // indirect
|
||||||
golang.org/x/term v0.11.0 // indirect
|
golang.org/x/term v0.11.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -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.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 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
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/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.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.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
|
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 h1:3D76CRYbH03Rudi8sEgs/YO0x3JIMdyq8jlQtk/44fU=
|
||||||
github.com/tinygo-org/cbgo v0.0.4/go.mod h1:7+HgWIHd4nbAz0ESjGlJ1/v9LDU1Ox8MGzP9mah/fLk=
|
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 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
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-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-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|
47
hci.go
47
hci.go
|
@ -1,4 +1,4 @@
|
||||||
//go:build ninafw || hci
|
//go:build ninafw || hci || cyw43439
|
||||||
|
|
||||||
package bluetooth
|
package bluetooth
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@ const (
|
||||||
|
|
||||||
hciCommandPkt = 0x01
|
hciCommandPkt = 0x01
|
||||||
hciACLDataPkt = 0x02
|
hciACLDataPkt = 0x02
|
||||||
|
hciSynchronousDataPkt = 0x03
|
||||||
hciEventPkt = 0x04
|
hciEventPkt = 0x04
|
||||||
hciSecurityPkt = 0x06
|
hciSecurityPkt = 0x06
|
||||||
|
|
||||||
|
@ -126,6 +127,7 @@ type hciTransport interface {
|
||||||
endRead()
|
endRead()
|
||||||
Buffered() int
|
Buffered() int
|
||||||
ReadByte() (byte, error)
|
ReadByte() (byte, error)
|
||||||
|
Read(buf []byte) (int, error)
|
||||||
Write(buf []byte) (int, error)
|
Write(buf []byte) (int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,8 +158,19 @@ func (h *hci) start() error {
|
||||||
h.transport.startRead()
|
h.transport.startRead()
|
||||||
defer h.transport.endRead()
|
defer h.transport.endRead()
|
||||||
|
|
||||||
for h.transport.Buffered() > 0 {
|
var data [32]byte
|
||||||
h.transport.ReadByte()
|
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
|
return nil
|
||||||
|
@ -177,14 +190,19 @@ func (h *hci) poll() error {
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
for h.transport.Buffered() > 0 {
|
for h.transport.Buffered() > 0 {
|
||||||
data, _ := h.transport.ReadByte()
|
sz := h.transport.Buffered()
|
||||||
h.buf[i] = data
|
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)
|
done, err := h.processPacket(i)
|
||||||
switch {
|
switch {
|
||||||
case err == ErrHCIUnknown || err == ErrHCIInvalidPacket || err == ErrHCIUnknownEvent:
|
case err == ErrHCIUnknown || err == ErrHCIInvalidPacket || err == ErrHCIUnknownEvent:
|
||||||
if debug {
|
if debug {
|
||||||
println("hci error:", err.Error())
|
println("hci error:", err.Error(), hex.EncodeToString(h.buf[:i]))
|
||||||
}
|
}
|
||||||
i = 0
|
i = 0
|
||||||
time.Sleep(5 * time.Millisecond)
|
time.Sleep(5 * time.Millisecond)
|
||||||
|
@ -199,7 +217,6 @@ func (h *hci) poll() error {
|
||||||
i = 0
|
i = 0
|
||||||
time.Sleep(5 * time.Millisecond)
|
time.Sleep(5 * time.Millisecond)
|
||||||
default:
|
default:
|
||||||
i++
|
|
||||||
time.Sleep(1 * time.Millisecond)
|
time.Sleep(1 * time.Millisecond)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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:
|
default:
|
||||||
if debug {
|
if debug {
|
||||||
println("unknown packet data:", h.buf[0])
|
println("unknown packet data:", hex.EncodeToString(h.buf[0:i]))
|
||||||
}
|
}
|
||||||
return true, ErrHCIUnknown
|
return true, ErrHCIUnknown
|
||||||
}
|
}
|
||||||
|
@ -725,6 +752,10 @@ func (h *hci) handleEventData(buf []byte) error {
|
||||||
return ErrHCIUnknownEvent
|
return ErrHCIUnknownEvent
|
||||||
}
|
}
|
||||||
case evtHardwareError:
|
case evtHardwareError:
|
||||||
|
if debug {
|
||||||
|
println("evtHardwareError", hex.EncodeToString(buf))
|
||||||
|
}
|
||||||
|
|
||||||
return ErrHCIUnknownEvent
|
return ErrHCIUnknownEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build ninafw || hci
|
//go:build ninafw || hci || cyw43439
|
||||||
|
|
||||||
package bluetooth
|
package bluetooth
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build hci || ninafw
|
//go:build hci || ninafw || cyw43439
|
||||||
|
|
||||||
package bluetooth
|
package bluetooth
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue