Skip to content

Commit 3e2ce45

Browse files
deadprogramaykevl
authored andcommitted
examples: extend HRS to perform notifications, add heartrate-monitor example that shows notifications
Signed-off-by: deadprogram <ron@hybridgroup.com>
1 parent c1d8db9 commit 3e2ce45

File tree

4 files changed

+156
-1
lines changed

4 files changed

+156
-1
lines changed

examples/heartrate-monitor/main.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// This example scans and then connects to a specific Bluetooth peripheral
2+
// that can provide the Heart Rate Service (HRS).
3+
//
4+
// Once connected, it subscribes to notifications for the data value, and
5+
// displays it.
6+
//
7+
// To run this on a desktop system:
8+
//
9+
// go run ./examples/heartrate-monitor EE:74:7D:C9:2A:68
10+
//
11+
// To run this on a microcontroller, change the constant value in the file
12+
// "mcu.go" to set the MAC address of the device you want to discover.
13+
// Then, flash to the microcontroller board like this:
14+
//
15+
// tinygo flash -o circuitplay-bluefruit ./examples/heartrate-monitor
16+
//
17+
// Once the program is flashed to the board, connect to the USB port
18+
// via serial to view the output.
19+
//
20+
package main
21+
22+
import (
23+
"tinygo.org/x/bluetooth"
24+
)
25+
26+
var (
27+
adapter = bluetooth.DefaultAdapter
28+
29+
heartRateServiceUUID = bluetooth.New16BitUUID(0x180D)
30+
heartRateCharacteristicUUID = bluetooth.New16BitUUID(0x2A37)
31+
)
32+
33+
func main() {
34+
println("enabling")
35+
36+
// Enable BLE interface.
37+
must("enable BLE stack", adapter.Enable())
38+
39+
ch := make(chan bluetooth.ScanResult, 1)
40+
41+
// Start scanning.
42+
println("scanning...")
43+
err := adapter.Scan(func(adapter *bluetooth.Adapter, result bluetooth.ScanResult) {
44+
println("found device:", result.Address.String(), result.RSSI, result.LocalName())
45+
if result.Address.String() == connectAddress() {
46+
adapter.StopScan()
47+
ch <- result
48+
}
49+
})
50+
51+
var device *bluetooth.Device
52+
select {
53+
case result := <-ch:
54+
device, err = adapter.Connect(result.Address, bluetooth.ConnectionParams{})
55+
if err != nil {
56+
println(err.Error())
57+
return
58+
}
59+
60+
println("connected to ", result.Address.String())
61+
}
62+
63+
// get services
64+
println("discovering services/characteristics")
65+
srvcs, err := device.DiscoverServices([]bluetooth.UUID{heartRateServiceUUID})
66+
must("discover services", err)
67+
68+
if len(srvcs) == 0 {
69+
panic("could not find heart rate service")
70+
}
71+
72+
srvc := srvcs[0]
73+
74+
println("found service", srvc.UUID().String())
75+
76+
chars, err := srvc.DiscoverCharacteristics([]bluetooth.UUID{heartRateCharacteristicUUID})
77+
if err != nil {
78+
println(err)
79+
}
80+
81+
if len(chars) == 0 {
82+
panic("could not find heart rate characteristic")
83+
}
84+
85+
char := chars[0]
86+
println("found characteristic", char.UUID().String())
87+
88+
char.EnableNotifications(func(buf []byte) {
89+
println("data:", uint8(buf[0]))
90+
})
91+
92+
select {}
93+
}
94+
95+
func must(action string, err error) {
96+
if err != nil {
97+
panic("failed to " + action + ": " + err.Error())
98+
}
99+
}

examples/heartrate-monitor/mcu.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// +build baremetal
2+
3+
package main
4+
5+
import (
6+
"time"
7+
)
8+
9+
// replace this with the MAC address of the Bluetooth peripheral you want to connect to.
10+
const deviceAddress = "E4:B7:F4:11:8D:33"
11+
12+
func connectAddress() string {
13+
return deviceAddress
14+
}
15+
16+
// done just blocks forever, allows USB CDC reset for flashing new software.
17+
func done() {
18+
println("Done.")
19+
20+
time.Sleep(1 * time.Hour)
21+
}

examples/heartrate-monitor/os.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// +build !baremetal
2+
3+
package main
4+
5+
import "os"
6+
7+
func connectAddress() string {
8+
if len(os.Args) < 2 {
9+
println("usage: heartrate-monitor [address]")
10+
os.Exit(1)
11+
}
12+
13+
// look for device with specific name
14+
address := os.Args[1]
15+
16+
return address
17+
}
18+
19+
// done just prints a message and allows program to exit.
20+
func done() {
21+
println("Done.")
22+
}

examples/heartrate/main.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"math/rand"
45
"time"
56

67
"tinygo.org/x/bluetooth"
@@ -29,7 +30,8 @@ func main() {
2930
Handle: &heartRateMeasurement,
3031
UUID: bluetooth.New16BitUUID(0x2A37), // Heart Rate Measurement
3132
Value: []byte{0, heartRate},
32-
Flags: bluetooth.CharacteristicReadPermission | bluetooth.CharacteristicWritePermission,
33+
Flags: bluetooth.CharacteristicReadPermission | bluetooth.CharacteristicWritePermission |
34+
bluetooth.CharacteristicNotifyPermission,
3335
WriteEvent: func(client bluetooth.Connection, offset int, value []byte) {
3436
if offset != 0 || len(value) < 2 {
3537
return
@@ -48,6 +50,12 @@ func main() {
4850
nextBeat = nextBeat.Add(time.Minute / time.Duration(heartRate))
4951
println("tick", time.Now().Format("04:05.000"))
5052
time.Sleep(nextBeat.Sub(time.Now()))
53+
54+
// random variation in heartrate
55+
heartRate = randomInt(65, 85)
56+
57+
// and push the next notification
58+
heartRateMeasurement.Write([]byte{byte(heartRate)})
5159
}
5260
}
5361

@@ -56,3 +64,8 @@ func must(action string, err error) {
5664
panic("failed to " + action + ": " + err.Error())
5765
}
5866
}
67+
68+
// Returns an int >= min, < max
69+
func randomInt(min, max int) uint8 {
70+
return uint8(min + rand.Intn(max-min))
71+
}

0 commit comments

Comments
 (0)