Skip to content

Commit

Permalink
gattc/*: DeviceCharacteristic Read() implementation
Browse files Browse the repository at this point in the history
Signed-off-by: deadprogram <[email protected]>
  • Loading branch information
deadprogram authored Oct 22, 2020
1 parent c27b1cb commit 266de98
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 5 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions adapter_nrf528xx.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
12 changes: 12 additions & 0 deletions examples/discover/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package main

import (
"strconv"

"tinygo.org/x/bluetooth"
)

Expand Down Expand Up @@ -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())

Expand All @@ -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]))
}
}
}

Expand Down
9 changes: 7 additions & 2 deletions gap_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
34 changes: 31 additions & 3 deletions gattc_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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
}
11 changes: 11 additions & 0 deletions gattc_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
36 changes: 36 additions & 0 deletions gattc_sd.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

0 comments on commit 266de98

Please sign in to comment.