Files
cheesy-arena-lite/lights.go

304 lines
9.0 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"
)
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
hotGoal string
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)
lights.packets["red"] = &LightPacket{}
lights.packets["blue"] = &LightPacket{}
lights.oldPackets = make(map[string]*LightPacket)
lights.oldPackets["red"] = &LightPacket{}
lights.oldPackets["blue"] = &LightPacket{}
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)
2014-08-23 21:42:23 -07:00
// Don't enable lights for a side if the controller address is not configured.
if len(eventSettings.RedGoalLightsAddress) != 0 {
conn, err := net.Dial("udp4", eventSettings.RedGoalLightsAddress)
lights.connections["red"] = &conn
if err != nil {
return err
}
} else {
lights.connections["red"] = nil
2014-08-23 21:42:23 -07:00
}
if len(eventSettings.BlueGoalLightsAddress) != 0 {
conn, err := net.Dial("udp4", eventSettings.BlueGoalLightsAddress)
lights.connections["blue"] = &conn
if err != nil {
return err
}
} else {
lights.connections["blue"] = nil
}
2014-08-23 21:42:23 -07:00
lights.newConnections = true
return nil
}
// Makes a goal for the given alliance hot.
2014-08-23 21:42:23 -07:00
func (lights *Lights) SetHotGoal(alliance string, leftSide bool) {
if leftSide {
2014-08-28 00:12:45 -07:00
lights.packets[alliance].setColor(0, "off")
lights.packets[alliance].setColor(1, "off")
lights.packets[alliance].setColor(2, "off")
2014-08-23 21:42:23 -07:00
lights.packets[alliance].setColor(3, "yellow")
lights.packets[alliance].setColor(4, "yellow")
lights.packets[alliance].setColor(5, "yellow")
lights.hotGoal = "left"
} else {
2014-08-23 21:42:23 -07:00
lights.packets[alliance].setColor(0, "yellow")
lights.packets[alliance].setColor(1, "yellow")
lights.packets[alliance].setColor(2, "yellow")
2014-08-28 00:12:45 -07:00
lights.packets[alliance].setColor(3, "off")
lights.packets[alliance].setColor(4, "off")
lights.packets[alliance].setColor(5, "off")
2014-08-23 21:42:23 -07:00
lights.hotGoal = "right"
}
lights.sendLights()
}
// Lights up the given alliance's goal for the given number of assists.
2014-08-23 21:42:23 -07:00
func (lights *Lights) SetAssistGoal(alliance string, numAssists int) {
2014-08-28 00:12:45 -07:00
lights.packets[alliance].setColor(0, "off")
lights.packets[alliance].setColor(1, "off")
lights.packets[alliance].setColor(2, "off")
lights.packets[alliance].setColor(3, "off")
lights.packets[alliance].setColor(4, "off")
lights.packets[alliance].setColor(5, "off")
2014-08-23 21:42:23 -07:00
if numAssists > 0 {
lights.packets[alliance].setColor(2, alliance)
lights.packets[alliance].setColor(3, alliance)
}
if numAssists > 1 {
lights.packets[alliance].setColor(1, alliance)
lights.packets[alliance].setColor(4, alliance)
}
if numAssists > 2 {
lights.packets[alliance].setColor(0, alliance)
lights.packets[alliance].setColor(5, alliance)
}
2014-08-23 21:42:23 -07:00
lights.hotGoal = ""
lights.sendLights()
}
// Turns off all lights for the given alliance's goal.
2014-08-23 21:42:23 -07:00
func (lights *Lights) ClearGoal(alliance string) {
2014-08-28 00:12:45 -07:00
lights.packets[alliance].setColorFade(0, "off", 10)
lights.packets[alliance].setColorFade(1, "off", 10)
lights.packets[alliance].setColorFade(2, "off", 10)
lights.packets[alliance].setColorFade(3, "off", 10)
lights.packets[alliance].setColorFade(4, "off", 10)
lights.packets[alliance].setColorFade(5, "off", 10)
}
// Turns on the given alliance's pedestal.
2014-08-23 21:42:23 -07:00
func (lights *Lights) SetPedestal(alliance string) {
if alliance == "red" {
lights.packets["blue"].setColor(6, alliance)
} else {
lights.packets["red"].setColor(6, alliance)
}
lights.sendLights()
}
// Turns off the given alliance's pedestal.
2014-08-23 21:42:23 -07:00
func (lights *Lights) ClearPedestal(alliance string) {
if alliance == "red" {
2014-08-28 00:12:45 -07:00
lights.packets["blue"].setColorFade(6, "off", 10)
2014-08-23 21:42:23 -07:00
} else {
2014-08-28 00:12:45 -07:00
lights.packets["red"].setColorFade(6, "off", 10)
}
lights.sendLights()
}
// Turns all lights green to signal that the field is safe to enter.
func (lights *Lights) SetFieldReset() {
lights.packets["red"].setAllColor("green")
lights.packets["blue"].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":
lights.packets["red"].setAllColor("off")
lights.packets["blue"].setAllColor("off")
case "all_white":
lights.packets["red"].setAllColor("white")
lights.packets["blue"].setAllColor("white")
case "all_red":
lights.packets["red"].setAllColor("red")
lights.packets["blue"].setAllColor("red")
case "all_green":
lights.packets["red"].setAllColor("green")
lights.packets["blue"].setAllColor("green")
case "all_blue":
lights.packets["red"].setAllColor("blue")
lights.packets["blue"].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() {
for alliance, connection := range lights.connections {
2014-08-23 21:42:23 -07:00
if lights.newConnections || *lights.packets[alliance] != *lights.oldPackets[alliance] {
if connection != nil {
_, err := (*connection).Write(lights.packets[alliance][:])
if err != nil {
log.Printf("Failed to send %s light packet.", alliance)
}
2014-08-23 21:42:23 -07:00
}
mainArena.hotGoalLightNotifier.Notify(lights.hotGoal)
}
*lights.oldPackets[alliance] = *lights.packets[alliance]
}
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:
lights.packets["red"].setAllColor("white")
lights.packets["blue"].setAllColor("off")
case 2:
lights.packets["red"].setAllColor("off")
lights.packets["blue"].setAllColor("white")
fallthrough
default:
lights.animationCount = 0
}
lights.sendLights()
case "fade_red":
if lights.animationCount == 1 {
lights.packets["red"].setAllColorFade("red", 18)
lights.packets["blue"].setAllColorFade("red", 18)
} else if lights.animationCount == 61 {
lights.packets["red"].setAllColorFade("darkred", 18)
lights.packets["blue"].setAllColorFade("darkred", 18)
} else if lights.animationCount > 120 {
lights.animationCount = 0
}
lights.sendLights()
case "fade_blue":
if lights.animationCount == 1 {
lights.packets["red"].setAllColorFade("blue", 18)
lights.packets["blue"].setAllColorFade("blue", 18)
} else if lights.animationCount == 61 {
lights.packets["red"].setAllColorFade("darkblue", 18)
lights.packets["blue"].setAllColorFade("darkblue", 18)
} else if lights.animationCount > 120 {
lights.animationCount = 0
}
lights.sendLights()
case "fade_red_blue":
if lights.animationCount == 1 {
lights.packets["red"].setAllColorFade("blue", 18)
lights.packets["blue"].setAllColorFade("darkred", 18)
} else if lights.animationCount == 61 {
lights.packets["red"].setAllColorFade("darkblue", 18)
lights.packets["blue"].setAllColorFade("red", 18)
} else if lights.animationCount > 120 {
lights.animationCount = 0
}
lights.sendLights()
}
}