Compare commits

...

10 Commits

Author SHA1 Message Date
10db8f6d89
implement party mode 2024-04-03 00:57:50 -06:00
4a29e0c600
swap inside brightness and party buttons
- The outside button is next to the outside light, but not the inside button. This moves it beside the light and puts the party button in the middle (on the prototype board)
2024-04-03 00:56:44 -06:00
69042cbe9c
make brightness values configurable
- Also simplify the cycleBrightness() function with a loop
- Adjusted some of the brightness values
2024-04-02 23:57:32 -06:00
972b395f5d
better encapsulate InitPWM() 2024-04-02 23:43:42 -06:00
772ac6a8d8
add select block to button press channel
- outchan is unbuffered, so drop the message if there's already one sitting there.
2024-04-02 16:53:35 -06:00
67607347e4
remove time.Sleep() calls
- time.Sleep() blocks the entire program, other goroutines won't run. Instead, watch the button channels and filter out any extra presses within too short of a time.
2024-04-02 12:58:16 -06:00
3c4b177360
remove redundant goroutines watching brightness changes 2024-04-01 07:08:47 -06:00
bbd231b2eb
change ledset to a receiver on led 2024-04-01 06:25:20 -06:00
856a6e2d88
refactor lighthardware struct
- add led struct for individual colour LEDs
2024-04-01 06:19:19 -06:00
32d03ddd05
refactor to support multiple modes 2024-04-01 03:46:42 -06:00

347
main.go
View File

