Add support for Philips Color Kinetics LEDs in vault.

This commit is contained in:
Patrick Fairbank
2018-08-19 02:00:50 -07:00
parent fcc3199c7f
commit 635ce72806
12 changed files with 401 additions and 93 deletions

View File

@@ -29,7 +29,9 @@ CREATE TABLE event_settings (
stemtveventcode VARCHAR(16),
scaleledaddress VARCHAR(255),
redswitchledaddress VARCHAR(255),
blueswitchledaddress VARCHAR(255)
blueswitchledaddress VARCHAR(255),
redvaultledaddress VARCHAR(255),
bluevaultledaddress VARCHAR(255)
);
-- +goose Down

View File

@@ -11,6 +11,7 @@ import (
"github.com/Team254/cheesy-arena/led"
"github.com/Team254/cheesy-arena/model"
"github.com/Team254/cheesy-arena/partner"
"github.com/Team254/cheesy-arena/vaultled"
"log"
"math/rand"
"time"
@@ -83,6 +84,8 @@ type Arena struct {
ScaleLeds led.Controller
RedSwitchLeds led.Controller
BlueSwitchLeds led.Controller
RedVaultLeds vaultled.Controller
BlueVaultLeds vaultled.Controller
warmupLedMode led.Mode
lastRedAllianceReady bool
lastBlueAllianceReady bool
@@ -189,6 +192,12 @@ func (arena *Arena) LoadSettings() error {
if err = arena.BlueSwitchLeds.SetAddress(settings.BlueSwitchLedAddress); err != nil {
return err
}
if err = arena.RedVaultLeds.SetAddress(settings.RedVaultLedAddress); err != nil {
return err
}
if err = arena.BlueVaultLeds.SetAddress(settings.BlueVaultLedAddress); err != nil {
return err
}
return nil
}
@@ -257,6 +266,8 @@ func (arena *Arena) LoadMatch(match *model.Match) error {
arena.ScaleLeds.SetMode(led.OffMode, led.OffMode)
arena.RedSwitchLeds.SetMode(led.RedMode, led.RedMode)
arena.BlueSwitchLeds.SetMode(led.BlueMode, led.BlueMode)
arena.RedVaultLeds.SetAllModes(vaultled.OffMode)
arena.BlueVaultLeds.SetAllModes(vaultled.OffMode)
arena.lastRedAllianceReady = false
arena.lastBlueAllianceReady = false
@@ -807,6 +818,8 @@ func (arena *Arena) handleLeds() {
handleSeesawTeleopLeds(arena.Scale, &arena.ScaleLeds)
handleSeesawTeleopLeds(arena.RedSwitch, &arena.RedSwitchLeds)
handleSeesawTeleopLeds(arena.BlueSwitch, &arena.BlueSwitchLeds)
handleVaultTeleopLeds(arena.RedVault, &arena.RedVaultLeds)
handleVaultTeleopLeds(arena.BlueVault, &arena.BlueVaultLeds)
case PausePeriod:
arena.ScaleLeds.SetMode(led.OffMode, led.OffMode)
arena.RedSwitchLeds.SetMode(led.OffMode, led.OffMode)
@@ -822,11 +835,15 @@ func (arena *Arena) handleLeds() {
arena.ScaleLeds.SetMode(mode, mode)
arena.RedSwitchLeds.SetMode(mode, mode)
arena.BlueSwitchLeds.SetMode(mode, mode)
arena.RedVaultLeds.SetAllModes(vaultled.OffMode)
arena.BlueVaultLeds.SetAllModes(vaultled.OffMode)
}
arena.ScaleLeds.Update()
arena.RedSwitchLeds.Update()
arena.BlueSwitchLeds.Update()
arena.RedVaultLeds.Update()
arena.BlueVaultLeds.Update()
}
func handleSeesawTeleopLeds(seesaw *game.Seesaw, leds *led.Controller) {
@@ -867,6 +884,33 @@ func handleSeesawTeleopLeds(seesaw *game.Seesaw, leds *led.Controller) {
}
}
func handleVaultTeleopLeds(vault *game.Vault, leds *vaultled.Controller) {
playedMode := vaultled.RedPlayedMode
if vault.Alliance == game.BlueAlliance {
playedMode = vaultled.BluePlayedMode
}
cubesModeMap := map[int]vaultled.Mode{0: vaultled.OffMode, 1: vaultled.OneCubeMode, 2: vaultled.TwoCubeMode,
3: vaultled.ThreeCubeMode}
if vault.ForcePowerUp != nil {
leds.SetForceMode(playedMode)
} else {
leds.SetForceMode(cubesModeMap[vault.ForceCubes])
}
if vault.LevitatePlayed {
leds.SetLevitateMode(playedMode)
} else {
leds.SetLevitateMode(cubesModeMap[vault.LevitateCubes])
}
if vault.BoostPowerUp != nil {
leds.SetBoostMode(playedMode)
} else {
leds.SetBoostMode(cubesModeMap[vault.BoostCubes])
}
}
func (arena *Arena) handleEstop(station string, state bool) {
allianceStation := arena.AllianceStations[station]
if state {

View File

@@ -5,36 +5,36 @@
package led
type color int
type Color int
const (
red color = iota
orange
yellow
green
teal
blue
purple
white
black
purpleRed
purpleBlue
dimRed
dimBlue
Red Color = iota
Orange
Yellow
Green
Teal
Blue
Purple
White
Black
PurpleRed
PurpleBlue
DimRed
DimBlue
)
var colors = map[color][3]byte{
red: {255, 0, 0},
orange: {255, 50, 0},
yellow: {255, 255, 0},
green: {0, 255, 0},
teal: {0, 100, 100},
blue: {0, 0, 255},
purple: {100, 0, 100},
white: {255, 255, 255},
black: {0, 0, 0},
purpleRed: {200, 0, 50},
purpleBlue: {50, 0, 200},
dimRed: {50, 0, 0},
dimBlue: {0, 0, 50},
var Colors = map[Color][3]byte{
Red: {255, 0, 0},
Orange: {255, 50, 0},
Yellow: {255, 255, 0},
Green: {0, 255, 0},
Teal: {0, 100, 100},
Blue: {0, 0, 255},
Purple: {100, 0, 100},
White: {255, 255, 255},
Black: {0, 0, 0},
PurpleRed: {200, 0, 50},
PurpleBlue: {50, 0, 200},
DimRed: {50, 0, 0},
DimBlue: {0, 0, 50},
}

View File

@@ -103,7 +103,7 @@ func (controller *Controller) Update() error {
// Constructs the structure of an E1.31 data packet that can be re-used indefinitely by updating the pixel data and
// re-sending it.
func createBlankPacket(numPixels int) []byte {
size := 126 + 3*numPixels
size := pixelDataOffset + 3*numPixels
packet := make([]byte, size)
// Preamble size

View File

@@ -23,15 +23,15 @@ type strip struct {
func (strip *strip) updatePixels() {
switch strip.currentMode {
case RedMode:
strip.updateSingleColorMode(red)
strip.updateSingleColorMode(Red)
case GreenMode:
strip.updateSingleColorMode(green)
strip.updateSingleColorMode(Green)
case BlueMode:
strip.updateSingleColorMode(blue)
strip.updateSingleColorMode(Blue)
case WhiteMode:
strip.updateSingleColorMode(white)
strip.updateSingleColorMode(White)
case PurpleMode:
strip.updateSingleColorMode(purple)
strip.updateSingleColorMode(Purple)
case ChaseMode:
strip.updateChaseMode()
case WarmupMode:
@@ -90,43 +90,43 @@ func (strip *strip) populatePacketPixels(pixelData []byte) {
}
// Returns the primary color (red or blue) of this strip.
func (strip *strip) getColor() color {
func (strip *strip) getColor() Color {
if strip.isRed {
return red
return Red
}
return blue
return Blue
}
// Returns the opposite primary color (red or blue) to this strip.
func (strip *strip) getOppositeColor() color {
func (strip *strip) getOppositeColor() Color {
if strip.isRed {
return blue
return Blue
}
return red
return Red
}
// Returns a color partway between purple and the primary color (red or blue) of this strip.
func (strip *strip) getMidColor() color {
func (strip *strip) getMidColor() Color {
if strip.isRed {
return purpleBlue
return PurpleBlue
}
return purpleRed
return PurpleRed
}
// Returns a dim version of the primary color (red or blue) of this strip.
func (strip *strip) getDimColor() color {
func (strip *strip) getDimColor() Color {
if strip.isRed {
return dimRed
return DimRed
}
return dimBlue
return DimBlue
}
// Returns a dim version of the opposite primary color (red or blue) of this strip.
func (strip *strip) getDimOppositeColor() color {
func (strip *strip) getDimOppositeColor() Color {
if strip.isRed {
return dimBlue
return DimBlue
}
return dimRed
return DimRed
}
// Returns the starting offset for the gradient mode for this strip.
@@ -139,23 +139,23 @@ func (strip *strip) getGradientStartOffset() int {
func (strip *strip) updateOffMode() {
for i := 0; i < numPixels; i++ {
strip.pixels[i] = colors[black]
strip.pixels[i] = Colors[Black]
}
}
func (strip *strip) updateSingleColorMode(color color) {
func (strip *strip) updateSingleColorMode(color Color) {
for i := 0; i < numPixels; i++ {
strip.pixels[i] = colors[color]
strip.pixels[i] = Colors[color]
}
}
func (strip *strip) updateChaseMode() {
if strip.counter == int(black)*numPixels { // Ignore colors listed after white.
if strip.counter == int(Black)*numPixels { // Ignore colors listed after white.
strip.counter = 0
}
color := color(strip.counter / numPixels)
color := Color(strip.counter / numPixels)
pixelIndex := strip.counter % numPixels
strip.pixels[pixelIndex] = colors[color]
strip.pixels[pixelIndex] = Colors[color]
}
func (strip *strip) updateWarmupMode() {
@@ -163,14 +163,14 @@ func (strip *strip) updateWarmupMode() {
if strip.counter == 0 {
// Show solid white to start.
for i := 0; i < numPixels; i++ {
strip.pixels[i] = colors[white]
strip.pixels[i] = Colors[White]
}
} else if strip.counter <= endCounter {
// Build to the alliance color from each side.
numLitPixels := numPixels / 2 * strip.counter / endCounter
for i := 0; i < numLitPixels; i++ {
strip.pixels[i] = colors[strip.getColor()]
strip.pixels[numPixels-i-1] = colors[strip.getColor()]
strip.pixels[i] = Colors[strip.getColor()]
strip.pixels[numPixels-i-1] = Colors[strip.getColor()]
}
} else {
// Prevent the counter from rolling over.
@@ -184,11 +184,11 @@ func (strip *strip) updateWarmup2Mode() {
if strip.counter < startCounter {
// Show solid purple to start.
for i := 0; i < numPixels; i++ {
strip.pixels[i] = colors[purple]
strip.pixels[i] = Colors[Purple]
}
} else if strip.counter <= endCounter {
for i := 0; i < numPixels; i++ {
strip.pixels[i] = getFadeColor(purple, strip.getColor(), strip.counter-startCounter,
strip.pixels[i] = getFadeColor(Purple, strip.getColor(), strip.counter-startCounter,
endCounter-startCounter)
}
} else {
@@ -204,11 +204,11 @@ func (strip *strip) updateWarmup3Mode() {
if strip.counter < startCounter {
// Show solid purple to start.
for i := 0; i < numPixels; i++ {
strip.pixels[i] = colors[purple]
strip.pixels[i] = Colors[Purple]
}
} else if strip.counter < middleCounter {
for i := 0; i < numPixels; i++ {
strip.pixels[i] = getFadeColor(purple, strip.getMidColor(), strip.counter-startCounter,
strip.pixels[i] = getFadeColor(Purple, strip.getMidColor(), strip.counter-startCounter,
middleCounter-startCounter)
}
} else if strip.counter <= endCounter {
@@ -230,7 +230,7 @@ func (strip *strip) updateWarmup4Mode() {
if strip.counter >= middleCounter {
for i := 0; i < numPixels; i++ {
if i < strip.counter-middleCounter {
strip.pixels[i] = colors[strip.getColor()]
strip.pixels[i] = Colors[strip.getColor()]
}
}
}
@@ -247,16 +247,16 @@ func (strip *strip) updateOwnedMode() {
case 0:
fallthrough
case 1:
strip.pixels[len(strip.pixels)-i-1] = colors[strip.getColor()]
strip.pixels[len(strip.pixels)-i-1] = Colors[strip.getColor()]
default:
strip.pixels[len(strip.pixels)-i-1] = colors[black]
strip.pixels[len(strip.pixels)-i-1] = Colors[Black]
}
}
}
func (strip *strip) updateNotOwnedMode() {
for i := 0; i < numPixels; i++ {
strip.pixels[i] = colors[strip.getDimColor()]
strip.pixels[i] = Colors[strip.getDimColor()]
}
}
@@ -271,11 +271,11 @@ func (strip *strip) updateForceMode() {
case 2:
fallthrough
case 4:
strip.pixels[i] = colors[strip.getColor()]
strip.pixels[i] = Colors[strip.getColor()]
case 3:
strip.pixels[i] = colors[strip.getDimOppositeColor()]
strip.pixels[i] = Colors[strip.getDimOppositeColor()]
default:
strip.pixels[i] = colors[black]
strip.pixels[i] = Colors[Black]
}
}
}
@@ -288,9 +288,9 @@ func (strip *strip) updateBoostMode() {
}
for i := 0; i < numPixels; i++ {
if i%pixelSpacing == strip.counter/speedDivisor%pixelSpacing {
strip.pixels[i] = colors[strip.getColor()]
strip.pixels[i] = Colors[strip.getColor()]
} else {
strip.pixels[i] = colors[black]
strip.pixels[i] = Colors[Black]
}
}
}
@@ -300,7 +300,7 @@ func (strip *strip) updateRandomMode() {
return
}
for i := 0; i < numPixels; i++ {
strip.pixels[i] = colors[color(rand.Intn(int(black)))] // Ignore colors listed after white.
strip.pixels[i] = Colors[Color(rand.Intn(int(Black)))] // Ignore colors listed after white.
}
}
@@ -313,21 +313,21 @@ func (strip *strip) updateFadeRedBlueMode() {
for i := 0; i < numPixels; i++ {
if strip.counter < holdCycles {
strip.pixels[i] = colors[black]
strip.pixels[i] = Colors[Black]
} else if strip.counter < holdCycles+fadeCycles {
strip.pixels[i] = getFadeColor(black, red, strip.counter-holdCycles, fadeCycles)
strip.pixels[i] = getFadeColor(Black, Red, strip.counter-holdCycles, fadeCycles)
} else if strip.counter < 2*holdCycles+fadeCycles {
strip.pixels[i] = colors[red]
strip.pixels[i] = Colors[Red]
} else if strip.counter < 2*holdCycles+2*fadeCycles {
strip.pixels[i] = getFadeColor(red, black, strip.counter-2*holdCycles-fadeCycles, fadeCycles)
strip.pixels[i] = getFadeColor(Red, Black, strip.counter-2*holdCycles-fadeCycles, fadeCycles)
} else if strip.counter < 3*holdCycles+2*fadeCycles {
strip.pixels[i] = colors[black]
strip.pixels[i] = Colors[Black]
} else if strip.counter < 3*holdCycles+3*fadeCycles {
strip.pixels[i] = getFadeColor(black, blue, strip.counter-3*holdCycles-2*fadeCycles, fadeCycles)
strip.pixels[i] = getFadeColor(Black, Blue, strip.counter-3*holdCycles-2*fadeCycles, fadeCycles)
} else if strip.counter < 4*holdCycles+3*fadeCycles {
strip.pixels[i] = colors[blue]
strip.pixels[i] = Colors[Blue]
} else if strip.counter < 4*holdCycles+4*fadeCycles {
strip.pixels[i] = getFadeColor(blue, black, strip.counter-4*holdCycles-3*fadeCycles, fadeCycles)
strip.pixels[i] = getFadeColor(Blue, Black, strip.counter-4*holdCycles-3*fadeCycles, fadeCycles)
}
}
}
@@ -341,11 +341,11 @@ func (strip *strip) updateFadeSingleMode() {
for i := 0; i < numPixels; i++ {
if strip.counter < offCycles {
strip.pixels[i] = colors[black]
strip.pixels[i] = Colors[Black]
} else if strip.counter < offCycles+fadeCycles {
strip.pixels[i] = getFadeColor(black, strip.getColor(), strip.counter-offCycles, fadeCycles)
strip.pixels[i] = getFadeColor(Black, strip.getColor(), strip.counter-offCycles, fadeCycles)
} else if strip.counter < offCycles+2*fadeCycles {
strip.pixels[i] = getFadeColor(strip.getColor(), black, strip.counter-offCycles-fadeCycles, fadeCycles)
strip.pixels[i] = getFadeColor(strip.getColor(), Black, strip.counter-offCycles-fadeCycles, fadeCycles)
}
}
}
@@ -360,17 +360,17 @@ func (strip *strip) updateBlinkMode() {
divisor := 10
for i := 0; i < numPixels; i++ {
if strip.counter%divisor < divisor/2 {
strip.pixels[i] = colors[white]
strip.pixels[i] = Colors[White]
} else {
strip.pixels[i] = colors[black]
strip.pixels[i] = Colors[Black]
}
}
}
// Interpolates between the two colors based on the given fraction.
func getFadeColor(fromColor, toColor color, numerator, denominator int) [3]byte {
from := colors[fromColor]
to := colors[toColor]
func getFadeColor(fromColor, toColor Color, numerator, denominator int) [3]byte {
from := Colors[fromColor]
to := Colors[toColor]
var fadeColor [3]byte
for i := 0; i < 3; i++ {
fadeColor[i] = byte(int(from[i]) + numerator*(int(to[i])-int(from[i]))/denominator)
@@ -382,10 +382,10 @@ func getFadeColor(fromColor, toColor color, numerator, denominator int) [3]byte
func getGradientColor(offset, numPixels int) [3]byte {
offset %= numPixels
if 3*offset < numPixels {
return getFadeColor(red, green, 3*offset, numPixels)
return getFadeColor(Red, Green, 3*offset, numPixels)
} else if 3*offset < 2*numPixels {
return getFadeColor(green, blue, 3*offset-numPixels, numPixels)
return getFadeColor(Green, Blue, 3*offset-numPixels, numPixels)
} else {
return getFadeColor(blue, red, 3*offset-2*numPixels, numPixels)
return getFadeColor(Blue, Red, 3*offset-2*numPixels, numPixels)
}
}

View File

@@ -35,6 +35,8 @@ type EventSettings struct {
ScaleLedAddress string
RedSwitchLedAddress string
BlueSwitchLedAddress string
RedVaultLedAddress string
BlueVaultLedAddress string
}
const eventSettingsId = 0

View File

@@ -86,6 +86,7 @@
<legend>LEDs</legend>
<form class="" action="/setup/field/test" method="POST">
<div class="form-group">
<label>Switch/Scale</label>
{{range $i, $name := .LedModeNames}}
<div class="radio">
<label>
@@ -95,6 +96,17 @@
</div>
{{end}}
</div>
<div class="form-group">
<label>Vault</label>
{{range $i, $name := .VaultLedModeNames}}
<div class="radio">
<label>
<input type="radio" name="vaultMode" value="{{$i}}" onclick="this.form.submit()"
{{if eq $.CurrentVaultLedMode $i}}checked{{end}}>{{$name}}
</label>
</div>
{{end}}
</div>
</form>
</div>
</div>

View File

@@ -259,6 +259,18 @@
<input type="text" class="form-control" name="blueSwitchLedAddress" value="{{.BlueSwitchLedAddress}}">
</div>
</div>
<div class="form-group">
<label class="col-lg-5 control-label">Red Vault Controller Address</label>
<div class="col-lg-7">
<input type="text" class="form-control" name="redVaultLedAddress" value="{{.RedVaultLedAddress}}">
</div>
</div>
<div class="form-group">
<label class="col-lg-5 control-label">Blue Vault Controller Address</label>
<div class="col-lg-7">
<input type="text" class="form-control" name="blueVaultLedAddress" value="{{.BlueVaultLedAddress}}">
</div>
</div>
</fieldset>
<div class="form-group">
<div class="col-lg-7 col-lg-offset-5">

199
vaultled/controller.go Normal file
View File

@@ -0,0 +1,199 @@
// Copyright 2018 Team 254. All Rights Reserved.
// Author: pat@patfairbank.com (Patrick Fairbank)
//
// Represents a Philips Color Kinetics LED controller with one output, as used in the 2018 vault.
package vaultled
import (
"fmt"
"github.com/Team254/cheesy-arena/led"
"net"
"time"
)
const (
port = 6038
packetTimeoutSec = 1
numPixels = 17
pixelDataOffset = 21
)
type Controller struct {
CurrentForceMode Mode
CurrentLevitateMode Mode
CurrentBoostMode Mode
pixels [numPixels][3]byte
oldPixels [numPixels][3]byte
conn net.Conn
packet []byte
lastPacketTime time.Time
}
func (controller *Controller) SetAddress(address string) error {
if controller.conn != nil {
controller.conn.Close()
controller.conn = nil
}
if address != "" {
var err error
if controller.conn, err = net.Dial("udp4", fmt.Sprintf("%s:%d", address, port)); err != nil {
return err
}
}
return nil
}
// Sets the current mode for the section of LEDs corresponding to the force powerup.
func (controller *Controller) SetForceMode(mode Mode) {
controller.CurrentForceMode = mode
controller.setPixels(0, mode)
}
// Sets the current mode for the section of LEDs corresponding to the levitate powerup.
func (controller *Controller) SetLevitateMode(mode Mode) {
controller.CurrentLevitateMode = mode
controller.setPixels(6, mode)
}
// Sets the current mode for the section of LEDs corresponding to the boost powerup.
func (controller *Controller) SetBoostMode(mode Mode) {
controller.CurrentBoostMode = mode
controller.setPixels(12, mode)
}
// Sets the current mode for all sections of LEDs to the same value.
func (controller *Controller) SetAllModes(mode Mode) {
controller.SetForceMode(mode)
controller.SetLevitateMode(mode)
controller.SetBoostMode(mode)
}
// Sends a packet if necessary. Should be called from a timed loop.
func (controller *Controller) Update() error {
if controller.conn == nil {
// This controller is not configured; do nothing.
return nil
}
// Create the template packet if it doesn't already exist.
if len(controller.packet) == 0 {
controller.packet = createBlankPacket(numPixels)
}
// Send packets if the pixel values have changed.
if controller.shouldSendPacket() {
controller.populatePacketPixels(controller.packet[pixelDataOffset:])
controller.sendPacket()
}
return nil
}
func (controller *Controller) setPixels(offset int, mode Mode) {
for i := 0; i < 5; i++ {
controller.pixels[offset+i] = led.Colors[led.Black]
}
switch mode {
case ThreeCubeMode:
controller.pixels[offset+3] = led.Colors[led.Yellow]
fallthrough
case TwoCubeMode:
controller.pixels[offset+2] = led.Colors[led.Yellow]
fallthrough
case OneCubeMode:
controller.pixels[offset+1] = led.Colors[led.Yellow]
case RedPlayedMode:
for i := 0; i < 5; i++ {
controller.pixels[offset+i] = led.Colors[led.Red]
}
case BluePlayedMode:
for i := 0; i < 5; i++ {
controller.pixels[offset+i] = led.Colors[led.Blue]
}
}
}
// Constructs the structure of a KiNET data packet that can be re-used indefinitely by updating the pixel data and
// re-sending it.
func createBlankPacket(numPixels int) []byte {
size := pixelDataOffset + 3*numPixels
packet := make([]byte, size)
// Magic sequence
packet[0] = 0x04
packet[1] = 0x01
packet[2] = 0xdc
packet[3] = 0x4a
// Version
packet[4] = 0x01
packet[5] = 0x00
// Type
packet[6] = 0x01
packet[7] = 0x01
// Sequence
packet[8] = 0x00
packet[9] = 0x00
packet[10] = 0x00
packet[11] = 0x00
// Port
packet[12] = 0x00
// Padding
packet[13] = 0x00
// Flags
packet[14] = 0x00
packet[15] = 0x00
// Timer
packet[16] = 0xff
packet[17] = 0xff
packet[18] = 0xff
packet[19] = 0xff
// Universe
packet[20] = 0x00
// Remainder of packet is pixel data which will be populated whenever packet is sent.
return packet
}
// Returns true if the pixel data has changed.
func (controller *Controller) shouldSendPacket() bool {
for i := 0; i < numPixels; i++ {
if controller.pixels[i] != controller.oldPixels[i] {
return true
}
}
return time.Since(controller.lastPacketTime).Seconds() > packetTimeoutSec
}
// Writes the pixel RGB values into the given packet in preparation for sending.
func (controller *Controller) populatePacketPixels(pixelData []byte) {
for i, pixel := range controller.pixels {
pixelData[3*i] = pixel[0]
pixelData[3*i+1] = pixel[1]
pixelData[3*i+2] = pixel[2]
}
// Keep a record of the pixel values in order to detect future changes.
controller.oldPixels = controller.pixels
controller.lastPacketTime = time.Now()
}
func (controller *Controller) sendPacket() error {
_, err := controller.conn.Write(controller.packet)
if err != nil {
return err
}
return nil
}

26
vaultled/mode.go Normal file
View File

@@ -0,0 +1,26 @@
// Copyright 2018 Team 254. All Rights Reserved.
// Author: pat@patfairbank.com (Patrick Fairbank)
//
// Contains the set of display modes for the vault LEDs.
package vaultled
type Mode int
const (
OffMode Mode = iota
OneCubeMode
TwoCubeMode
ThreeCubeMode
RedPlayedMode
BluePlayedMode
)
var ModeNames = map[Mode]string{
OffMode: "Off",
OneCubeMode: "One Cube",
TwoCubeMode: "Two Cubes",
ThreeCubeMode: "Three Cubes",
RedPlayedMode: "Red Played",
BluePlayedMode: "Blue Played",
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/Team254/cheesy-arena/field"
"github.com/Team254/cheesy-arena/led"
"github.com/Team254/cheesy-arena/model"
"github.com/Team254/cheesy-arena/vaultled"
"log"
"net/http"
"strconv"
@@ -34,8 +35,11 @@ func (web *Web) fieldGetHandler(w http.ResponseWriter, r *http.Request) {
CoilNames []string
CurrentLedMode led.Mode
LedModeNames map[led.Mode]string
CurrentVaultLedMode vaultled.Mode
VaultLedModeNames map[vaultled.Mode]string
}{web.arena.EventSettings, web.arena.AllianceStationDisplays, plc.GetInputNames(), plc.GetRegisterNames(),
plc.GetCoilNames(), web.arena.ScaleLeds.GetCurrentMode(), led.ModeNames}
plc.GetCoilNames(), web.arena.ScaleLeds.GetCurrentMode(), led.ModeNames,
web.arena.RedVaultLeds.CurrentForceMode, vaultled.ModeNames}
err = template.ExecuteTemplate(w, "base", data)
if err != nil {
handleWebErr(w, err)
@@ -83,6 +87,11 @@ func (web *Web) fieldTestPostHandler(w http.ResponseWriter, r *http.Request) {
web.arena.RedSwitchLeds.SetMode(ledMode, ledMode)
web.arena.BlueSwitchLeds.SetMode(ledMode, ledMode)
vaultMode, _ := strconv.Atoi(r.PostFormValue("vaultMode"))
vaultLedMode := vaultled.Mode(vaultMode)
web.arena.RedVaultLeds.SetAllModes(vaultLedMode)
web.arena.BlueVaultLeds.SetAllModes(vaultLedMode)
http.Redirect(w, r, "/setup/field", 303)
}

View File

@@ -73,6 +73,8 @@ func (web *Web) settingsPostHandler(w http.ResponseWriter, r *http.Request) {
eventSettings.ScaleLedAddress = r.PostFormValue("scaleLedAddress")
eventSettings.RedSwitchLedAddress = r.PostFormValue("redSwitchLedAddress")
eventSettings.BlueSwitchLedAddress = r.PostFormValue("blueSwitchLedAddress")
eventSettings.RedVaultLedAddress = r.PostFormValue("redVaultLedAddress")
eventSettings.BlueVaultLedAddress = r.PostFormValue("blueVaultLedAddress")
err := web.arena.Database.SaveEventSettings(eventSettings)
if err != nil {