2015-06-07 12:38:19 -07:00
|
|
|
package ble
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"strings"
|
|
|
|
"github.com/hybridgroup/gobot"
|
|
|
|
"github.com/paypal/gatt"
|
|
|
|
)
|
|
|
|
|
2015-06-07 19:31:00 -07:00
|
|
|
// TODO: handle other OS defaults besides Linux
|
2015-06-07 12:38:19 -07:00
|
|
|
var DefaultClientOptions = []gatt.Option{
|
|
|
|
gatt.LnxMaxConnections(1),
|
|
|
|
gatt.LnxDeviceID(-1, false),
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ gobot.Adaptor = (*BLEAdaptor)(nil)
|
|
|
|
|
|
|
|
// Represents a Connection to a BLE Peripheral
|
|
|
|
type BLEAdaptor struct {
|
|
|
|
name string
|
|
|
|
uuid string
|
|
|
|
device gatt.Device
|
2015-06-29 09:47:18 -07:00
|
|
|
peripheral gatt.Peripheral
|
2015-06-07 12:38:19 -07:00
|
|
|
//sp io.ReadWriteCloser
|
|
|
|
connected bool
|
|
|
|
//connect func(string) (io.ReadWriteCloser, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewBLEAdaptor returns a new BLEAdaptor given a name and uuid
|
|
|
|
func NewBLEAdaptor(name string, uuid string) *BLEAdaptor {
|
|
|
|
return &BLEAdaptor{
|
|
|
|
name: name,
|
|
|
|
uuid: uuid,
|
2015-06-29 09:47:18 -07:00
|
|
|
connected: false,
|
2015-06-07 12:38:19 -07:00
|
|
|
// connect: func(port string) (io.ReadWriteCloser, error) {
|
|
|
|
// return serial.OpenPort(&serial.Config{Name: port, Baud: 115200})
|
|
|
|
// },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BLEAdaptor) Name() string { return b.name }
|
|
|
|
func (b *BLEAdaptor) UUID() string { return b.uuid }
|
2015-06-29 15:25:59 -07:00
|
|
|
func (b *BLEAdaptor) Peripheral() gatt.Peripheral { return b.peripheral }
|
2015-06-07 12:38:19 -07:00
|
|
|
|
|
|
|
// Connect initiates a connection to the BLE peripheral. Returns true on successful connection.
|
|
|
|
func (b *BLEAdaptor) Connect() (errs []error) {
|
|
|
|
device, err := gatt.NewDevice(DefaultClientOptions...)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Failed to open BLE device, err: %s\n", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
b.device = device
|
|
|
|
|
|
|
|
// Register handlers.
|
|
|
|
device.Handle(
|
|
|
|
gatt.PeripheralDiscovered(b.onDiscovered),
|
2015-06-29 15:25:59 -07:00
|
|
|
//gatt.PeripheralConnected(b.onConnected),
|
2015-06-07 12:38:19 -07:00
|
|
|
gatt.PeripheralDisconnected(b.onDisconnected),
|
|
|
|
)
|
|
|
|
|
|
|
|
device.Init(b.onStateChanged)
|
|
|
|
|
|
|
|
// TODO: make sure peripheral currently exists for this UUID before returning
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reconnect attempts to reconnect to the BLE peripheral. If it has an active connection
|
|
|
|
// it will first close that connection and then establish a new connection.
|
|
|
|
// Returns true on Successful reconnection
|
|
|
|
func (b *BLEAdaptor) Reconnect() (errs []error) {
|
|
|
|
if b.connected {
|
|
|
|
b.Disconnect()
|
|
|
|
}
|
|
|
|
return b.Connect()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disconnect terminates the connection to the BLE peripheral. Returns true on successful disconnect.
|
|
|
|
func (b *BLEAdaptor) Disconnect() (errs []error) {
|
|
|
|
// if a.connected {
|
|
|
|
// if err := a.sp.Close(); err != nil {
|
|
|
|
// return []error{err}
|
|
|
|
// }
|
|
|
|
// a.connected = false
|
|
|
|
// }
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finalize finalizes the BLEAdaptor
|
|
|
|
func (b *BLEAdaptor) Finalize() (errs []error) {
|
|
|
|
return b.Disconnect()
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReadCharacteristic returns bytes from the BLE device for the
|
|
|
|
// requested service and characteristic
|
2015-06-29 15:25:59 -07:00
|
|
|
func (b *BLEAdaptor) ReadCharacteristic(sUUID string, cUUID string) (data chan []byte, err error) {
|
|
|
|
//defer b.peripheral.Device().CancelConnection(b.peripheral)
|
|
|
|
fmt.Println("ReadCharacteristic")
|
2015-06-29 09:47:18 -07:00
|
|
|
if !b.connected {
|
|
|
|
log.Fatalf("Cannot read from BLE device until connected")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c := make(chan []byte)
|
2015-06-29 15:25:59 -07:00
|
|
|
f := func(p gatt.Peripheral, e error) {
|
2015-06-29 09:47:18 -07:00
|
|
|
b.performRead(c, sUUID, cUUID)
|
|
|
|
}
|
|
|
|
|
|
|
|
b.device.Handle(
|
|
|
|
gatt.PeripheralConnected(f),
|
|
|
|
)
|
|
|
|
|
|
|
|
b.peripheral.Device().Connect(b.peripheral)
|
2015-06-07 12:38:19 -07:00
|
|
|
|
2015-06-29 15:25:59 -07:00
|
|
|
return c, nil
|
2015-06-29 09:47:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BLEAdaptor) performRead(c chan []byte, sUUID string, cUUID string) {
|
2015-06-29 15:25:59 -07:00
|
|
|
fmt.Println("performRead")
|
|
|
|
fmt.Printf("%x", b.Peripheral())
|
2015-06-29 09:47:18 -07:00
|
|
|
s := b.getService(sUUID)
|
|
|
|
characteristic := b.getCharacteristic(s, cUUID)
|
|
|
|
|
|
|
|
val, err := b.peripheral.ReadCharacteristic(characteristic)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Failed to read characteristic, err: %s\n", err)
|
|
|
|
c <- []byte{}
|
|
|
|
}
|
|
|
|
|
|
|
|
c <- val
|
2015-06-07 12:38:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BLEAdaptor) getPeripheral() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-06-29 15:25:59 -07:00
|
|
|
func (b *BLEAdaptor) getService(sUUID string) (service *gatt.Service) {
|
|
|
|
fmt.Println("getService")
|
|
|
|
ss, err := b.Peripheral().DiscoverServices(nil)
|
|
|
|
fmt.Println(ss)
|
|
|
|
fmt.Println("yo")
|
|
|
|
fmt.Println(err)
|
2015-06-29 09:47:18 -07:00
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Failed to discover services, err: %s\n", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-06-29 15:25:59 -07:00
|
|
|
fmt.Println("service")
|
|
|
|
|
|
|
|
for _, s := range ss {
|
|
|
|
msg := "Service: " + s.UUID().String()
|
|
|
|
if len(s.Name()) > 0 {
|
|
|
|
msg += " (" + s.Name() + ")"
|
|
|
|
}
|
|
|
|
fmt.Println(msg)
|
|
|
|
|
|
|
|
id := strings.ToUpper(s.UUID().String())
|
|
|
|
if strings.ToUpper(sUUID) != id {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
msg = "Found Service: " + s.UUID().String()
|
|
|
|
if len(s.Name()) > 0 {
|
|
|
|
msg += " (" + s.Name() + ")"
|
|
|
|
}
|
|
|
|
fmt.Println(msg)
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println("getService: none found")
|
|
|
|
return
|
2015-06-29 09:47:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BLEAdaptor) getCharacteristic(s *gatt.Service, cUUID string) (c *gatt.Characteristic) {
|
2015-06-29 15:25:59 -07:00
|
|
|
fmt.Println("getCharacteristic")
|
|
|
|
cs, err := b.Peripheral().DiscoverCharacteristics(nil, s)
|
2015-06-29 09:47:18 -07:00
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Failed to discover characteristics, err: %s\n", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-06-29 15:25:59 -07:00
|
|
|
for _, char := range cs {
|
|
|
|
id := strings.ToUpper(char.UUID().String())
|
|
|
|
if strings.ToUpper(cUUID) != id {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
msg := " Found Characteristic " + char.UUID().String()
|
|
|
|
if len(char.Name()) > 0 {
|
|
|
|
msg += " (" + char.Name() + ")"
|
|
|
|
}
|
|
|
|
msg += "\n properties " + char.Properties().String()
|
|
|
|
fmt.Println(msg)
|
|
|
|
return char
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2015-06-07 12:38:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BLEAdaptor) onStateChanged(d gatt.Device, s gatt.State) {
|
|
|
|
fmt.Println("State:", s)
|
|
|
|
switch s {
|
|
|
|
case gatt.StatePoweredOn:
|
|
|
|
fmt.Println("scanning...")
|
|
|
|
d.Scan([]gatt.UUID{}, false)
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
d.StopScanning()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BLEAdaptor) onDiscovered(p gatt.Peripheral, a *gatt.Advertisement, rssi int) {
|
2015-06-29 15:25:59 -07:00
|
|
|
fmt.Printf("\nPeripheral ID:%s, NAME:(%s)\n", p.ID(), p.Name())
|
2015-06-07 12:38:19 -07:00
|
|
|
id := strings.ToUpper(b.UUID())
|
|
|
|
if strings.ToUpper(p.ID()) != id {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
b.connected = true
|
2015-06-29 09:47:18 -07:00
|
|
|
b.peripheral = p
|
2015-06-07 12:38:19 -07:00
|
|
|
|
|
|
|
// Stop scanning once we've got the peripheral we're looking for.
|
|
|
|
p.Device().StopScanning()
|
|
|
|
|
|
|
|
fmt.Printf("\nPeripheral ID:%s, NAME:(%s)\n", p.ID(), p.Name())
|
|
|
|
fmt.Println(" Local Name =", a.LocalName)
|
|
|
|
fmt.Println(" TX Power Level =", a.TxPowerLevel)
|
|
|
|
fmt.Println(" Manufacturer Data =", a.ManufacturerData)
|
|
|
|
fmt.Println(" Service Data =", a.ServiceData)
|
|
|
|
fmt.Println("")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BLEAdaptor) onConnected(p gatt.Peripheral, err error) {
|
|
|
|
fmt.Println("Connected")
|
|
|
|
defer p.Device().CancelConnection(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BLEAdaptor) onDisconnected(p gatt.Peripheral, err error) {
|
|
|
|
fmt.Println("Disconnected")
|
|
|
|
}
|
|
|
|
|