144 lines
3.6 KiB
Go
144 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())
|
||
|
|
}
|
||
|
|
}
|