@ -2,6 +2,7 @@ package main
import (
"machine"
"runtime"
"time"
)
@ -11,32 +12,44 @@ type pwm interface {
Channel(machine.Pin) (uint8, error)
}
type led struct {
pin machine.Pin
pwm pwm
channel uint8
}
func (l *led) InitPWM() error {
var err error
l.channel, err = l.pwm.Channel(l.pin)
return err
}
func (l *led) set(brightness uint32) {
l.pwm.Set(l.channel, (l.pwm.Top()/brightnesspeak)*brightness)
}
type lighthardware struct {
rPin machine.Pin
gPin machine.Pin
bPin machine.Pin
rPwm pwm
gPwm pwm
bPwm pwm
rCh uint8
gCh uint8
bCh uint8
red led
green led
blue led
}
func (lhw *lighthardware) InitPWM() error {
var err error
lhw.rCh, err = lhw.rPwm.Channel(lhw.rPin)
err = lhw.red.InitPWM()
if err != nil {
return err
}
lhw.gCh, err = lhw.gPwm.Channel(lhw.gPin)
err = lhw.green.InitPWM()
if err != nil {
return err
}
lhw.bCh, err = lhw.bPwm.Channel(lhw.bPin)
err = lhw.blue.InitPWM()
if err != nil {
return err
}
@ -44,15 +57,36 @@ func (lhw *lighthardware) InitPWM() error {
return nil
}
type lightSet struct {
inside *lighthardware
inside2 *lighthardware
outside *lighthardware
}
type brightnesses struct {
inside uint32
outside uint32
}
var (
brightnessSteps = []uint32{0, 255, 100, 20}
)
const (
period = uint64(1e9 / 500)
pressdelay = time.Millisecond * 500
brightnesspeak = uint32(255)
pressdelay = time.Millisecond * 300
brightnesspeak = uint32(256)
defaultrng = uint32(time.Millisecond * 250)
maxrng = uint32(time.Millisecond * 500)
minrng = uint32(time.Millisecond * 50)
)
func main() {
errs := make(chan error)
outsidepushed_raw := make(chan bool)
insidepushed_raw := make(chan bool)
partypushed_raw := make(chan bool)
outsidepushed := make(chan bool)
insidepushed := make(chan bool)
partypushed := make(chan bool)
@ -61,8 +95,8 @@ func main() {
insidebrightness := make(chan uint32, 2)
outsidebutton := machine.GP22
insidebutton := machine.GP21
partybutton := machine.GP20
insidebutton := machine.GP20
partybutton := machine.GP21
outsidebutton.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
insidebutton.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
@ -70,23 +104,27 @@ func main() {
outsidebutton.SetInterrupt(machine.PinFalling, func(p machine.Pin) {
select {
case outsidepushed <- true:
case outsidepushed_raw <- true:
default:
}
})
insidebutton.SetInterrupt(machine.PinFalling, func(p machine.Pin) {
select {
case insidepushed <- true:
case insidepushed_raw <- true:
default:
}
})
partybutton.SetInterrupt(machine.PinFalling, func(p machine.Pin) {
select {
case partypushed <- true:
case partypushed_raw <- true:
default:
}
})
go delayChan(outsidepushed_raw, outsidepushed)
go delayChan(insidepushed_raw, insidepushed)
go delayChan(partypushed_raw, partypushed)
pwm2 := machine.PWM2
pwm2.Configure(machine.PWMConfig{
Period: period,
@ -109,12 +147,18 @@ func main() {
})
insideLight := lighthardware{
rPin: machine.GP11,
gPin: machine.GP13,
bPin: machine.GP12,
rPwm: pwm5,
gPwm: pwm6,
bPwm: pwm6,
red: led{
pin: machine.GP11,
pwm: pwm5,
},
green: led{
pin: machine.GP13,
pwm: pwm6,
},
blue: led{
pin: machine.GP12,
pwm: pwm6,
},
}
err := insideLight.InitPWM()
@ -122,12 +166,18 @@ func main() {
errs <- err
} else {
insideLight2 := lighthardware{
rPin: machine.GP8,
gPin: machine.GP10,
bPin: machine.GP9,
rPwm: pwm4,
gPwm: pwm5,
bPwm: pwm4,
red: led{
pin: machine.GP8,
pwm: pwm4,
},
green: led{
pin: machine.GP10,
pwm: pwm5,
},
blue: led{
pin: machine.GP9,
pwm: pwm4,
},
}
err = insideLight2.InitPWM()
@ -135,21 +185,33 @@ func main() {
errs <- err
} else {
outsideLight := lighthardware{
rPin: machine.GP5,
gPin: machine.GP7,
bPin: machine.GP6,
rPwm: pwm2,
gPwm: pwm3,
bPwm: pwm3,
red: led{
pin: machine.GP5,
pwm: pwm2,
},
green: led{
pin: machine.GP7,
pwm: pwm3,
},
blue: led{
pin: machine.GP6,
pwm: pwm3,
},
}
err = outsideLight.InitPWM()
if err != nil {
errs <- err
} else {
lights := lightSet{
inside: &insideLight,
inside2: &insideLight2,
outside: &outsideLight,
}
go cycleBrightness(insidepushed, insidebrightness)
go cycleBrightness(outsidepushed, outsidebrightness)
go loop(&insideLight, &insideLight2, &outsideLight, insidebrightness, outsidebrightness)
go loop(lights, insidebrightness, outsidebrightness, partypushed)
}
}
}
@ -157,66 +219,195 @@ func main() {
println((<-errs).Error())
}
func cycleBrightness(pushchan chan bool, brightnesschan chan uint32) {
brightnesschan <- 0
func delayChan(inchan <-chan bool, outchan chan<- bool) {
var last time.Time
for {
<-pushchan
brightnesschan <- 255
time.Sleep(pressdelay)
<-pushchan
brightnesschan <- 120
time.Sleep(pressdelay)
<-pushchan
brightnesschan <- 30
time.Sleep(pressdelay)
<-pushchan
brightnesschan <- 0
time.Sleep(pressdelay)
val := <-inchan
now := time.Now()
if now.Sub(last) > pressdelay {
last = now
select {
case outchan <- val:
default:
}
}
}
}
func ledset(lpwm pwm, ledch uint8, brightness uint32) {
lpwm.Set(ledch, (lpwm.Top()/brightnesspeak)*brightness)
func cycleBrightness(pushchan <-chan bool, brightnesschan chan<- uint32) {
for {
for _, b := range brightnessSteps {
brightnesschan <- b
<-pushchan
}
}
}
func loop(inside *lighthardware, inside2 *lighthardware, outside *lighthardware, insidebrightness chan uint32, outsidebrightness chan uint32) {
func loop(lights lightSet, insidebrightness chan uint32, outsidebrightness chan uint32, partypushed <-chan bool) {
partyChange := make(chan bool)
lastBrightness := make(chan brightnesses)
for {
go normal(lights, insidebrightness, outsidebrightness, partyChange, lastBrightness)
<-partypushed
partyChange <- true
lb := <-lastBrightness
insidebrightness <- lb.inside
outsidebrightness <- lb.outside
go party(lights, insidebrightness, outsidebrightness, partyChange, lastBrightness)
<-partypushed
partyChange <- true
lb = <-lastBrightness
insidebrightness <- lb.inside
outsidebrightness <- lb.outside
}
}
func normal(lights lightSet, inBrightChange <-chan uint32, outBrightChange <-chan uint32, partyChange <-chan bool, lastBrightness chan<- brightnesses) {
var brightIn uint32
var brightOut uint32
inBrightChange := make(chan bool)
outBrightChange := make(chan bool)
go func() {
for {
brightIn = <-insidebrightness
select {
case inBrightChange <- true:
case brightIn = <-inBrightChange:
setNormal(lights.inside, brightIn)
setNormal(lights.inside2, brightIn)
case brightOut = <-outBrightChange:
setNormal(lights.outside, brightOut)
case <-partyChange:
lastBrightness <- brightnesses{inside: brightIn, outside: brightOut}
return
}
}
}
func setNormal(light *lighthardware, brightness uint32) {
light.red.set(brightness)
light.green.set(brightness)
light.blue.set(brightness)
}
func party(lights lightSet, inBrightChange <-chan uint32, outBrightChange <-chan uint32, partyChange <-chan bool, lastBrightness chan<- brightnesses) {
var brightIn uint32
var brightOut uint32
inBright := make(chan uint32, 1)
in2Bright := make(chan uint32, 1)
outBright := make(chan uint32, 1)
partysOver := make(chan bool, 3)
partysDone := make(chan bool, 3)
go partyLight(lights.inside, inBright, partysOver, partysDone)
go partyLight(lights.inside2, in2Bright, partysOver, partysDone)
go partyLight(lights.outside, outBright, partysOver, partysDone)
runtime.Gosched()
for {
select {
case brightIn = <-inBrightChange:
inBright <- brightIn
in2Bright <- brightIn
case brightOut = <-outBrightChange:
outBright <- brightOut
case <-partyChange:
partysOver <- true
partysOver <- true
partysOver <- true
runtime.Gosched()
<-partysDone
<-partysDone
<-partysDone
lastBrightness <- brightnesses{inside: brightIn, outside: brightOut}
return
}
}
}
func partyLight(light *lighthardware, brightChange <-chan uint32, endParty <-chan bool, partyEnded chan<- bool) {
rBright := make(chan uint32, 1)
gBright := make(chan uint32, 1)
bBright := make(chan uint32, 1)
partysOver := make(chan bool, 3)
partysDone := make(chan bool, 3)
go partyColour(light.red, rBright, partysOver, partysDone)
go partyColour(light.green, gBright, partysOver, partysDone)
go partyColour(light.blue, bBright, partysOver, partysDone)
runtime.Gosched()
for {
select {
case brightness := <-brightChange:
rBright <- brightness
gBright <- brightness
bBright <- brightness
case <-endParty:
partysOver <- true
partysOver <- true
partysOver <- true
runtime.Gosched()
<-partysDone
<-partysDone
<-partysDone
partyEnded <- true
return
}
}
}
func partyColour(light led, brightChange <-chan uint32, endParty <-chan bool, partyEnded chan<- bool) {
brightness := <-brightChange
LOOP:
for {
if brightness > 0 {
r, err := machine.GetRNG()
if err != nil {
r = defaultrng
}
r = (r % maxrng) + minrng
delaytime := time.Duration(r / brightness)
for i := brightness; i > 0; i-- {
light.set(i)
runtime.Gosched()
time.Sleep(delaytime)
select {
case brightness = <-brightChange:
continue LOOP
case <-endParty:
partyEnded <- true
return
default:
}
}
}()
go func() {
for {
brightOut = <-outsidebrightness
for i := uint32(0); i <= brightness; i++ {
light.set(i)
runtime.Gosched()
time.Sleep(delaytime)
select {
case outBrightChange <- true:
case brightness = <-brightChange:
continue LOOP
case <-endParty:
partyEnded <- true
return
default:
}
}
}()
for {
} else {
light.set(0)
select {
case <-inBrightChange:
normal(inside, brightIn)
normal(inside2, brightIn)
case <-outBrightChange:
normal(outside, brightOut)
case brightness = <-brightChange:
continue
case <-endParty:
partyEnded <- true
return
}
}
}
func normal(light *lighthardware, brightness uint32) {
ledset(light.rPwm, light.rCh, brightness)
ledset(light.gPwm, light.gCh, brightness)
ledset(light.bPwm, light.bCh, brightness)
}