gattc/*: DeviceCharacteristic Read() implementation

Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
Ron Evans 2020-10-22 19:04:47 +02:00 committed by GitHub
parent c27b1cb3be
commit 266de9824a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 110 additions and 5 deletions

@ -11,6 +11,8 @@ smoketest-tinygo:
@md5sum test.hex
$(TINYGO) build -o test.uf2 -size=short -target=circuitplay-bluefruit ./examples/circuitplay
@md5sum test.hex
$(TINYGO) build -o test.uf2 -size=short -target=circuitplay-bluefruit ./examples/discover
@md5sum test.hex
$(TINYGO) build -o test.hex -size=short -target=pca10040-s132v6 ./examples/heartrate
@md5sum test.hex
$(TINYGO) build -o test.hex -size=short -target=reelboard-s140v7 ./examples/ledcolor

@ -219,6 +219,17 @@ func handleEvent() {
}
}
}
case C.BLE_GATTC_EVT_READ_RSP:
readEvent := gattcEvent.params.unionfield_read_rsp()
if debug {
println("evt: read response, data length", readEvent.len)
}
readingCharacteristic.handle_value.Set(readEvent.handle)
readingCharacteristic.offset = readEvent.offset
readingCharacteristic.length = readEvent.len
// copy read event data into Go slice
copy(readingCharacteristic.value, (*[255]byte)(unsafe.Pointer(&readEvent.data[0]))[:readEvent.len:readEvent.len])
case C.BLE_GATTC_EVT_HVX:
hvxEvent := gattcEvent.params.unionfield_hvx()
switch hvxEvent._type {

@ -17,6 +17,8 @@
package main
import (
"strconv"
"tinygo.org/x/bluetooth"
)
@ -59,6 +61,9 @@ func main() {
srvcs, err := device.DiscoverServices(nil)
must("discover services", err)
// buffer to retrieve characteristic data
buf := make([]byte, 255)
for _, srvc := range srvcs {
println("- service", srvc.UUID().String())
@ -68,6 +73,13 @@ func main() {
}
for _, char := range chars {
println("-- characteristic", char.UUID().String())
n, err := char.Read(buf)
if err != nil {
println(" ", err.Error())
} else {
println(" data bytes", strconv.Itoa(n))
println(" value =", string(buf[:n]))
}
}
}

@ -156,12 +156,17 @@ func (pd *peripheralDelegate) DidDiscoverCharacteristics(prph cbgo.Peripheral, s
}
// DidUpdateValueForCharacteristic is called when the characteristic for a Service
// for a Peripheral receives a notification with a new value.
// for a Peripheral receives a notification with a new value,
// or receives a value for a read request.
func (pd *peripheralDelegate) DidUpdateValueForCharacteristic(prph cbgo.Peripheral, chr cbgo.Characteristic, err error) {
uuid, _ := ParseUUID(chr.UUID().String())
if char, ok := pd.d.characteristics[uuid]; ok {
if char != nil && char.callback != nil {
if err == nil && char.callback != nil {
go char.callback(chr.Value())
}
if char.readChan != nil {
char.readChan <- err
}
}
}

@ -92,9 +92,11 @@ func (s *DeviceService) DiscoverCharacteristics(uuids []UUID) ([]DeviceCharacter
for _, dchar := range s.service.Characteristics() {
uuid, _ := ParseUUID(dchar.UUID().String())
char := DeviceCharacteristic{
uuidWrapper: uuid,
service: s,
characteristic: dchar,
deviceCharacteristic: &deviceCharacteristic{
uuidWrapper: uuid,
service: s,
characteristic: dchar,
},
}
chars = append(chars, char)
s.device.characteristics[char.uuidWrapper] = &char
@ -108,12 +110,17 @@ func (s *DeviceService) DiscoverCharacteristics(uuids []UUID) ([]DeviceCharacter
// DeviceCharacteristic is a BLE characteristic on a connected peripheral
// device.
type DeviceCharacteristic struct {
*deviceCharacteristic
}
type deviceCharacteristic struct {
uuidWrapper
service *DeviceService
characteristic cbgo.Characteristic
callback func(buf []byte)
readChan chan error
}
// UUID returns the UUID for this DeviceCharacteristic.
@ -145,3 +152,24 @@ func (c DeviceCharacteristic) EnableNotifications(callback func(buf []byte)) err
return nil
}
// Read reads the current characteristic value.
func (c *deviceCharacteristic) Read(data []byte) (n int, err error) {
c.readChan = make(chan error)
c.service.device.prph.ReadCharacteristic(c.characteristic)
// wait for result
select {
case err := <-c.readChan:
c.readChan = nil
if err != nil {
return 0, err
}
case <-time.NewTimer(10 * time.Second).C:
c.readChan = nil
return 0, errors.New("timeout on Read()")
}
copy(data, c.characteristic.Value())
return len(c.characteristic.Value()), nil
}

@ -231,3 +231,14 @@ func (c DeviceCharacteristic) EnableNotifications(callback func(buf []byte)) err
}()
return c.characteristic.StartNotify()
}
// Read reads the current characteristic value.
func (c *DeviceCharacteristic) Read(data []byte) (int, error) {
options := make(map[string]interface{})
result, err := c.characteristic.ReadValue(options)
if err != nil {
return 0, err
}
copy(data, result)
return len(result), nil
}

@ -414,3 +414,39 @@ func (c DeviceCharacteristic) EnableNotifications(callback func(buf []byte)) err
})
return makeError(errCode)
}
// A global used to pass information from the event handler back to the
// Read function below.
var readingCharacteristic struct {
handle_value volatile.Register16
offset uint16
length uint16
value []byte
}
// Read reads the current characteristic value up to MTU length.
// A future enhancement would be to be able to retrieve a longer
// value by making multiple calls.
func (c *DeviceCharacteristic) Read(data []byte) (n int, err error) {
// global will copy bytes from read operation into data slice
readingCharacteristic.value = data
errCode := C.sd_ble_gattc_read(c.connectionHandle, c.valueHandle, 0)
if errCode != 0 {
return 0, Error(errCode)
}
// wait for response with data
for readingCharacteristic.handle_value.Get() == 0 {
arm.Asm("wfe")
}
// how much data was read into buffer
n = int(readingCharacteristic.length)
// prepare for next read
readingCharacteristic.handle_value.Set(0)
readingCharacteristic.length = 0
return
}