bluetooth/gattc_linux.go

308 lines
9 KiB
Go
Raw Normal View History

//go:build !baremetal
2020-06-28 01:14:25 +03:00
package bluetooth
import (
"errors"
"sort"
2020-06-28 01:14:25 +03:00
"strings"
"time"
"github.com/godbus/dbus/v5"
2020-06-28 01:14:25 +03:00
)
var (
errDupNotif = errors.New("unclosed notifications")
)
// UUIDWrapper is a type alias for UUID so we ensure no conflicts with
// struct method of the same name.
type uuidWrapper = UUID
2020-06-28 01:14:25 +03:00
// DeviceService is a BLE service on a connected peripheral device.
type DeviceService struct {
uuidWrapper
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
adapter *Adapter
servicePath string
2020-06-28 01:14:25 +03:00
}
// UUID returns the UUID for this DeviceService.
func (s DeviceService) UUID() UUID {
return s.uuidWrapper
}
2020-06-28 01:14:25 +03:00
// DiscoverServices starts a service discovery procedure. Pass a list of service
// UUIDs you are interested in to this function. Either a slice of all services
// is returned (of the same length as the requested UUIDs and in the same
// order), or if some services could not be discovered an error is returned.
//
// Passing a nil slice of UUIDs will return a complete list of
2020-06-28 01:14:25 +03:00
// services.
//
// On Linux with BlueZ, this just waits for the ServicesResolved signal (if
// services haven't been resolved yet) and uses this list of cached services.
func (d Device) DiscoverServices(uuids []UUID) ([]DeviceService, error) {
start := time.Now()
2020-06-28 01:14:25 +03:00
for {
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
resolved, err := d.device.GetProperty("org.bluez.Device1.ServicesResolved")
2020-06-28 01:14:25 +03:00
if err != nil {
return nil, err
}
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
if resolved.Value().(bool) {
2020-06-28 01:14:25 +03:00
break
}
// This is a terrible hack, but I couldn't find another way.
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
// TODO: actually there is, by waiting for a property change event of
// ServicesResolved.
2020-06-28 01:14:25 +03:00
time.Sleep(10 * time.Millisecond)
if time.Since(start) > 10*time.Second {
return nil, errors.New("timeout on DiscoverServices")
}
2020-06-28 01:14:25 +03:00
}
services := []DeviceService{}
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
uuidServices := make(map[UUID]struct{})
2020-06-28 01:14:25 +03:00
servicesFound := 0
// Iterate through all objects managed by BlueZ, hoping to find the services
// we're looking for.
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
var list map[dbus.ObjectPath]map[string]map[string]dbus.Variant
err := d.adapter.bluez.Call("org.freedesktop.DBus.ObjectManager.GetManagedObjects", 0).Store(&list)
2020-06-28 01:14:25 +03:00
if err != nil {
return nil, err
}
objects := make([]string, 0, len(list))
2020-06-28 01:14:25 +03:00
for objectPath := range list {
objects = append(objects, string(objectPath))
}
sort.Strings(objects)
for _, objectPath := range objects {
if !strings.HasPrefix(objectPath, string(d.device.Path())+"/service") {
2020-06-28 01:14:25 +03:00
continue
}
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
properties, ok := list[dbus.ObjectPath(objectPath)]["org.bluez.GattService1"]
if !ok {
2020-06-28 01:14:25 +03:00
continue
}
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
serviceUUID, _ := ParseUUID(properties["UUID"].Value().(string))
if len(uuids) > 0 {
found := false
for _, uuid := range uuids {
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
if uuid == serviceUUID {
// One of the services we're looking for.
found = true
break
}
2020-06-28 01:14:25 +03:00
}
if !found {
2020-06-28 01:14:25 +03:00
continue
}
}
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
if _, ok := uuidServices[serviceUUID]; ok {
// There is more than one service with the same UUID?
// Don't overwrite it, to keep the servicesFound count correct.
continue
}
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
ds := DeviceService{
uuidWrapper: serviceUUID,
adapter: d.adapter,
servicePath: objectPath,
}
services = append(services, ds)
servicesFound++
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
uuidServices[serviceUUID] = struct{}{}
2020-06-28 01:14:25 +03:00
}
if servicesFound < len(uuids) {
2020-06-28 01:14:25 +03:00
return nil, errors.New("bluetooth: could not find some services")
}
return services, nil
}
// DeviceCharacteristic is a BLE characteristic on a connected peripheral
// device.
type DeviceCharacteristic struct {
uuidWrapper
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
adapter *Adapter
characteristic dbus.BusObject
property chan *dbus.Signal // channel where notifications are reported
propertiesChangedMatchOption dbus.MatchOption // the same value must be passed to RemoveMatchSignal
2020-06-28 01:14:25 +03:00
}
// UUID returns the UUID for this DeviceCharacteristic.
func (c DeviceCharacteristic) UUID() UUID {
return c.uuidWrapper
}
2020-06-28 01:14:25 +03:00
// DiscoverCharacteristics discovers characteristics in this service. Pass a
// list of characteristic UUIDs you are interested in to this function. Either a
// list of all requested services is returned, or if some services could not be
// discovered an error is returned. If there is no error, the characteristics
// slice has the same length as the UUID slice with characteristics in the same
// order in the slice as in the requested UUID list.
//
// Passing a nil slice of UUIDs will return a complete
2020-06-28 01:14:25 +03:00
// list of characteristics.
func (s DeviceService) DiscoverCharacteristics(uuids []UUID) ([]DeviceCharacteristic, error) {
var chars []DeviceCharacteristic
if len(uuids) > 0 {
// The caller wants to get a list of characteristics in a specific
// order.
chars = make([]DeviceCharacteristic, len(uuids))
}
2020-06-28 01:14:25 +03:00
// Iterate through all objects managed by BlueZ, hoping to find the
// characteristic we're looking for.
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
var list map[dbus.ObjectPath]map[string]map[string]dbus.Variant
err := s.adapter.bluez.Call("org.freedesktop.DBus.ObjectManager.GetManagedObjects", 0).Store(&list)
2020-06-28 01:14:25 +03:00
if err != nil {
return nil, err
}
objects := make([]string, 0, len(list))
2020-06-28 01:14:25 +03:00
for objectPath := range list {
objects = append(objects, string(objectPath))
}
sort.Strings(objects)
for _, objectPath := range objects {
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
if !strings.HasPrefix(objectPath, s.servicePath+"/char") {
2020-06-28 01:14:25 +03:00
continue
}
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
properties, ok := list[dbus.ObjectPath(objectPath)]["org.bluez.GattCharacteristic1"]
if !ok {
2020-06-28 01:14:25 +03:00
continue
}
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
cuuid, _ := ParseUUID(properties["UUID"].Value().(string))
char := DeviceCharacteristic{
uuidWrapper: cuuid,
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
adapter: s.adapter,
characteristic: s.adapter.bus.Object("org.bluez", dbus.ObjectPath(objectPath)),
}
if len(uuids) > 0 {
// The caller wants to get a list of characteristics in a specific
// order. Check whether this is one of those.
for i, uuid := range uuids {
if chars[i] != (DeviceCharacteristic{}) {
// To support multiple identical characteristics, we need to
// ignore the characteristics that are already found. See:
// https://github.com/tinygo-org/bluetooth/issues/131
continue
}
if cuuid == uuid {
// one of the characteristics we're looking for.
chars[i] = char
break
}
2020-06-28 01:14:25 +03:00
}
} else {
// The caller wants to get all characteristics, in any order.
chars = append(chars, char)
}
2020-06-28 01:14:25 +03:00
}
// Check that we have found all characteristics.
for _, char := range chars {
if char == (DeviceCharacteristic{}) {
return nil, errors.New("bluetooth: could not find some characteristics")
}
2020-06-28 01:14:25 +03:00
}
return chars, nil
}
// WriteWithoutResponse replaces the characteristic value with a new value. The
// call will return before all data has been written. A limited number of such
// writes can be in flight at any given time. This call is also known as a
// "write command" (as opposed to a write request).
func (c DeviceCharacteristic) WriteWithoutResponse(p []byte) (n int, err error) {
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
err = c.characteristic.Call("org.bluez.GattCharacteristic1.WriteValue", 0, p, map[string]dbus.Variant(nil)).Err
2020-06-28 01:14:25 +03:00
if err != nil {
return 0, err
}
return len(p), nil
}
// EnableNotifications enables notifications in the Client Characteristic
// Configuration Descriptor (CCCD). This means that most peripherals will send a
// notification with a new value every time the value of the characteristic
// changes.
//
// Users may call EnableNotifications with a nil callback to disable notifications.
func (c DeviceCharacteristic) EnableNotifications(callback func(buf []byte)) error {
switch callback {
default:
if c.property != nil {
return errDupNotif
}
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
// Start watching for changes in the Value property.
c.property = make(chan *dbus.Signal)
c.adapter.bus.Signal(c.property)
c.propertiesChangedMatchOption = dbus.WithMatchInterface("org.freedesktop.DBus.Properties")
c.adapter.bus.AddMatchSignal(c.propertiesChangedMatchOption)
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
err := c.characteristic.Call("org.bluez.GattCharacteristic1.StartNotify", 0).Err
if err != nil {
return err
}
go func() {
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
for sig := range c.property {
if sig.Name == "org.freedesktop.DBus.Properties.PropertiesChanged" {
interfaceName := sig.Body[0].(string)
if interfaceName != "org.bluez.GattCharacteristic1" {
continue
}
if sig.Path != c.characteristic.Path() {
continue
}
changes := sig.Body[1].(map[string]dbus.Variant)
if value, ok := changes["Value"].Value().([]byte); ok {
callback(value)
}
}
2020-06-28 01:14:25 +03:00
}
}()
return nil
case nil:
if c.property == nil {
return nil
}
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
err := c.adapter.bus.RemoveMatchSignal(c.propertiesChangedMatchOption)
c.adapter.bus.RemoveSignal(c.property)
c.property = nil
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
return err
}
2020-06-28 01:14:25 +03:00
}
// GetMTU returns the MTU for the characteristic.
func (c DeviceCharacteristic) GetMTU() (uint16, error) {
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
mtu, err := c.characteristic.GetProperty("org.bluez.GattCharacteristic1.MTU")
if err != nil {
return uint16(0), err
}
return mtu.Value().(uint16), nil
}
// Read reads the current characteristic value.
func (c DeviceCharacteristic) Read(data []byte) (int, error) {
options := make(map[string]interface{})
linux: rewrite everything to use DBus directly This is a big rewrite to use DBus calls directly instead of going through go-bluetooth first. This is a big change, but I believe it is an improvement. While the go-bluetooth works for many cases, it's a layer in between that I believe hurts more than it helps. Without it, we can just program directly against the BlueZ D-Bus API. The end result is about 10% more code. With this rewrite, I fixed the following issues: * All MapToStruct warnings are gone, like in https://github.com/tinygo-org/bluetooth/issues/193. * Advertisements can be restarted after they were stopped. Previously this resulted in a panic. * Looking at the source code of go-bluetooth, it appears that it includes devices from a different Bluetooth adapter than the one that's currently scanning. This is fixed with the rewrite. * Fix a bug in Adapter.AddService where it would only allow adding a single service. Multiple services can now be added. This was actually the motivating bug that led me down to rewrite the whole thing because I couldn't figure out where the bug was in go-bluetooth (it's many layers deep). * The `WriteEvent` callback in a characteristic now also gets the 'offset' parameter which wasn't provided by go-bluetooth. This rewrite also avoids go-bluetooth specific workarounds like https://github.com/tinygo-org/bluetooth/pull/74 and https://github.com/tinygo-org/bluetooth/pull/121. I have tested all examples in the smoketest-linux Makefile target. They all still work with this rewrite.
2024-01-02 14:51:05 +03:00
var result []byte
err := c.characteristic.Call("org.bluez.GattCharacteristic1.ReadValue", 0, options).Store(&result)
if err != nil {
return 0, err
}
copy(data, result)
return len(result), nil
}