tinygo-org / bluetooth

Cross-platform Bluetooth API for Go and TinyGo. Supports Linux, macOS, Windows, and bare metal using Nordic SoftDevice or HCI
https://tinygo.org
Other
701 stars 132 forks source link

Problem with SetConnectedHandler() on Linux (Raspbian) Peripheral Device #145

Open SVdvr opened 1 year ago

SVdvr commented 1 year ago

Hello,

I am using your lib to create/manage a peripheral BLE device on an RPI 4.

It already works quite well, I can advertise and read/write with services and characteristics I defined. However, I would need to run a function each time a a Central device connects/disconnects to my RPI. As I understood, the 'adapter.SetConnectHandler()' can be used for that, but it doesn't work for me. Did I miss something ? My code is very similar to this example : https://github.com/tinygo-org/bluetooth/blob/v0.6.0/examples/circuitplay/main.go

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()
    must("config adv", adv.Configure(bluetooth.AdvertisementOptions{
        LocalName: "TinyGo colors",
    }))
    must("start adv", adv.Start())

How do I (is it possible to ?) configure a handler that will be called each time a central device connects to my Linux (Raspbian) peripheral ?

Thank you !

TirelessDev commented 1 year ago

SetConnectedHandler() or more accurately adapter.connectHandler is called when the adaptor is acting as a central itself and a connection is established to a peripheral. It is not called on disconnect in Linux, MacOS, or Windows, only for the embedded nordic implementations. However, I am working on a PR that adds this to the MacOS and Linux implementations, you can find it in my fork if you are interested.

For your use case, you need to implement the callbacks for the peripheral services that you are implementing. I am not aware of a call to adapter.connectHandler for any peripheral connection events or a similar alternative. However, I have not used the peripheral side of this library so have likely missed something.

At the bottom of the go library abstractions, the BlueZ stack is used for the Linux implementation. You can find its docs here git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc. This is wrapped by github.com/muka/go-bluetooth which tinygo uses, so by looking through there you can see if the functionality you are looking for is possible and work backwards into the tinygo library to see if it is exposed, or how it may be implemented.

deadprogram commented 1 year ago

What @TirelessDev said! :smile_cat:

SVdvr commented 1 year ago

Hello, I used github.com/muka/go-bluetooth to monitor on DBus Property "Connected" (I guess that's what @TirelessDev did on his fork, but I saw it after I did it myself 😅) and I managed to do what I wanted ( call a function when a central device connects / disconnects to my peripheral )

I guess I will modify it later to do like @TirelessDev, as it seems much more elegant that what I did ( https://github.com/tinygo-org/bluetooth/pull/149/commits/80d9f9dca455c7750246e50cb2ccc9fdf97fcefe )

Anyway, thank you for your help, it works well !

TirelessDev commented 1 year ago

Nice, good to know that that property change is fired off when acting as a peripheral as well!

It might then be worth weaving the functionality into this library in the same way, though I am not sure if the same would be possible on MacOS and Windows. @SVdvr did you want to put a draft PR together with what you have working so that we can look at doing this?

deadprogram commented 1 year ago

Yes please!

SVdvr commented 1 year ago

Hello, sorry for the delay, I completely forgot to answer the last post... I can try to add this functionnality on TirelessDev's fork, but it will work only for Linux, as I only used https://github.com/muka/go-bluetooth .

I'll try to do it during the nex days/weeks, but I'll still tell you how it works, maybe someone will find a better idea. As a peripheral :

  1. When initializing, get all the bonded devices (there's a function for that in https://github.com/muka/go-bluetooth) and instanciate them
  2. For each device, use d.device.WatchProperties() to watch DBus's "Property Changed" channel (as TirelessDev did for central devices on is fork). With this, we can detect when a device connects/disconnects/pairs/bonds.
  3. Since we don't trigger a connection ourselves (unlike central devices), we also have to watch DBus's "InterfaceAdded" channel, so that we can instanciate a new device object when a central connects to our peripheral.