414 lines
8.3 KiB
Go
414 lines
8.3 KiB
Go
package main
|
|
|
|
import (
|
|
"machine"
|
|
"runtime"
|
|
"time"
|
|
)
|
|
|
|
type pwm interface {
|
|
Top() uint32
|
|
Set(uint8, uint32)
|
|
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 {
|
|
red led
|
|
green led
|
|
blue led
|
|
}
|
|
|
|
func (lhw *lighthardware) InitPWM() error {
|
|
var err error
|
|
|
|
err = lhw.red.InitPWM()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = lhw.green.InitPWM()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = lhw.blue.InitPWM()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
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 * 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)
|
|
|
|
outsidebrightness := make(chan uint32, 2)
|
|
insidebrightness := make(chan uint32, 2)
|
|
|
|
outsidebutton := machine.GP22
|
|
insidebutton := machine.GP20
|
|
partybutton := machine.GP21
|
|
|
|
outsidebutton.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
|
insidebutton.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
|
partybutton.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
|
|
|
outsidebutton.SetInterrupt(machine.PinFalling, func(p machine.Pin) {
|
|
select {
|
|
case outsidepushed_raw <- true:
|
|
default:
|
|
}
|
|
})
|
|
insidebutton.SetInterrupt(machine.PinFalling, func(p machine.Pin) {
|
|
select {
|
|
case insidepushed_raw <- true:
|
|
default:
|
|
}
|
|
})
|
|
partybutton.SetInterrupt(machine.PinFalling, func(p machine.Pin) {
|
|
select {
|
|
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,
|
|
})
|
|
pwm3 := machine.PWM3
|
|
pwm3.Configure(machine.PWMConfig{
|
|
Period: period,
|
|
})
|
|
pwm4 := machine.PWM4
|
|
pwm4.Configure(machine.PWMConfig{
|
|
Period: period,
|
|
})
|
|
pwm5 := machine.PWM5
|
|
pwm5.Configure(machine.PWMConfig{
|
|
Period: period,
|
|
})
|
|
pwm6 := machine.PWM6
|
|
pwm6.Configure(machine.PWMConfig{
|
|
Period: period,
|
|
})
|
|
|
|
insideLight := lighthardware{
|
|
red: led{
|
|
pin: machine.GP11,
|
|
pwm: pwm5,
|
|
},
|
|
green: led{
|
|
pin: machine.GP13,
|
|
pwm: pwm6,
|
|
},
|
|
blue: led{
|
|
pin: machine.GP12,
|
|
pwm: pwm6,
|
|
},
|
|
}
|
|
err := insideLight.InitPWM()
|
|
|
|
if err != nil {
|
|
errs <- err
|
|
} else {
|
|
insideLight2 := lighthardware{
|
|
red: led{
|
|
pin: machine.GP8,
|
|
pwm: pwm4,
|
|
},
|
|
green: led{
|
|
pin: machine.GP10,
|
|
pwm: pwm5,
|
|
},
|
|
blue: led{
|
|
pin: machine.GP9,
|
|
pwm: pwm4,
|
|
},
|
|
}
|
|
err = insideLight2.InitPWM()
|
|
|
|
if err != nil {
|
|
errs <- err
|
|
} else {
|
|
outsideLight := lighthardware{
|
|
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(lights, insidebrightness, outsidebrightness, partypushed)
|
|
}
|
|
}
|
|
}
|
|
|
|
println((<-errs).Error())
|
|
}
|
|
|
|
func delayChan(inchan <-chan bool, outchan chan<- bool) {
|
|
var last time.Time
|
|
|
|
for {
|
|
val := <-inchan
|
|
now := time.Now()
|
|
if now.Sub(last) > pressdelay {
|
|
last = now
|
|
select {
|
|
case outchan <- val:
|
|
default:
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func cycleBrightness(pushchan <-chan bool, brightnesschan chan<- uint32) {
|
|
for {
|
|
for _, b := range brightnessSteps {
|
|
brightnesschan <- b
|
|
<-pushchan
|
|
}
|
|
}
|
|
}
|
|
|
|
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
|
|
|
|
for {
|
|
select {
|
|
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:
|
|
}
|
|
}
|
|
|
|
for i := uint32(0); i <= brightness; i++ {
|
|
light.set(i)
|
|
runtime.Gosched()
|
|
time.Sleep(delaytime)
|
|
|
|
select {
|
|
case brightness = <-brightChange:
|
|
continue LOOP
|
|
case <-endParty:
|
|
partyEnded <- true
|
|
return
|
|
default:
|
|
}
|
|
}
|
|
} else {
|
|
light.set(0)
|
|
select {
|
|
case brightness = <-brightChange:
|
|
continue
|
|
case <-endParty:
|
|
partyEnded <- true
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|