LEDController/cmd/ledcontroller-server/main.go

170 lines
6.2 KiB
Go
Raw Normal View History

package main
import (
"fmt"
"log"
"math"
"os"
"strconv"
"time"
patterns "git.martyn.berlin/martyn/LEDController/internal/patterns"
queue "git.martyn.berlin/martyn/LEDController/internal/queue"
remapping "git.martyn.berlin/martyn/LEDController/internal/remapping"
webserver "git.martyn.berlin/martyn/LEDController/internal/webserver"
"github.com/Hundemeier/go-sacn/sacn"
)
type RGBcolor = [3]byte
var currentFrame [2][512]byte
var channels [2]chan<- [512]byte
var sema = make(chan struct{}, 1) // a binary semaphore guarding currentFrame
var currentEffect queue.QueueItem
var globalEffectChannel = make(chan queue.QueueItem, 1024)
func foreverLoop() {
for /*ever*/ {
time.Sleep(40 * time.Millisecond) //25fps
for u := 0; u < 2; u++ {
sema <- struct{}{} // acquire token
channels[u] <- currentFrame[u]
<-sema
}
}
}
func reduceBrightness(universe [512]byte, percentage int) [512]byte {
for i := range universe {
universe[i] = byte(float64(universe[i]) * (float64(percentage) / float64(100)))
}
return universe
}
var universeCount int = 0
func main() {
go func() {
var err error
listenPort := 5353
if os.Getenv("LISTEN_PORT") != "" {
listenPort, err = strconv.Atoi(os.Getenv("LISTEN_PORT"))
if err != nil {
listenPort = 5353
}
}
fmt.Printf("Starting webserver on port %d\n", listenPort)
webserver.HandleHTTP(globalEffectChannel, listenPort)
}()
PanelIP := os.Getenv("PANEL_IP")
if PanelIP == "" {
PanelIP = "127.0.0.1"
}
PanelWidth, err := strconv.Atoi(os.Getenv("PANEL_WIDTH"))
if err != nil {
PanelWidth = 68
}
PanelHeight, err := strconv.Atoi(os.Getenv("PANEL_HEIGHT"))
if err != nil {
PanelHeight = 4
}
universeCount = int(math.Ceil(float64(PanelHeight*PanelWidth*3) / 510))
fmt.Printf("Universe count is %d", universeCount)
PanelBrightness, err := strconv.Atoi(os.Getenv("PANEL_BRIGHTNESS"))
if err != nil {
PanelBrightness = 100
}
//instead of "" you could provide an ip-address that the socket should bind to
trans, err := sacn.NewTransmitter("", [16]byte{1, 2}, "test")
if err != nil {
log.Fatal(err)
}
//activates the universes
for i := 0; i < universeCount; i++ {
channels[i], err = trans.Activate(uint16(i + 1))
//deactivate the channel on exit
defer close(channels[i])
trans.SetMulticast(uint16(i+1), false) //this specific setup will not multicast on windows,
trans.SetDestinations(uint16(i+1), []string{PanelIP})
}
// Plasma for start frame
/*rearranged := reduceBrightness(remapping.SliceRearrange(PanelWidth, PanelHeight, true, remapping.XYGridToLinear(PanelWidth, PanelHeight, patterns.PlasmaPanel(PanelWidth, PanelHeight, 40))), PanelBrightness)
for i := 0; i < universeCount; i++ {
currentFrame[i] = remapping.Slice512(rearranged[i])
}*/
var e queue.QueueItem
e.Effect = "red"
e.Duration = 40 * 50
globalEffectChannel <- e
e.Effect = "colour"
e.Duration = 40 * 10
e.SeedColour[0] = 0
e.SeedColour[1] = 255
e.SeedColour[2] = 0
globalEffectChannel <- e
e.Effect = "default"
globalEffectChannel <- e
go func() {
for /*ever*/ {
if currentEffect.Duration > 0 {
currentEffect.Duration -= 40
} else {
if len(globalEffectChannel) > 0 {
currentEffect = <-globalEffectChannel
}
}
var rearranged [][]byte
switch currentEffect.Effect {
case "line":
rearranged = remapping.SliceRearrange(PanelWidth, PanelHeight, true, remapping.XYGridToLinear(PanelWidth, PanelHeight, patterns.ZigZag(PanelWidth, PanelHeight)))
case "plasma":
rearranged = remapping.SliceRearrange(PanelWidth, PanelHeight, true, remapping.XYGridToLinear(PanelWidth, PanelHeight, patterns.PlasmaPanel(PanelWidth, PanelHeight, currentEffect.Speed)))
case "red":
rearranged = remapping.SliceRearrange(PanelWidth, PanelHeight, false, remapping.XYGridToLinear(PanelWidth, PanelHeight, patterns.RedPanel(PanelWidth, PanelHeight)))
case "random":
rearranged = remapping.SliceRearrange(PanelWidth, PanelHeight, false, remapping.XYGridToLinear(PanelWidth, PanelHeight, patterns.RandomColourPanel(PanelWidth, PanelHeight, currentEffect.Speed)))
case "linearplasma":
rearranged = remapping.SliceRearrange(PanelWidth, PanelHeight, false, patterns.LinearPlasma(PanelWidth*PanelHeight))
case "gradientred":
rearranged = remapping.SliceRearrange(PanelWidth, PanelHeight, false, patterns.Gradient(255, 0, 0, 0, 0, 255, 0, PanelWidth*PanelHeight))
case "sine":
var black patterns.RGBcolor
var red patterns.RGBcolor
red[0] = 255
rearranged = remapping.SliceRearrange(PanelWidth, PanelHeight, true, remapping.XYGridToLinear(PanelWidth, PanelHeight, patterns.Sinewave(PanelWidth, PanelHeight, black, red, currentEffect.Speed)))
case "sinechase":
var black patterns.RGBcolor
var red patterns.RGBcolor
red[0] = 255
rearranged = remapping.SliceRearrange(PanelWidth, PanelHeight, true, remapping.XYGridToLinear(PanelWidth, PanelHeight, patterns.SineChase(PanelWidth, PanelHeight, black, red, currentEffect.Speed)))
case "plasmapulse":
rearranged = remapping.SliceRearrange(PanelWidth, PanelHeight, false, remapping.XYGridToLinear(PanelWidth, PanelHeight, patterns.PlasmaColourPanel(PanelWidth, PanelHeight, currentEffect.Speed)))
case "colour":
rearranged = remapping.SliceRearrange(PanelWidth, PanelHeight, false, remapping.XYGridToLinear(PanelWidth, PanelHeight, patterns.FillPanel(PanelWidth, PanelHeight, currentEffect.SeedColour[0], currentEffect.SeedColour[1], currentEffect.SeedColour[2])))
case "fade":
rearranged = remapping.SliceRearrange(PanelWidth, PanelHeight, true, remapping.XYGridToLinear(PanelWidth, PanelHeight, patterns.GradientPanel(PanelWidth, PanelHeight, currentEffect.SeedColour, currentEffect.SecondColour)))
default:
rearranged = remapping.SliceRearrange(PanelWidth, PanelHeight, false, remapping.XYGridToLinear(PanelWidth, PanelHeight, patterns.FillPanel(PanelWidth, PanelHeight, 128, 0, 128)))
}
//rearranged := remapping.SliceRearrange(PanelWidth,PanelHeight,true,linearPlasma(PanelWidth*PanelHeight))
sema <- struct{}{} // acquire token
for i := 0; i < universeCount; i++ {
currentFrame[i] = reduceBrightness(remapping.Slice512(rearranged[i]), PanelBrightness)
}
<-sema
time.Sleep(40 * time.Millisecond)
}
}()
foreverLoop()
}