Skip to content

Instantly share code, notes, and snippets.

@tzechienchu
Last active July 7, 2021 09:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tzechienchu/3685e7a2b6680b86f11eaaa4bc03e98c to your computer and use it in GitHub Desktop.
Save tzechienchu/3685e7a2b6680b86f11eaaa4bc03e98c to your computer and use it in GitHub Desktop.
Wio Terminal Goroutine on Button/Timer/Lite ADC
package main
import (
"fmt"
"image/color"
"machine"
"sync"
"time"
"tinygo.org/x/drivers/ili9341"
)
var (
led = machine.LED
led1 = machine.BCM27
btnA = machine.WIO_KEY_A
btnB = machine.WIO_KEY_B
btnC = machine.WIO_KEY_C
display *ili9341.Device
)
var (
black = color.RGBA{0, 0, 0, 255}
gray = color.RGBA{32, 32, 32, 255}
white = color.RGBA{255, 255, 255, 255}
red = color.RGBA{255, 0, 0, 255}
blue = color.RGBA{0, 0, 255, 255}
green = color.RGBA{0, 255, 0, 255}
)
func initialize() error {
machine.SPI3.Configure(machine.SPIConfig{
SCK: machine.LCD_SCK_PIN,
SDO: machine.LCD_SDO_PIN,
SDI: machine.LCD_SDI_PIN,
Frequency: 48000000,
})
backlight := machine.LCD_BACKLIGHT
backlight.Configure(machine.PinConfig{Mode: machine.PinOutput})
display = ili9341.NewSPI(
machine.SPI3,
machine.LCD_DC,
machine.LCD_SS_PIN,
machine.LCD_RESET,
)
display.Configure(ili9341.Config{
Rotation: ili9341.Rotation270,
})
display.FillScreen(black)
backlight.High()
return nil
}
func errDisp(err error) {
for {
fmt.Printf("%s\r\n", err.Error())
time.Sleep(10 * time.Second)
}
}
func main() {
err := initialize()
if err != nil {
errDisp(err)
}
label1 := NewLabel(240, 0x12)
label2 := NewLabel(240, 0x12)
label3A := NewLabel(150, 0x12)
label3B := NewLabel(70, 0x12)
label3C := NewLabel(70, 0x12)
label4 := NewLabel(240, 0x12)
done := make(chan interface{})
defer close(done)
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
btnA.Configure(machine.PinConfig{Mode: machine.PinInput})
btnB.Configure(machine.PinConfig{Mode: machine.PinInput})
btnC.Configure(machine.PinConfig{Mode: machine.PinInput})
chBtnA := pinDebounce(done, btnA, time.Duration(10))
chBtnB := pinDebounce(done, btnB, time.Duration(10))
chBtnC := pinDebounce(done, btnC, time.Duration(10))
chSLiteRaw := readLightSensor(done, time.Duration(100))
chSLite := lowPass(done, chSLiteRaw)
chans := fork2(done, chSLite)
chBuffer := buffer(done, 32, chans[1])
chCnt1 := timerFunc(done, time.Duration(100))
chanCnt1s := fork2(done, chCnt1)
chGroup15 := group(done, 10, chanCnt1s[0])
chCnt2 := timerFunc(done, time.Duration(500))
chanCnt2s := fork2(done, chCnt2)
chGroup22 := group(done, 2, chanCnt2s[0])
chMG12 := merge(done, chGroup15, chGroup22)
//time.Sleep(2000 * time.Millisecond)
for {
select {
case cnt := <-chanCnt1s[1]:
label1.SetText(fmt.Sprintf("timer-100ms: %04X", cnt), white)
display.DrawRGBBitmap(0, 30, label1.buf, label1.w, label1.h)
case cnt := <-chanCnt2s[1]:
label2.SetText(fmt.Sprintf("timer-500ms: %04X", cnt), white)
display.DrawRGBBitmap(0, 50, label2.buf, label2.w, label2.h)
case cnt := <-chMG12:
fmt.Printf("BufMG...: %v \r\n", cnt[0][0])
//case cnt := <-chGroup22:
// fmt.Printf("Buf22...: %v \r\n", cnt)
// case cnt := <-chGroup15:
// fmt.Printf("Buf15...: %v \r\n", cnt)
case btnAV := <-chBtnC:
label3A.SetText(fmt.Sprintf("button: %v", btnAV), white)
display.DrawRGBBitmap(0, 70, label3A.buf, label3A.w, label3A.h)
case btnBV := <-chBtnB:
label3B.SetText(fmt.Sprintf("%v", btnBV), white)
display.DrawRGBBitmap(150, 70, label3B.buf, label3B.w, label3B.h)
case btnCV := <-chBtnA:
label3C.SetText(fmt.Sprintf("%v", btnCV), white)
display.DrawRGBBitmap(220, 70, label3C.buf, label3C.w, label3C.h)
case senLite := <-chans[0]:
label4.SetText(fmt.Sprintf("LiteSensor: %v", senLite), white)
display.DrawRGBBitmap(0, 90, label4.buf, label4.w, label4.h)
case bufferLite := <-chBuffer:
//fmt.Printf("Buf...: %v,%v \r\n", bufferLite[0], bufferLite[1])
display.FillRectangle(0, 120, 320, 120, black)
for i, v := range bufferLite {
display.SetPixel(int16(i)*10, 120+int16(v/40), blue)
}
}
time.Sleep(1 * time.Millisecond)
}
}
func timerFunc(
done <-chan interface{},
delay time.Duration,
) <-chan uint16 {
tStream := make(chan uint16)
cnt := uint16(0)
go func() {
defer close(tStream)
for {
cnt += 1
select {
case <-done:
return
case tStream <- cnt:
}
time.Sleep(delay * time.Millisecond)
}
}()
return tStream
}
func group(
done <-chan interface{},
bsize int,
vStream <-chan uint16,
) <-chan []uint16 {
gStream := make(chan []uint16)
go func() {
defer close(gStream)
buffer := make([]uint16, 0)
for v := range vStream {
select {
case <-done:
return
default:
{
buffer = append(buffer, v)
if len(buffer) == bsize {
gStream <- buffer
buffer = make([]uint16, 0)
}
}
}
}
}()
return gStream
}
func merge(
done <-chan interface{},
ch1 <-chan []uint16,
ch2 <-chan []uint16,
) <-chan [][]uint16 {
out := make(chan [][]uint16)
go func() {
defer close(out)
d := make([][]uint16, 0)
for {
select {
case <-done:
return
case m := <-ch1:
d = append(d, m)
if len(d) == 2 {
out <- d
d = make([][]uint16, 0)
}
case m := <-ch2:
d = append(d, m)
if len(d) == 2 {
out <- d
d = make([][]uint16, 0)
}
default:
}
time.Sleep(20 * time.Millisecond)
}
}()
return out
}
func mergeWait(cs ...<-chan []uint16) <-chan []uint16 {
out := make(chan []uint16)
var wg sync.WaitGroup
wg.Add(len(cs))
for _, c := range cs {
go func(c <-chan []uint16) {
for v := range c {
out <- v
}
wg.Done()
}(c)
}
go func() {
wg.Wait()
close(out)
}()
return out
}
func pinDebounce(
done <-chan interface{},
pin machine.Pin,
delay time.Duration,
) <-chan bool {
pStream := make(chan bool)
btnV := [2]bool{false, false}
go func() {
defer close(pStream)
for {
v1 := !pin.Get()
btnV[0] = v1
select {
case <-done:
return
case pStream <- btnV[0] && btnV[1]:
}
time.Sleep(time.Duration(delay) * time.Millisecond)
btnV[1] = btnV[0]
}
}()
return pStream
}
func readLightSensor(
done <-chan interface{},
delay time.Duration,
) <-chan uint16 {
sensor := machine.ADC{Pin: machine.WIO_LIGHT}
sensor.Configure(machine.ADCConfig{})
pStream := make(chan uint16)
go func() {
defer close(pStream)
for {
val := sensor.Get()
select {
case <-done:
return
case pStream <- val:
}
time.Sleep(time.Duration(delay) * time.Millisecond)
}
}()
return pStream
}
func lowPass(
done <-chan interface{},
vStream <-chan uint16,
) <-chan uint16 {
iStream := make(chan uint16)
his := uint16(0)
fir := func(val uint16) uint16 {
his = (his * 6 / 10) + (val * 4 / 10)
return his
}
go func() {
defer close(iStream)
for v := range vStream {
select {
case <-done:
return
case iStream <- fir(v):
}
}
}()
return iStream
}
func fork2(
done <-chan interface{},
vStream <-chan uint16,
) [2]chan uint16 {
var chans [2]chan uint16
for i := range chans {
chans[i] = make(chan uint16)
}
closeChans := func(chans [2]chan uint16) {
for i := range chans {
close(chans[i])
}
}
go func() {
defer closeChans(chans)
for v := range vStream {
select {
case <-done:
return
default:
{
for i := range chans {
chans[i] <- v
}
}
}
}
}()
return chans
}
func buffer(
done <-chan interface{},
bsize int,
vStream <-chan uint16,
) <-chan []uint16 {
buffer := make([]uint16, bsize)
addBuffer := func(d uint16) []uint16 {
buffer = buffer[1:]
buffer = append(buffer, d)
return buffer
}
bStream := make(chan []uint16)
go func() {
defer close(bStream)
for v := range vStream {
select {
case <-done:
return
case bStream <- addBuffer(v):
}
}
}()
return bStream
}
// func pinInterruptChan(pin machine.Pin) <-chan bool {
// var state volatile.Register8
// ch := make(chan bool)
// pin.SetInterrupt(machine.PinToggle, func(p machine.Pin) {
// b := false
// if state.Get() != 1 {
// state.Set(1)
// b = true
// } else {
// state.Set(0)
// }
// select {
// case ch <- b:
// default:
// }
// })
// return ch
// }
@tzechienchu
Copy link
Author

Add

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment