diff --git a/adapter.go b/adapter.go index a5e6012..ecd07b9 100644 --- a/adapter.go +++ b/adapter.go @@ -2,3 +2,10 @@ package bluetooth // Set this to true to print debug messages, for example for unknown events. const debug = false + +// SetConnectHandler sets a handler function to be called whenever the adaptor connects +// or disconnects. You must call this before you call adaptor.Connect() for centrals +// or adaptor.Start() for peripherals in order for it to work. +func (a *Adapter) SetConnectHandler(c func(device Addresser, connected bool)) { + a.connectHandler = c +} diff --git a/adapter_darwin.go b/adapter_darwin.go index a19ce03..06bd3f0 100644 --- a/adapter_darwin.go +++ b/adapter_darwin.go @@ -19,6 +19,8 @@ type Adapter struct { scanChan chan error poweredChan chan error connectChan chan cbgo.Peripheral + + connectHandler func(device Addresser, connected bool) } // DefaultAdapter is the default adapter on the system. @@ -28,6 +30,9 @@ var DefaultAdapter = &Adapter{ cm: cbgo.NewCentralManager(nil), pm: cbgo.NewPeripheralManager(nil), connectChan: make(chan cbgo.Peripheral), + connectHandler: func(device Addresser, connected bool) { + return + }, } // Enable configures the BLE stack. It must be called before any diff --git a/adapter_linux.go b/adapter_linux.go index e5136c3..15aa354 100644 --- a/adapter_linux.go +++ b/adapter_linux.go @@ -15,13 +15,19 @@ type Adapter struct { id string cancelChan chan struct{} defaultAdvertisement *Advertisement + + connectHandler func(device Addresser, connected bool) } // DefaultAdapter is the default adapter on the system. On Linux, it is the // first adapter available. // // Make sure to call Enable() before using it to initialize the adapter. -var DefaultAdapter = &Adapter{} +var DefaultAdapter = &Adapter{ + connectHandler: func(device Addresser, connected bool) { + return + }, +} // Enable configures the BLE stack. It must be called before any // Bluetooth-related calls (unless otherwise indicated). diff --git a/adapter_nrf51.go b/adapter_nrf51.go index 1fa02fb..58b665d 100644 --- a/adapter_nrf51.go +++ b/adapter_nrf51.go @@ -47,6 +47,7 @@ func handleEvent() { switch id { case C.BLE_GAP_EVT_CONNECTED: currentConnection.Reg = gapEvent.conn_handle + DefaultAdapter.connectHandler(nil, true) case C.BLE_GAP_EVT_DISCONNECTED: if defaultAdvertisement.isAdvertising.Get() != 0 { // The advertisement was running but was automatically stopped @@ -58,6 +59,7 @@ func handleEvent() { defaultAdvertisement.start() } currentConnection.Reg = C.BLE_CONN_HANDLE_INVALID + DefaultAdapter.connectHandler(nil, false) case C.BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: // Respond with the default PPCP connection parameters by passing // nil: diff --git a/adapter_nrf528xx.go b/adapter_nrf528xx.go index edbbfd9..5ff341e 100644 --- a/adapter_nrf528xx.go +++ b/adapter_nrf528xx.go @@ -64,12 +64,14 @@ func handleEvent() { println("evt: connected in peripheral role") } currentConnection.Reg = gapEvent.conn_handle + DefaultAdapter.connectHandler(nil, true) case C.BLE_GAP_ROLE_CENTRAL: if debug { println("evt: connected in central role") } connectionAttempt.connectionHandle = gapEvent.conn_handle connectionAttempt.state.Set(2) // connection was successful + DefaultAdapter.connectHandler(nil, true) } case C.BLE_GAP_EVT_DISCONNECTED: if debug { @@ -92,6 +94,7 @@ func handleEvent() { // necessary. C.sd_ble_gap_adv_start(defaultAdvertisement.handle, C.BLE_CONN_CFG_TAG_DEFAULT) } + DefaultAdapter.connectHandler(nil, false) case C.BLE_GAP_EVT_ADV_REPORT: advReport := gapEvent.params.unionfield_adv_report() if debug && &scanReportBuffer.data[0] != advReport.data.p_data { diff --git a/adapter_sd.go b/adapter_sd.go index fda0d0d..338af8e 100644 --- a/adapter_sd.go +++ b/adapter_sd.go @@ -39,13 +39,18 @@ type Adapter struct { isDefault bool scanning bool charWriteHandlers []charWriteHandler + + connectHandler func(device Addresser, connected bool) } // DefaultAdapter is the default adapter on the current system. On Nordic chips, // it will return the SoftDevice interface. // // Make sure to call Enable() before using it to initialize the adapter. -var DefaultAdapter = &Adapter{isDefault: true} +var DefaultAdapter = &Adapter{isDefault: true, + connectHandler: func(device Addresser, connected bool) { + return + }} // Enable configures the BLE stack. It must be called before any // Bluetooth-related calls (unless otherwise indicated). diff --git a/adapter_windows.go b/adapter_windows.go index 3f74375..685fa11 100644 --- a/adapter_windows.go +++ b/adapter_windows.go @@ -7,12 +7,18 @@ import ( type Adapter struct { watcher *winbt.IBluetoothLEAdvertisementWatcher + + connectHandler func(device Addresser, connected bool) } // DefaultAdapter is the default adapter on the system. // // Make sure to call Enable() before using it to initialize the adapter. -var DefaultAdapter = &Adapter{} +var DefaultAdapter = &Adapter{ + connectHandler: func(device Addresser, connected bool) { + return + }, +} // Enable configures the BLE stack. It must be called before any // Bluetooth-related calls (unless otherwise indicated). diff --git a/examples/circuitplay/main.go b/examples/circuitplay/main.go index 0e73587..234cb24 100644 --- a/examples/circuitplay/main.go +++ b/examples/circuitplay/main.go @@ -26,13 +26,31 @@ var ( var neo machine.Pin = machine.NEOPIXELS var led machine.Pin = machine.LED +var ws ws2812.Device +var rg bool + +var connected bool +var disconnected bool = true func main() { println("starting") led.Configure(machine.PinConfig{Mode: machine.PinOutput}) neo.Configure(machine.PinConfig{Mode: machine.PinOutput}) - ws := ws2812.New(neo) + ws = ws2812.New(neo) + + adapter.SetConnectHandler(func(d bluetooth.Addresser, c bool) { + connected = c + + if !connected && !disconnected { + clearLEDS() + disconnected = true + } + + if connected { + disconnected = false + } + }) must("enable BLE stack", adapter.Enable()) adv := adapter.DefaultAdvertisement() @@ -62,20 +80,11 @@ func main() { }, })) - rg := false - for { rg = !rg - for i := range leds { - rg = !rg - if rg { - leds[i] = color.RGBA{R: ledColor[0], G: ledColor[1], B: ledColor[2]} - } else { - leds[i] = color.RGBA{R: 0x00, G: 0x00, B: 0x00} - } + if connected { + writeLEDS() } - - ws.WriteColors(leds[:]) led.Set(rg) time.Sleep(100 * time.Millisecond) } @@ -86,3 +95,24 @@ func must(action string, err error) { panic("failed to " + action + ": " + err.Error()) } } + +func writeLEDS() { + for i := range leds { + rg = !rg + if rg { + leds[i] = color.RGBA{R: ledColor[0], G: ledColor[1], B: ledColor[2]} + } else { + leds[i] = color.RGBA{R: 0x00, G: 0x00, B: 0x00} + } + } + + ws.WriteColors(leds[:]) +} + +func clearLEDS() { + for i := range leds { + leds[i] = color.RGBA{R: 0x00, G: 0x00, B: 0x00} + } + + ws.WriteColors(leds[:]) +} diff --git a/gap_darwin.go b/gap_darwin.go index 46413c9..abecec0 100644 --- a/gap_darwin.go +++ b/gap_darwin.go @@ -116,6 +116,8 @@ func (a *Adapter) Connect(address Addresser, params ConnectionParams) (*Device, d.delegate = &peripheralDelegate{d: d} p.SetDelegate(d.delegate) + a.connectHandler(nil, true) + return d, nil case <-time.NewTimer(10 * time.Second).C: return nil, errors.New("timeout on Connect") diff --git a/gap_linux.go b/gap_linux.go index 78c4eba..2ec326e 100644 --- a/gap_linux.go +++ b/gap_linux.go @@ -259,6 +259,9 @@ func (a *Adapter) Connect(address Addresser, params ConnectionParams) (*Device, } } + // TODO: a proper async callback. + a.connectHandler(nil, true) + return &Device{ device: dev, }, nil