-
Notifications
You must be signed in to change notification settings - Fork 175
linux: allow Linux to DiscoverServices/DiscoverCharacteristics without a specific list #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
64ee33d
b415f18
221f101
337e68c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "os" | ||
|
|
||
| "github.com/tinygo-org/bluetooth" | ||
| ) | ||
|
|
||
| var adapter = bluetooth.DefaultAdapter | ||
|
|
||
| func main() { | ||
| if len(os.Args) < 2 { | ||
| println("usage: discover [local name]") | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| // look for device with specific name | ||
| name := os.Args[1] | ||
|
|
||
| // Enable BLE interface. | ||
| must("enable BLE stack", adapter.Enable()) | ||
|
|
||
| ch := make(chan bluetooth.ScanResult, 1) | ||
|
|
||
| // Start scanning. | ||
| println("scanning...") | ||
| err := adapter.Scan(func(adapter *bluetooth.Adapter, result bluetooth.ScanResult) { | ||
| println("found device:", result.Address.String(), result.RSSI, result.LocalName()) | ||
| if result.LocalName() == name { | ||
| adapter.StopScan() | ||
| ch <- result | ||
| } | ||
| }) | ||
|
|
||
| var device *bluetooth.Device | ||
| select { | ||
| case result := <-ch: | ||
| device, err = adapter.Connect(result.Address, bluetooth.ConnectionParams{}) | ||
| if err != nil { | ||
| println(err.Error()) | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| println("connected to ", result.LocalName()) | ||
| } | ||
|
|
||
| // get services | ||
| println("discovering services/characteristics") | ||
| srvcs, err := device.DiscoverServices(nil) | ||
| for _, srvc := range srvcs { | ||
| println("- service", srvc.UUID.String()) | ||
|
|
||
| chars, _ := srvc.DiscoverCharacteristics(nil) | ||
| for _, char := range chars { | ||
| println("-- characteristic", char.UUID.String()) | ||
| } | ||
| } | ||
|
|
||
| must("start scan", err) | ||
| } | ||
|
|
||
| func must(action string, err error) { | ||
| if err != nil { | ||
| panic("failed to " + action + ": " + err.Error()) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,8 @@ import ( | |
|
|
||
| // DeviceService is a BLE service on a connected peripheral device. | ||
| type DeviceService struct { | ||
| UUID | ||
|
|
||
| service *gatt.GattService1 | ||
| } | ||
|
|
||
|
|
@@ -21,8 +23,7 @@ type DeviceService struct { | |
| // 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 currently result in zero services being | ||
| // returned, but this may be changed in the future to return a complete list of | ||
| // Passing a nil slice of UUIDs will return a complete list of | ||
| // services. | ||
| // | ||
| // On Linux with BlueZ, this just waits for the ServicesResolved signal (if | ||
|
|
@@ -40,7 +41,8 @@ func (d *Device) DiscoverServices(uuids []UUID) ([]DeviceService, error) { | |
| time.Sleep(10 * time.Millisecond) | ||
| } | ||
|
|
||
| services := make([]DeviceService, len(uuids)) | ||
| services := []DeviceService{} | ||
| uuidServices := make(map[string]string) | ||
| servicesFound := 0 | ||
|
|
||
| // Iterate through all objects managed by BlueZ, hoping to find the services | ||
|
|
@@ -65,23 +67,38 @@ func (d *Device) DiscoverServices(uuids []UUID) ([]DeviceService, error) { | |
| if err != nil { | ||
| return nil, err | ||
| } | ||
| for i, uuid := range uuids { | ||
| if service.Properties.UUID != uuid.String() { | ||
| // Not one of the services we're looking for. | ||
| continue | ||
|
|
||
| if len(uuids) > 0 { | ||
| found := false | ||
| for _, uuid := range uuids { | ||
| if service.Properties.UUID == uuid.String() { | ||
| // One of the services we're looking for. | ||
| found = true | ||
| break | ||
| } | ||
| } | ||
| if services[i].service != nil { | ||
| // There is more than one service with the same UUID? | ||
| // Don't overwrite it, to keep the servicesFound count correct. | ||
| if !found { | ||
| continue | ||
| } | ||
| services[i].service = service | ||
| servicesFound++ | ||
| break | ||
| } | ||
|
|
||
| if _, ok := uuidServices[service.Properties.UUID]; ok { | ||
| // There is more than one service with the same UUID? | ||
| // Don't overwrite it, to keep the servicesFound count correct. | ||
| continue | ||
| } | ||
|
|
||
| uuid, _ := ParseUUID(service.Properties.UUID) | ||
| ds := DeviceService{UUID: uuid, | ||
| service: service, | ||
| } | ||
|
|
||
| services = append(services, ds) | ||
| servicesFound++ | ||
| uuidServices[service.Properties.UUID] = service.Properties.UUID | ||
| } | ||
|
|
||
| if servicesFound != len(uuids) { | ||
| if servicesFound <= len(uuids) { | ||
| return nil, errors.New("bluetooth: could not find some services") | ||
| } | ||
|
|
||
|
|
@@ -91,6 +108,8 @@ func (d *Device) DiscoverServices(uuids []UUID) ([]DeviceService, error) { | |
| // DeviceCharacteristic is a BLE characteristic on a connected peripheral | ||
| // device. | ||
| type DeviceCharacteristic struct { | ||
| UUID | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't catch this with the darwin support, but I wonder whether this would perhaps be better implemented as a getter? This could also be done in a separate PR, but seeing that the example heavily relies on UUIDs it may be best to do that in this PR. (The same argument goes for
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that is a good idea, but perhaps best done in another PR. |
||
|
|
||
| characteristic *gatt.GattCharacteristic1 | ||
| } | ||
|
|
||
|
|
@@ -101,11 +120,11 @@ type DeviceCharacteristic struct { | |
| // 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 currently result in zero characteristics | ||
| // being returned, but this may be changed in the future to return a complete | ||
| // Passing a nil slice of UUIDs will return a complete | ||
| // list of characteristics. | ||
| func (s *DeviceService) DiscoverCharacteristics(uuids []UUID) ([]DeviceCharacteristic, error) { | ||
| chars := make([]DeviceCharacteristic, len(uuids)) | ||
| chars := []DeviceCharacteristic{} | ||
| uuidChars := make(map[string]string) | ||
| characteristicsFound := 0 | ||
|
|
||
| // Iterate through all objects managed by BlueZ, hoping to find the | ||
|
|
@@ -130,23 +149,38 @@ func (s *DeviceService) DiscoverCharacteristics(uuids []UUID) ([]DeviceCharacter | |
| if err != nil { | ||
| return nil, err | ||
| } | ||
| for i, uuid := range uuids { | ||
| if char.Properties.UUID != uuid.String() { | ||
| // Not one of the characteristics we're looking for. | ||
| continue | ||
|
|
||
| if len(uuids) > 0 { | ||
| found := false | ||
| for _, uuid := range uuids { | ||
| if char.Properties.UUID == uuid.String() { | ||
| // One of the services we're looking for. | ||
| found = true | ||
| break | ||
| } | ||
| } | ||
| if chars[i].characteristic != nil { | ||
| // There is more than one characteristic with the same UUID? | ||
| // Don't overwrite it, to keep the servicesFound count correct. | ||
| if !found { | ||
| continue | ||
| } | ||
| chars[i].characteristic = char | ||
| characteristicsFound++ | ||
| break | ||
| } | ||
|
|
||
| if _, ok := uuidChars[char.Properties.UUID]; ok { | ||
| // There is more than one characteristic with the same UUID? | ||
| // Don't overwrite it, to keep the servicesFound count correct. | ||
| continue | ||
| } | ||
|
|
||
| uuid, _ := ParseUUID(char.Properties.UUID) | ||
| dc := DeviceCharacteristic{UUID: uuid, | ||
| characteristic: char, | ||
| } | ||
|
|
||
| chars = append(chars, dc) | ||
| characteristicsFound++ | ||
| uuidChars[char.Properties.UUID] = char.Properties.UUID | ||
| } | ||
|
|
||
| if characteristicsFound != len(uuids) { | ||
| if characteristicsFound < len(uuids) { | ||
| return nil, errors.New("bluetooth: could not find some characteristics") | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.