151 lines
3.1 KiB
Go
151 lines
3.1 KiB
Go
|
|
package main
|
||
|
|
|
||
|
|
// BLE scanner example.
|
||
|
|
// Scans for nearby BLE devices and shows their names, addresses and signal
|
||
|
|
// strength (RSSI) on the display. Press button A to clear the list.
|
||
|
|
|
||
|
|
import (
|
||
|
|
"image/color"
|
||
|
|
"machine"
|
||
|
|
"strconv"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/tinygo-org/bluetooth"
|
||
|
|
"tinygo.org/x/drivers/st7789"
|
||
|
|
"tinygo.org/x/tinyfont"
|
||
|
|
"tinygo.org/x/tinyfont/freesans"
|
||
|
|
)
|
||
|
|
|
||
|
|
const maxDevices = 5
|
||
|
|
|
||
|
|
type bleDevice struct {
|
||
|
|
name string
|
||
|
|
addr string
|
||
|
|
rssi int16
|
||
|
|
}
|
||
|
|
|
||
|
|
var (
|
||
|
|
adapter = bluetooth.DefaultAdapter
|
||
|
|
display st7789.Device
|
||
|
|
devices [maxDevices]bleDevice
|
||
|
|
count int
|
||
|
|
)
|
||
|
|
|
||
|
|
var (
|
||
|
|
black = color.RGBA{0, 0, 0, 255}
|
||
|
|
cyan = color.RGBA{0, 200, 255, 255}
|
||
|
|
white = color.RGBA{255, 255, 255, 255}
|
||
|
|
yellow = color.RGBA{255, 220, 0, 255}
|
||
|
|
green = color.RGBA{0, 220, 100, 255}
|
||
|
|
gray = color.RGBA{150, 150, 150, 255}
|
||
|
|
)
|
||
|
|
|
||
|
|
func main() {
|
||
|
|
initDisplay()
|
||
|
|
|
||
|
|
btnA := machine.P1_06
|
||
|
|
btnA.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||
|
|
|
||
|
|
must("enable BLE", adapter.Enable())
|
||
|
|
|
||
|
|
drawHeader()
|
||
|
|
|
||
|
|
// scan runs in a goroutine; found devices are stored and displayed in the main loop
|
||
|
|
go func() {
|
||
|
|
adapter.Scan(func(a *bluetooth.Adapter, result bluetooth.ScanResult) {
|
||
|
|
name := result.LocalName()
|
||
|
|
if name == "" {
|
||
|
|
name = result.Address.String()
|
||
|
|
}
|
||
|
|
|
||
|
|
// update existing entry if already seen, otherwise add new
|
||
|
|
found := false
|
||
|
|
for i := 0; i < count; i++ {
|
||
|
|
if devices[i].addr == result.Address.String() {
|
||
|
|
devices[i].rssi = result.RSSI
|
||
|
|
found = true
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if !found && count < maxDevices {
|
||
|
|
devices[count] = bleDevice{
|
||
|
|
name: name,
|
||
|
|
addr: result.Address.String(),
|
||
|
|
rssi: result.RSSI,
|
||
|
|
}
|
||
|
|
count++
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}()
|
||
|
|
|
||
|
|
for {
|
||
|
|
// button A clears the list
|
||
|
|
if !btnA.Get() {
|
||
|
|
count = 0
|
||
|
|
display.FillRectangle(0, 32, 240, 103, black)
|
||
|
|
time.Sleep(200 * time.Millisecond)
|
||
|
|
}
|
||
|
|
|
||
|
|
drawDevices()
|
||
|
|
time.Sleep(500 * time.Millisecond)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
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 drawHeader() {
|
||
|
|
tinyfont.WriteLine(&display, &freesans.Bold12pt7b, 10, 24, "BLE Scanner", cyan)
|
||
|
|
}
|
||
|
|
|
||
|
|
func drawDevices() {
|
||
|
|
// clear device list area
|
||
|
|
display.FillRectangle(0, 32, 240, 103, black)
|
||
|
|
|
||
|
|
if count == 0 {
|
||
|
|
tinyfont.WriteLine(&display, &freesans.Regular9pt7b, 10, 55, "No devices found...", gray)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
for i := 0; i < count; i++ {
|
||
|
|
y := int16(52 + i*20)
|
||
|
|
name := devices[i].name
|
||
|
|
if len(name) > 16 {
|
||
|
|
name = name[:16]
|
||
|
|
}
|
||
|
|
rssi := " " + strconv.Itoa(int(devices[i].rssi)) + "dB"
|
||
|
|
|
||
|
|
// color by signal strength
|
||
|
|
c := white
|
||
|
|
if devices[i].rssi > -60 {
|
||
|
|
c = green
|
||
|
|
} else if devices[i].rssi > -80 {
|
||
|
|
c = yellow
|
||
|
|
}
|
||
|
|
|
||
|
|
tinyfont.WriteLine(&display, &freesans.Regular9pt7b, 5, y, name+rssi, c)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func must(action string, err error) {
|
||
|
|
if err != nil {
|
||
|
|
panic("failed to " + action + ": " + err.Error())
|
||
|
|
}
|
||
|
|
}
|