Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package bluetooth
type BLEAdapter interface {
Connect(address Address, params ConnectionParams) (Device, error)
Enable() error
Reset() error
Scan(callback func(*Adapter, ScanResult)) (err error)
SetConnectHandler(c func(device Device, connected bool))
StopScan() error
Expand Down
5 changes: 5 additions & 0 deletions adapter_cyw43439.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ func (a *Adapter) Enable() error {
return nil
}

// Reset is a no-op on CYW43439. Provided for interface symmetry.
func (a *Adapter) Reset() error {
return nil
}

type hciSPI struct {
dev *cyw43439.Device
}
Expand Down
49 changes: 43 additions & 6 deletions adapter_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,18 @@ var DefaultAdapter = &Adapter{

// Enable configures the BLE stack. It must be called before any
// Bluetooth-related calls (unless otherwise indicated).
//
// poweredChan is cleared on both success and timeout paths so
// a subsequent Enable() on the same Adapter can run again.
func (a *Adapter) Enable() error {
if a.poweredChan != nil {
return errors.New("already calling Enable function")
}

a.poweredChan = make(chan error, 1)

// Set the delegate before checking State so we don't miss an
// async DidUpdateState that fires between construction and now.
// Set delegate before checking state — a fresh CBCentralManager
// can fire DidUpdateState before SetDelegate, losing the event.
a.cmd = &centralManagerDelegate{a: a}
a.cm.SetDelegate(a.cmd)

Expand Down Expand Up @@ -82,6 +85,42 @@ func (a *Adapter) Enable() error {
return nil
}

// Reset tears down CoreBluetooth managers so a subsequent Enable()
// rebuilds them from scratch. Useful for recovering from stale
// CBPeripheral handles, adapter switching, and test cleanup.
//
// Caller must ensure no Scan/Connect/DiscoverServices is in flight.
// After Reset, call Enable() to create fresh managers.
//
// Note: process-level CoreBluetooth state (e.g. the advertisement
// deduplication table) survives Reset — only process exit clears it.
func (a *Adapter) Reset() error {
if a.scanChan != nil {
_ = a.StopScan()
}

// Unblock goroutines parked in Connect — closing the chan
// yields a zero Peripheral so Connect returns an error.
a.connectMap.Range(func(key, value any) bool {
a.connectMap.Delete(key)
if ch, ok := value.(chan cbgo.Peripheral); ok {
defer func() { _ = recover() }()
close(ch)
}
return true
})

a.cm = cbgo.NewCentralManager(nil)
a.pm = cbgo.NewPeripheralManager(nil)
a.cmd = nil
a.pmd = nil
a.poweredChan = nil
a.scanChan = nil
a.peripheralFoundHandler = nil

return nil
}

// CentralManager delegate functions

type centralManagerDelegate struct {
Expand All @@ -103,12 +142,10 @@ func (cmd *centralManagerDelegate) CentralManagerDidUpdateState(cmgr cbgo.Centra
case cbgo.ManagerStateUnauthorized:
event = errors.New("bluetooth is not authorized for this app")
default:
// Unknown / Resetting are intermediate; wait for the next update.
return
}
// Non-blocking; select handles a nil poweredChan correctly (the
// case is never ready, default fires) so a late or repeated
// update never parks the delegate goroutine.
// Non-blocking send: poweredChan may be nil after Enable
// completes, or already buffered.
select {
case cmd.a.poweredChan <- event:
default:
Expand Down
5 changes: 5 additions & 0 deletions adapter_hci_uart.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ func (a *Adapter) Enable() error {
return nil
}

// Reset is a no-op on HCI UART. Provided for interface symmetry.
func (a *Adapter) Reset() error {
return nil
}

type hciUART struct {
uart *machine.UART

Expand Down
11 changes: 11 additions & 0 deletions adapter_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ func (a *Adapter) Enable() (err error) {
return nil
}

// Reset clears BlueZ state so a subsequent Enable() rebuilds it.
// Mostly a no-op on Linux; provided for interface symmetry.
func (a *Adapter) Reset() error {
a.bus = nil
a.bluez = nil
a.adapter = nil
a.address = ""
a.scanCancelChan = nil
return nil
}

func (a *Adapter) Address() (MACAddress, error) {
if a.address == "" {
return MACAddress{}, errors.New("adapter not enabled")
Expand Down
5 changes: 5 additions & 0 deletions adapter_ninafw.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ func (a *Adapter) Enable() error {
return a.enable()
}

// Reset is a no-op on NINA. Provided for interface symmetry.
func (a *Adapter) Reset() error {
return nil
}

func resetNINA() {
machine.NINA_RESETN.Configure(machine.PinConfig{Mode: machine.PinOutput})

Expand Down
5 changes: 5 additions & 0 deletions adapter_sd.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ func (a *Adapter) Enable() error {
return makeError(errCode)
}

// Reset is a no-op on SoftDevice. Provided for interface symmetry.
func (a *Adapter) Reset() error {
return nil
}

// DisableInterrupts must be used instead of disabling interrupts directly, to
// play well with the SoftDevice. Restore interrupts to the previous state with
// RestoreInterrupts.
Expand Down
5 changes: 5 additions & 0 deletions adapter_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ func (a *Adapter) Enable() error {
return ole.RoInitialize(1) // initialize with multithreading enabled
}

// Reset is a no-op on Windows. Provided for interface symmetry.
func (a *Adapter) Reset() error {
return nil
}

func awaitAsyncOperation(asyncOperation *foundation.IAsyncOperation, genericParamSignature string) error {
var status foundation.AsyncStatus

Expand Down
Loading