Skip to content

Commit 7470aeb

Browse files
committed
examples: add Find My Gopherbot example
Signed-off-by: deadprogram <[email protected]>
1 parent 62d5d30 commit 7470aeb

File tree

3 files changed

+222
-0
lines changed

3 files changed

+222
-0
lines changed

examples/findmy/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Find My Gopherbot
2+
3+
Your Gopherbot is now a FindMy beacon.
4+
5+
Requires CircuitPlayground Bluefruit.
6+
7+
Uses "Go Haystack" see [https://github.com/hybridgroup/go-haystack](https://github.com/hybridgroup/go-haystack)
8+
9+
## Flashing
10+
11+
```shell
12+
tinygo flash -target circuitplay-bluefruit -ldflags="-X main.AdvertisingKey='YOURKEYHERE'" ./examples/demo
13+
```

examples/findmy/beacon.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//go:build circuitplay_bluefruit
2+
3+
package main
4+
5+
import (
6+
"encoding/base64"
7+
"errors"
8+
"time"
9+
10+
"github.com/hybridgroup/go-haystack/lib/findmy"
11+
"tinygo.org/x/bluetooth"
12+
)
13+
14+
var adapter = bluetooth.DefaultAdapter
15+
16+
// AdvertisingKey is the public key of the device. Must be base64 encoded.
17+
var AdvertisingKey string
18+
19+
func initBeacon() {
20+
// wait for USB serial to be available
21+
time.Sleep(2 * time.Second)
22+
23+
key, err := getKeyData()
24+
if err != nil {
25+
fail("failed to get key data: " + err.Error())
26+
}
27+
println("key is", AdvertisingKey, "(", len(key), "bytes)")
28+
29+
opts := bluetooth.AdvertisementOptions{
30+
AdvertisementType: bluetooth.AdvertisingTypeNonConnInd,
31+
Interval: bluetooth.NewDuration(1285000 * time.Microsecond), // 1285ms
32+
ManufacturerData: []bluetooth.ManufacturerDataElement{findmy.NewData(key)},
33+
}
34+
35+
must("enable BLE stack", adapter.Enable())
36+
37+
// Set the address to the first 6 bytes of the public key.
38+
adapter.SetRandomAddress(bluetooth.MAC{key[5], key[4], key[3], key[2], key[1], key[0] | 0xC0})
39+
40+
println("configure advertising...")
41+
adv := adapter.DefaultAdvertisement()
42+
must("config adv", adv.Configure(opts))
43+
44+
println("start advertising...")
45+
must("start adv", adv.Start())
46+
}
47+
48+
// getKeyData returns the public key data from the base64 encoded string.
49+
func getKeyData() ([]byte, error) {
50+
val, err := base64.StdEncoding.DecodeString(AdvertisingKey)
51+
if err != nil {
52+
return nil, err
53+
}
54+
if len(val) != 28 {
55+
return nil, errors.New("public key must be 28 bytes long")
56+
}
57+
58+
return val, nil
59+
}
60+
61+
// must calls a function and fails if an error occurs.
62+
func must(action string, err error) {
63+
if err != nil {
64+
fail("failed to " + action + ": " + err.Error())
65+
}
66+
}
67+
68+
// fail prints a message over and over forever.
69+
func fail(msg string) {
70+
for {
71+
println(msg)
72+
time.Sleep(time.Second)
73+
}
74+
}

examples/findmy/main.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package main
2+
3+
import (
4+
"image/color"
5+
"time"
6+
7+
"github.com/hybridgroup/gopherbot"
8+
)
9+
10+
const (
11+
greenVisor = iota
12+
redVisor
13+
cylonVisor
14+
tiltVisor
15+
xmasVisor
16+
)
17+
18+
const (
19+
forward = iota
20+
backward
21+
)
22+
23+
var (
24+
accel *gopherbot.AccelerometerDevice
25+
visor *gopherbot.VisorDevice
26+
speaker *gopherbot.SpeakerDevice
27+
28+
pos = 0
29+
)
30+
31+
func main() {
32+
initBeacon()
33+
34+
accel = gopherbot.Accelerometer()
35+
visor = gopherbot.Visor()
36+
speaker = gopherbot.Speaker()
37+
38+
antenna := gopherbot.Antenna()
39+
backpack := gopherbot.Backpack()
40+
41+
left := gopherbot.LeftButton()
42+
right := gopherbot.RightButton()
43+
44+
mode := redVisor
45+
46+
go antenna.Blink()
47+
48+
for {
49+
if right.Pushed() {
50+
mode++
51+
if mode > xmasVisor {
52+
mode = greenVisor
53+
}
54+
}
55+
56+
if left.Pushed() {
57+
mode--
58+
if mode < greenVisor {
59+
mode = xmasVisor
60+
}
61+
}
62+
63+
switch mode {
64+
case greenVisor:
65+
visor.Green()
66+
if gopherbot.Slider().IsOn() {
67+
backpack.Alternate(color.RGBA{R: 0x00, G: 0xff, B: 0x00}, color.RGBA{R: 0x00, G: 0x00, B: 0xff})
68+
} else {
69+
backpack.Off()
70+
}
71+
case redVisor:
72+
visor.Red()
73+
if gopherbot.Slider().IsOn() {
74+
backpack.Red()
75+
} else {
76+
backpack.Off()
77+
}
78+
case cylonVisor:
79+
visor.Cylon()
80+
if gopherbot.Slider().IsOn() {
81+
backpack.Alternate(color.RGBA{R: 0xff, G: 0x00, B: 0x00}, color.RGBA{R: 0x00, G: 0x00, B: 0x00})
82+
} else {
83+
backpack.Off()
84+
}
85+
case tiltVisor:
86+
tilt()
87+
case xmasVisor:
88+
visor.Xmas()
89+
if gopherbot.Slider().IsOn() {
90+
backpack.Xmas()
91+
} else {
92+
backpack.Off()
93+
}
94+
}
95+
96+
time.Sleep(200 * time.Millisecond)
97+
}
98+
}
99+
100+
func tilt() {
101+
x, y, z, _ := accel.ReadAcceleration()
102+
println(x, y, z)
103+
104+
switch {
105+
case x < 300000 && x > -300000:
106+
switch {
107+
case pos <= gopherbot.VisorLEDCount/2-1:
108+
pos++
109+
case pos >= gopherbot.VisorLEDCount/2+1:
110+
pos--
111+
}
112+
case x > 300000:
113+
pos++
114+
if pos == gopherbot.VisorLEDCount {
115+
pos = gopherbot.VisorLEDCount - 1
116+
speaker.Bleep()
117+
}
118+
case x < -300000:
119+
pos--
120+
if pos < 0 {
121+
pos = 0
122+
speaker.Bleep()
123+
}
124+
}
125+
126+
for i := range visor.LED {
127+
if i == pos {
128+
visor.LED[i] = color.RGBA{R: 0x00, G: 0xff, B: 0x00, A: 0x77}
129+
} else {
130+
visor.LED[i] = color.RGBA{R: 0x00, G: 0x00, B: 0x00, A: 0x77}
131+
}
132+
}
133+
134+
visor.Show()
135+
}

0 commit comments

Comments
 (0)