macos: able to discover services and characteristics for a device
Signed-off-by: Ron Evans <ron@hybridgroup.com>
This commit is contained in:
parent
5f44bb4a96
commit
dc738f9c47
4 changed files with 108 additions and 54 deletions
|
@ -10,7 +10,7 @@ This package attempts to build a cross-platform Bluetooth Low Energy module for
|
|||
| API used | WinRT | BlueZ (over D-Bus) | SoftDevice | CoreBluetooth |
|
||||
| Scanning | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| Connect to peripheral | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| Write peripheral characteristics | :x: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
| Write peripheral characteristics | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| Receive notifications | :x: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
| Advertisement | :x: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
| Local services | :x: | :heavy_check_mark: | :heavy_check_mark: | :x: |
|
||||
|
|
|
@ -80,40 +80,6 @@ func (a *Adapter) DidConnectPeripheral(cmgr cbgo.CentralManager, prph cbgo.Perip
|
|||
a.connectChan <- prph
|
||||
}
|
||||
|
||||
// DidDisconnectPeripheral when peripheral is disconnected.
|
||||
func (a *Adapter) DidDisconnectPeripheral(cmgr cbgo.CentralManager, prph cbgo.Peripheral, err error) {
|
||||
}
|
||||
|
||||
// PeripheralManager delegate functions
|
||||
|
||||
// PeripheralManagerDidUpdateState when state updated.
|
||||
func (a *Adapter) PeripheralManagerDidUpdateState(pmgr cbgo.PeripheralManager) {
|
||||
}
|
||||
|
||||
// DidAddService when service added.
|
||||
func (a *Adapter) DidAddService(pmgr cbgo.PeripheralManager, svc cbgo.Service, err error) {
|
||||
}
|
||||
|
||||
// DidStartAdvertising when advertising starts.
|
||||
func (a *Adapter) DidStartAdvertising(pmgr cbgo.PeripheralManager, err error) {
|
||||
}
|
||||
|
||||
// DidReceiveReadRequest when read request received.
|
||||
func (a *Adapter) DidReceiveReadRequest(pmgr cbgo.PeripheralManager, cbreq cbgo.ATTRequest) {
|
||||
}
|
||||
|
||||
// DidReceiveWriteRequests when write requests received.
|
||||
func (a *Adapter) DidReceiveWriteRequests(pmgr cbgo.PeripheralManager, cbreqs []cbgo.ATTRequest) {
|
||||
}
|
||||
|
||||
// CentralDidSubscribe when central subscribed.
|
||||
func (a *Adapter) CentralDidSubscribe(pmgr cbgo.PeripheralManager, cent cbgo.Central, cbchr cbgo.Characteristic) {
|
||||
}
|
||||
|
||||
// CentralDidUnsubscribe when central unsubscribed.
|
||||
func (a *Adapter) CentralDidUnsubscribe(pmgr cbgo.PeripheralManager, cent cbgo.Central, chr cbgo.Characteristic) {
|
||||
}
|
||||
|
||||
// makeScanResult creates a ScanResult when peripheral is found.
|
||||
func makeScanResult(prph cbgo.Peripheral, advFields cbgo.AdvFields, rssi int) ScanResult {
|
||||
uuid, _ := ParseUUID(prph.Identifier().String())
|
||||
|
|
|
@ -81,7 +81,11 @@ func (a *Adapter) StopScan() error {
|
|||
type Device struct {
|
||||
cbgo.PeripheralDelegateBase
|
||||
|
||||
cm cbgo.CentralManager
|
||||
cm cbgo.CentralManager
|
||||
prph cbgo.Peripheral
|
||||
|
||||
servicesChan chan error
|
||||
charsChan chan error
|
||||
}
|
||||
|
||||
// Connect starts a connection attempt to the given peripheral device address.
|
||||
|
@ -101,7 +105,10 @@ func (a *Adapter) Connect(address Addresser, params ConnectionParams) (*Device,
|
|||
select {
|
||||
case p := <-a.connectChan:
|
||||
d := &Device{
|
||||
cm: a.cm,
|
||||
cm: a.cm,
|
||||
prph: p,
|
||||
servicesChan: make(chan error),
|
||||
charsChan: make(chan error),
|
||||
}
|
||||
|
||||
p.SetDelegate(d)
|
||||
|
@ -111,23 +118,27 @@ func (a *Adapter) Connect(address Addresser, params ConnectionParams) (*Device,
|
|||
}
|
||||
}
|
||||
|
||||
// Peripheral returns the Device's cbgo.Peripheral
|
||||
func (d *Device) Peripheral() (prph cbgo.Peripheral) {
|
||||
return d.prph
|
||||
}
|
||||
|
||||
// CharsChan returns the Device's charsChan channel used for
|
||||
// blocking on discovering the characteristics for a service.
|
||||
func (d *Device) CharsChan() chan error {
|
||||
return d.charsChan
|
||||
}
|
||||
|
||||
// Peripheral delegate functions
|
||||
|
||||
// DidDiscoverServices is called when the services for a Peripheral
|
||||
// have been discovered.
|
||||
func (d *Device) DidDiscoverServices(prph cbgo.Peripheral, err error) {
|
||||
d.servicesChan <- nil
|
||||
}
|
||||
|
||||
// DidDiscoverCharacteristics is called when the characteristics for a Service
|
||||
// for a Peripheral have been discovered.
|
||||
func (d *Device) DidDiscoverCharacteristics(prph cbgo.Peripheral, svc cbgo.Service, err error) {
|
||||
}
|
||||
func (d *Device) DidDiscoverDescriptors(prph cbgo.Peripheral, chr cbgo.Characteristic, err error) {
|
||||
}
|
||||
func (d *Device) DidUpdateValueForCharacteristic(prph cbgo.Peripheral, chr cbgo.Characteristic, err error) {
|
||||
}
|
||||
func (d *Device) DidUpdateValueForDescriptor(prph cbgo.Peripheral, dsc cbgo.Descriptor, err error) {
|
||||
}
|
||||
func (d *Device) DidWriteValueForCharacteristic(prph cbgo.Peripheral, chr cbgo.Characteristic, err error) {
|
||||
}
|
||||
func (d *Device) DidWriteValueForDescriptor(prph cbgo.Peripheral, dsc cbgo.Descriptor, err error) {
|
||||
}
|
||||
func (d *Device) DidUpdateNotificationState(prph cbgo.Peripheral, chr cbgo.Characteristic, err error) {
|
||||
}
|
||||
func (d *Device) DidReadRSSI(prph cbgo.Peripheral, rssi int, err error) {
|
||||
d.charsChan <- nil
|
||||
}
|
||||
|
|
|
@ -1,15 +1,56 @@
|
|||
package bluetooth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/JuulLabs-OSS/cbgo"
|
||||
)
|
||||
|
||||
// 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.
|
||||
func (d *Device) DiscoverServices(uuids []UUID) ([]DeviceService, error) {
|
||||
return nil, nil
|
||||
cbuuids := []cbgo.UUID{}
|
||||
for _, u := range uuids {
|
||||
uuid, _ := cbgo.ParseUUID(u.String())
|
||||
cbuuids = append(cbuuids, uuid)
|
||||
}
|
||||
|
||||
d.prph.DiscoverServices(cbuuids)
|
||||
|
||||
// wait on channel for service discovery
|
||||
select {
|
||||
case <-d.servicesChan:
|
||||
svcs := []DeviceService{}
|
||||
for _, dsvc := range d.prph.Services() {
|
||||
uuid, _ := ParseUUID(dsvc.UUID().String())
|
||||
svc := DeviceService{
|
||||
UUID: uuid,
|
||||
device: d,
|
||||
service: dsvc,
|
||||
}
|
||||
svcs = append(svcs, svc)
|
||||
}
|
||||
return svcs, nil
|
||||
case <-time.NewTimer(10 * time.Second).C:
|
||||
return nil, errors.New("timeout on DiscoverServices")
|
||||
}
|
||||
}
|
||||
|
||||
// DeviceService is a BLE service on a connected peripheral device.
|
||||
type DeviceService struct {
|
||||
UUID
|
||||
|
||||
device *Device
|
||||
|
||||
service cbgo.Service
|
||||
}
|
||||
|
||||
// Device returns the Device for this service.
|
||||
func (s *DeviceService) Device() *Device {
|
||||
return s.device
|
||||
}
|
||||
|
||||
// DiscoverCharacteristics discovers characteristics in this service. Pass a
|
||||
|
@ -19,12 +60,42 @@ type DeviceService 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.
|
||||
func (s *DeviceService) DiscoverCharacteristics(uuids []UUID) ([]DeviceCharacteristic, error) {
|
||||
return nil, nil
|
||||
cbuuids := []cbgo.UUID{}
|
||||
for _, u := range uuids {
|
||||
uuid, _ := cbgo.ParseUUID(u.String())
|
||||
cbuuids = append(cbuuids, uuid)
|
||||
}
|
||||
|
||||
s.Device().Peripheral().DiscoverCharacteristics(cbuuids, s.service)
|
||||
|
||||
// wait on channel for characteristic discovery
|
||||
select {
|
||||
case <-s.Device().CharsChan():
|
||||
chars := []DeviceCharacteristic{}
|
||||
for _, dchar := range s.service.Characteristics() {
|
||||
uuid, _ := ParseUUID(dchar.UUID().String())
|
||||
char := DeviceCharacteristic{
|
||||
UUID: uuid,
|
||||
service: s,
|
||||
characteristic: dchar,
|
||||
}
|
||||
chars = append(chars, char)
|
||||
}
|
||||
return chars, nil
|
||||
case <-time.NewTimer(10 * time.Second).C:
|
||||
return nil, errors.New("timeout on DiscoverCharacteristics")
|
||||
}
|
||||
}
|
||||
|
||||
// DeviceCharacteristic is a BLE characteristic on a connected peripheral
|
||||
// device.
|
||||
type DeviceCharacteristic struct {
|
||||
UUID
|
||||
|
||||
service *DeviceService
|
||||
|
||||
characteristic cbgo.Characteristic
|
||||
callback func(buf []byte)
|
||||
}
|
||||
|
||||
// WriteWithoutResponse replaces the characteristic value with a new value. The
|
||||
|
@ -32,7 +103,9 @@ type DeviceCharacteristic struct {
|
|||
// 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) {
|
||||
return 0, nil
|
||||
c.service.Device().Peripheral().WriteCharacteristic(p, c.characteristic, false)
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// EnableNotifications enables notifications in the Client Characteristic
|
||||
|
@ -40,5 +113,9 @@ func (c DeviceCharacteristic) WriteWithoutResponse(p []byte) (n int, err error)
|
|||
// notification with a new value every time the value of the characteristic
|
||||
// changes.
|
||||
func (c DeviceCharacteristic) EnableNotifications(callback func(buf []byte)) error {
|
||||
if callback == nil {
|
||||
return errors.New("must provide a callback for EnableNotifications")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue