nicebadge/tutorial/ble/step2/main.go

143 lines
3.6 KiB
Go

package main
// BLE LED color control example.
// A mobile app writes 3 bytes (R, G, B) to the color characteristic
// and both WS2812 LEDs light up with that color.
//
// Service UUID: BADA5501-B5A3-F393-E0A9-E50E24DCCA9E
// Color char: BADA5502-B5A3-F393-E0A9-E50E24DCCA9E
//
// Compatible apps: nRF Connect, LightBlue (iOS/Android).
// To set color: write 3 hex bytes to the color characteristic, e.g. FF0080 = red:255 green:0 blue:128.
import (
"image/color"
"machine"
"strconv"
"github.com/tinygo-org/bluetooth"
"tinygo.org/x/drivers/st7789"
"tinygo.org/x/drivers/ws2812"
"tinygo.org/x/tinyfont"
"tinygo.org/x/tinyfont/freesans"
)
var (
adapter = bluetooth.DefaultAdapter
ledServiceUUID = bluetooth.NewUUID([16]byte{
0xBA, 0xDA, 0x55, 0x01, 0xB5, 0xA3, 0xF3, 0x93,
0xE0, 0xA9, 0xE5, 0x0E, 0x24, 0xDC, 0xCA, 0x9E,
})
colorCharUUID = bluetooth.NewUUID([16]byte{
0xBA, 0xDA, 0x55, 0x02, 0xB5, 0xA3, 0xF3, 0x93,
0xE0, 0xA9, 0xE5, 0x0E, 0x24, 0xDC, 0xCA, 0x9E,
})
)
var (
display st7789.Device
leds ws2812.Device
connected bool
ledColor color.RGBA
)
var (
black = color.RGBA{0, 0, 0, 255}
cyan = color.RGBA{0, 200, 255, 255}
white = color.RGBA{255, 255, 255, 255}
gray = color.RGBA{150, 150, 150, 255}
)
func main() {
initDisplay()
initLEDs()
drawStatus("Advertising...")
drawColor(color.RGBA{0, 0, 0, 255})
must("enable BLE", adapter.Enable())
must("add service", adapter.AddService(&bluetooth.Service{
UUID: ledServiceUUID,
Characteristics: []bluetooth.CharacteristicConfig{
{
UUID: colorCharUUID,
Flags: bluetooth.CharacteristicWritePermission | bluetooth.CharacteristicWriteWithoutResponsePermission,
WriteEvent: func(client bluetooth.Connection, offset int, value []byte) {
if len(value) < 3 {
return
}
// value[0]=R, value[1]=G, value[2]=B
ledColor = color.RGBA{value[0], value[1], value[2], 255}
setLEDs(ledColor)
drawColor(ledColor)
if !connected {
connected = true
drawStatus("Connected ")
}
},
},
},
}))
adv := adapter.DefaultAdvertisement()
must("configure adv", adv.Configure(bluetooth.AdvertisementOptions{
LocalName: "NiceBadge",
ServiceUUIDs: []bluetooth.UUID{ledServiceUUID},
}))
must("start adv", adv.Start())
// wait forever; all logic is driven by the BLE WriteEvent callback
select {}
}
func initDisplay() {
machine.SPI0.Configure(machine.SPIConfig{
SCK: machine.P1_01,
SDO: machine.P1_02,
Frequency: 8000000,
Mode: 0,
})
display = st7789.New(machine.SPI0,
machine.P1_15, machine.P1_13, machine.P0_10, machine.P0_09)
display.Configure(st7789.Config{
Rotation: st7789.ROTATION_90,
Width: 135,
Height: 240,
RowOffset: 40,
ColumnOffset: 53,
})
display.FillScreen(black)
}
func initLEDs() {
neo := machine.P1_11
neo.Configure(machine.PinConfig{Mode: machine.PinOutput})
leds = ws2812.New(neo)
}
func setLEDs(c color.RGBA) {
leds.WriteColors([]color.RGBA{c, c})
}
func drawStatus(status string) {
display.FillRectangle(0, 0, 240, 32, black)
tinyfont.WriteLine(&display, &freesans.Regular9pt7b, 10, 22, "BLE: "+status, cyan)
}
func drawColor(c color.RGBA) {
// show a filled rectangle with the current color and its RGB values below
display.FillRectangle(0, 38, 240, 60, color.RGBA{c.R, c.G, c.B, 255})
display.FillRectangle(0, 100, 240, 35, black)
rgb := "R:" + strconv.Itoa(int(c.R)) +
" G:" + strconv.Itoa(int(c.G)) +
" B:" + strconv.Itoa(int(c.B))
tinyfont.WriteLine(&display, &freesans.Regular9pt7b, 10, 122, rgb, white)
}
func must(action string, err error) {
if err != nil {
panic("failed to " + action + ": " + err.Error())
}
}