Files
cheesy-arena-lite/lights.go

259 lines
7.7 KiB
Go
Raw Normal View History

// Copyright 2014 Team 254. All Rights Reserved.
// Author: pat@patfairbank.com (Patrick Fairbank)
//
// Methods for controlling the field LED lighting.
package main
import (
2014-08-23 21:42:23 -07:00
"log"
"net"
2014-08-28 00:12:45 -07:00
"time"
)
2016-08-14 02:37:10 -07:00
const (
RED_DEFENSE = "redDefense"
BLUE_DEFENSE = "blueDefense"
)
2014-08-28 00:12:45 -07:00
type LightPacket [32]byte
2014-08-23 21:42:23 -07:00
type Lights struct {
connections map[string]*net.Conn
packets map[string]*LightPacket
oldPackets map[string]*LightPacket
newConnections bool
2014-08-28 00:12:45 -07:00
currentMode string
animationCount int
}
// Sets the color by name and transition time for the given LED channel.
2014-08-28 00:12:45 -07:00
func (lightPacket *LightPacket) setColorFade(channel int, color string, fade byte) {
2014-08-23 21:42:23 -07:00
switch color {
2014-08-28 00:12:45 -07:00
case "off":
lightPacket.setRgbFade(channel, 0, 0, 0, fade)
case "white":
lightPacket.setRgbFade(channel, 15, 15, 15, fade)
2014-08-23 21:42:23 -07:00
case "red":
2014-08-28 00:12:45 -07:00
lightPacket.setRgbFade(channel, 15, 0, 0, fade)
2014-08-23 21:42:23 -07:00
case "blue":
2014-08-28 00:12:45 -07:00
lightPacket.setRgbFade(channel, 0, 0, 15, fade)
case "green":
lightPacket.setRgbFade(channel, 0, 15, 0, fade)
2014-08-23 21:42:23 -07:00
case "yellow":
2014-08-28 00:12:45 -07:00
lightPacket.setRgbFade(channel, 15, 11, 0, fade)
case "darkred":
lightPacket.setRgbFade(channel, 1, 0, 0, fade)
case "darkblue":
lightPacket.setRgbFade(channel, 0, 0, 1, fade)
}
2014-08-23 21:42:23 -07:00
}
// Sets the color by name with instant transition for the given LED channel.
2014-08-28 00:12:45 -07:00
func (lightPacket *LightPacket) setColor(channel int, color string) {
lightPacket.setColorFade(channel, color, 0)
}
// Sets the color by RGB values and transition time for the given LED channel.
2014-08-28 00:12:45 -07:00
func (lightPacket *LightPacket) setRgbFade(channel int, red byte, green byte, blue byte, fade byte) {
lightPacket[channel*4] = red
lightPacket[channel*4+1] = green
lightPacket[channel*4+2] = blue
lightPacket[channel*4+3] = fade
}
// Sets the color by name with instant transition for all LED channels.
2014-08-28 00:12:45 -07:00
func (lightPacket *LightPacket) setAllColor(color string) {
lightPacket.setAllColorFade(color, 0)
}
// Sets the color by name and transition time for all LED channels.
2014-08-28 00:12:45 -07:00
func (lightPacket *LightPacket) setAllColorFade(color string, fade byte) {
for i := 0; i < 8; i++ {
lightPacket.setColorFade(i, color, fade)
}
2014-08-23 21:42:23 -07:00
}
func (lights *Lights) Setup() error {
2014-08-28 00:12:45 -07:00
lights.currentMode = "off"
2014-08-23 21:42:23 -07:00
err := lights.SetupConnections()
if err != nil {
return err
}
2014-08-23 21:42:23 -07:00
lights.packets = make(map[string]*LightPacket)
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE] = &LightPacket{}
lights.packets[BLUE_DEFENSE] = &LightPacket{}
2014-08-23 21:42:23 -07:00
lights.oldPackets = make(map[string]*LightPacket)
2016-08-14 02:37:10 -07:00
lights.oldPackets[RED_DEFENSE] = &LightPacket{}
lights.oldPackets[BLUE_DEFENSE] = &LightPacket{}
2014-08-23 21:42:23 -07:00
lights.sendLights()
2014-08-28 00:12:45 -07:00
// Set up a goroutine to animate the lights when necessary.
ticker := time.NewTicker(time.Millisecond * 50)
go func() {
for _ = range ticker.C {
lights.animate()
}
}()
2014-08-23 21:42:23 -07:00
return nil
}
2014-08-23 21:42:23 -07:00
func (lights *Lights) SetupConnections() error {
lights.connections = make(map[string]*net.Conn)
2016-08-14 02:37:10 -07:00
if err := lights.connect(RED_DEFENSE, eventSettings.RedDefenseLightsAddress); err != nil {
return err
}
if err := lights.connect(BLUE_DEFENSE, eventSettings.BlueDefenseLightsAddress); err != nil {
return err
}
lights.newConnections = true
return nil
}
2016-08-14 02:37:10 -07:00
func (lights *Lights) connect(controller, address string) error {
2014-08-23 21:42:23 -07:00
// Don't enable lights for a side if the controller address is not configured.
2016-08-14 02:37:10 -07:00
if len(address) != 0 {
conn, err := net.Dial("udp4", address)
lights.connections[controller] = &conn
2014-08-23 21:42:23 -07:00
if err != nil {
return err
}
} else {
2016-08-14 02:37:10 -07:00
lights.connections[controller] = nil
}
2014-08-23 21:42:23 -07:00
return nil
}
2016-08-14 02:37:10 -07:00
func (lights *Lights) ClearAll() {
lights.packets[RED_DEFENSE].setAllColorFade("off", 10)
lights.packets[BLUE_DEFENSE].setAllColorFade("off", 10)
lights.sendLights()
}
// Turns all lights green to signal that the field is safe to enter.
func (lights *Lights) SetFieldReset() {
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE].setAllColor("green")
lights.packets[BLUE_DEFENSE].setAllColor("green")
lights.sendLights()
}
// Sets the lights to the given non-match mode for show or testing.
2014-08-28 00:12:45 -07:00
func (lights *Lights) SetMode(mode string) {
lights.currentMode = mode
lights.animationCount = 0
switch mode {
case "off":
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE].setAllColor("off")
lights.packets[BLUE_DEFENSE].setAllColor("off")
2014-08-28 00:12:45 -07:00
case "all_white":
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE].setAllColor("white")
lights.packets[BLUE_DEFENSE].setAllColor("white")
2014-08-28 00:12:45 -07:00
case "all_red":
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE].setAllColor("red")
lights.packets[BLUE_DEFENSE].setAllColor("red")
2014-08-28 00:12:45 -07:00
case "all_green":
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE].setAllColor("green")
lights.packets[BLUE_DEFENSE].setAllColor("green")
2014-08-28 00:12:45 -07:00
case "all_blue":
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE].setAllColor("blue")
lights.packets[BLUE_DEFENSE].setAllColor("blue")
}
2014-08-23 21:42:23 -07:00
lights.sendLights()
}
// Sends a control packet to the LED controllers only if their state needs to be updated.
2014-08-23 21:42:23 -07:00
func (lights *Lights) sendLights() {
2016-08-14 02:37:10 -07:00
for controller, connection := range lights.connections {
if lights.newConnections || *lights.packets[controller] != *lights.oldPackets[controller] {
if connection != nil {
2016-08-14 02:37:10 -07:00
_, err := (*connection).Write(lights.packets[controller][:])
if err != nil {
2016-08-14 02:37:10 -07:00
log.Printf("Failed to send %s light packet.", controller)
}
2014-08-23 21:42:23 -07:00
}
}
2016-08-14 02:37:10 -07:00
*lights.oldPackets[controller] = *lights.packets[controller]
}
2014-08-23 21:42:23 -07:00
lights.newConnections = false
}
2014-08-28 00:12:45 -07:00
// State machine for controlling light sequences in the non-match modes.
2014-08-28 00:12:45 -07:00
func (lights *Lights) animate() {
lights.animationCount += 1
switch lights.currentMode {
case "strobe":
switch lights.animationCount {
case 1:
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE].setAllColor("white")
lights.packets[BLUE_DEFENSE].setAllColor("off")
2014-08-28 00:12:45 -07:00
case 2:
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE].setAllColor("off")
lights.packets[BLUE_DEFENSE].setAllColor("white")
2014-08-28 00:12:45 -07:00
fallthrough
default:
lights.animationCount = 0
}
lights.sendLights()
case "fade_red":
if lights.animationCount == 1 {
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE].setAllColorFade("red", 18)
lights.packets[BLUE_DEFENSE].setAllColorFade("red", 18)
2014-08-28 00:12:45 -07:00
} else if lights.animationCount == 61 {
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE].setAllColorFade("darkred", 18)
lights.packets[BLUE_DEFENSE].setAllColorFade("darkred", 18)
2014-08-28 00:12:45 -07:00
} else if lights.animationCount > 120 {
lights.animationCount = 0
}
lights.sendLights()
case "fade_blue":
if lights.animationCount == 1 {
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE].setAllColorFade("blue", 18)
lights.packets[BLUE_DEFENSE].setAllColorFade("blue", 18)
2014-08-28 00:12:45 -07:00
} else if lights.animationCount == 61 {
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE].setAllColorFade("darkblue", 18)
lights.packets[BLUE_DEFENSE].setAllColorFade("darkblue", 18)
2014-08-28 00:12:45 -07:00
} else if lights.animationCount > 120 {
lights.animationCount = 0
}
lights.sendLights()
case "fade_red_blue":
if lights.animationCount == 1 {
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE].setAllColorFade("blue", 18)
lights.packets[BLUE_DEFENSE].setAllColorFade("darkred", 18)
2014-08-28 00:12:45 -07:00
} else if lights.animationCount == 61 {
2016-08-14 02:37:10 -07:00
lights.packets[RED_DEFENSE].setAllColorFade("darkblue", 18)
lights.packets[BLUE_DEFENSE].setAllColorFade("red", 18)
2014-08-28 00:12:45 -07:00
} else if lights.animationCount > 120 {
lights.animationCount = 0
}
lights.sendLights()
}
}
2016-08-14 02:37:10 -07:00
// Turns on the lights below the defenses, with one channel per defense.
func (lights *Lights) SetDefenses(redDefensesStrength, blueDefensesStrength [5]int) {
for i := 0; i < 5; i++ {
if redDefensesStrength[i] == 0 {
lights.packets[RED_DEFENSE].setColorFade(i, "off", 10)
} else if redDefensesStrength[i] == 1 {
lights.packets[RED_DEFENSE].setColorFade(i, "yellow", 10)
} else {
lights.packets[RED_DEFENSE].setColorFade(i, "red", 10)
}
if blueDefensesStrength[i] == 0 {
lights.packets[BLUE_DEFENSE].setColorFade(i, "off", 10)
} else if blueDefensesStrength[i] == 1 {
lights.packets[BLUE_DEFENSE].setColorFade(i, "yellow", 10)
} else {
lights.packets[BLUE_DEFENSE].setColorFade(i, "blue", 10)
}
}
lights.sendLights()
}