mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-09 21:56:50 -04:00
Remove 2018-game-specific field/plc/led code.
This commit is contained in:
@@ -22,12 +22,7 @@ CREATE TABLE event_settings (
|
||||
plcaddress VARCHAR(255),
|
||||
tbadownloadenabled bool,
|
||||
adminpassword VARCHAR(255),
|
||||
readerpassword VARCHAR(255),
|
||||
scaleledaddress VARCHAR(255),
|
||||
redswitchledaddress VARCHAR(255),
|
||||
blueswitchledaddress VARCHAR(255),
|
||||
redvaultledaddress VARCHAR(255),
|
||||
bluevaultledaddress VARCHAR(255)
|
||||
readerpassword VARCHAR(255)
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
|
||||
253
field/arena.go
253
field/arena.go
@@ -8,14 +8,11 @@ package field
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena/game"
|
||||
"github.com/Team254/cheesy-arena/led"
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"github.com/Team254/cheesy-arena/network"
|
||||
"github.com/Team254/cheesy-arena/partner"
|
||||
"github.com/Team254/cheesy-arena/plc"
|
||||
"github.com/Team254/cheesy-arena/vaultled"
|
||||
"log"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -69,17 +66,6 @@ type Arena struct {
|
||||
LowerThird *model.LowerThird
|
||||
MuteMatchSounds bool
|
||||
matchAborted bool
|
||||
Scale *game.Seesaw
|
||||
RedSwitch *game.Seesaw
|
||||
BlueSwitch *game.Seesaw
|
||||
RedVault *game.Vault
|
||||
BlueVault *game.Vault
|
||||
ScaleLeds led.Controller
|
||||
RedSwitchLeds led.Controller
|
||||
BlueSwitchLeds led.Controller
|
||||
RedVaultLeds vaultled.Controller
|
||||
BlueVaultLeds vaultled.Controller
|
||||
warmupLedMode led.Mode
|
||||
lastRedAllianceReady bool
|
||||
lastBlueAllianceReady bool
|
||||
soundsPlayed map[*game.MatchSound]struct{}
|
||||
@@ -155,23 +141,6 @@ func (arena *Arena) LoadSettings() error {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize LEDs.
|
||||
if err = arena.ScaleLeds.SetAddress(settings.ScaleLedAddress); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = arena.RedSwitchLeds.SetAddress(settings.RedSwitchLedAddress); err != nil {
|
||||
return err
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -215,20 +184,6 @@ func (arena *Arena) LoadMatch(match *model.Match) error {
|
||||
arena.BlueRealtimeScore = NewRealtimeScore()
|
||||
arena.FieldVolunteers = false
|
||||
arena.FieldReset = false
|
||||
arena.Scale = &game.Seesaw{Kind: game.NeitherAlliance}
|
||||
arena.RedSwitch = &game.Seesaw{Kind: game.RedAlliance}
|
||||
arena.BlueSwitch = &game.Seesaw{Kind: game.BlueAlliance}
|
||||
arena.RedVault = &game.Vault{Alliance: game.RedAlliance}
|
||||
arena.BlueVault = &game.Vault{Alliance: game.BlueAlliance}
|
||||
game.ResetPowerUps()
|
||||
|
||||
// Set a consistent initial value for field element sidedness.
|
||||
arena.Scale.NearIsRed = true
|
||||
arena.RedSwitch.NearIsRed = true
|
||||
arena.BlueSwitch.NearIsRed = true
|
||||
arena.ScaleLeds.SetSidedness(true)
|
||||
arena.RedSwitchLeds.SetSidedness(true)
|
||||
arena.BlueSwitchLeds.SetSidedness(true)
|
||||
|
||||
// Notify any listeners about the new match.
|
||||
arena.MatchLoadNotifier.Notify()
|
||||
@@ -237,11 +192,6 @@ func (arena *Arena) LoadMatch(match *model.Match) error {
|
||||
arena.AllianceStationDisplayModeNotifier.Notify()
|
||||
|
||||
// Set the initial state of the lights.
|
||||
arena.ScaleLeds.SetMode(led.GreenMode, led.GreenMode)
|
||||
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
|
||||
|
||||
@@ -312,21 +262,6 @@ func (arena *Arena) SubstituteTeam(teamId int, station string) error {
|
||||
func (arena *Arena) StartMatch() error {
|
||||
err := arena.checkCanStartMatch()
|
||||
if err == nil {
|
||||
// Generate game-specific data or allow manual input for test matches.
|
||||
if arena.CurrentMatch.Type != "test" || !game.IsValidGameSpecificData(arena.CurrentMatch.GameSpecificData) {
|
||||
arena.CurrentMatch.GameSpecificData = game.GenerateGameSpecificData()
|
||||
}
|
||||
|
||||
// Configure the field elements with the game-specific data.
|
||||
switchNearIsRed := arena.CurrentMatch.GameSpecificData[0] == 'L'
|
||||
scaleNearIsRed := arena.CurrentMatch.GameSpecificData[1] == 'L'
|
||||
arena.Scale.NearIsRed = scaleNearIsRed
|
||||
arena.RedSwitch.NearIsRed = switchNearIsRed
|
||||
arena.BlueSwitch.NearIsRed = switchNearIsRed
|
||||
arena.ScaleLeds.SetSidedness(scaleNearIsRed)
|
||||
arena.RedSwitchLeds.SetSidedness(switchNearIsRed)
|
||||
arena.BlueSwitchLeds.SetSidedness(switchNearIsRed)
|
||||
|
||||
// Save the match start time and game-specifc data to the database for posterity.
|
||||
arena.CurrentMatch.StartedAt = time.Now()
|
||||
if arena.CurrentMatch.Type != "test" {
|
||||
@@ -442,7 +377,6 @@ func (arena *Arena) Update() {
|
||||
arena.AudienceDisplayModeNotifier.Notify()
|
||||
arena.AllianceStationDisplayMode = "match"
|
||||
arena.AllianceStationDisplayModeNotifier.Notify()
|
||||
//arena.sendGameSpecificDataPacket()
|
||||
if game.MatchTiming.WarmupDurationSec > 0 {
|
||||
arena.MatchState = WarmupPeriod
|
||||
enabled = false
|
||||
@@ -452,9 +386,6 @@ func (arena *Arena) Update() {
|
||||
enabled = true
|
||||
sendDsPacket = true
|
||||
}
|
||||
// Pick an LED warmup mode at random to keep things interesting.
|
||||
allWarmupModes := []led.Mode{led.WarmupMode, led.Warmup2Mode, led.Warmup3Mode, led.Warmup4Mode}
|
||||
arena.warmupLedMode = allWarmupModes[rand.Intn(len(allWarmupModes))]
|
||||
case WarmupPeriod:
|
||||
auto = true
|
||||
enabled = false
|
||||
@@ -541,6 +472,16 @@ func (arena *Arena) Update() {
|
||||
// Handle field sensors/lights/motors.
|
||||
arena.handlePlcInput()
|
||||
arena.handleLeds()
|
||||
|
||||
// Send a notification if there has been a change in score.
|
||||
redScore := &arena.RedRealtimeScore.CurrentScore
|
||||
oldRedScore := *redScore
|
||||
blueScore := &arena.BlueRealtimeScore.CurrentScore
|
||||
oldBlueScore := *blueScore
|
||||
// TODO(pat): Fix this to work with manual scoring.
|
||||
if !oldRedScore.Equals(redScore) || !oldBlueScore.Equals(blueScore) {
|
||||
arena.RealtimeScoreNotifier.Notify()
|
||||
}
|
||||
}
|
||||
|
||||
// Loops indefinitely to track and update the arena components.
|
||||
@@ -723,66 +664,6 @@ func (arena *Arena) handlePlcInput() {
|
||||
// Don't do anything if we're outside the match, otherwise we may overwrite manual edits.
|
||||
return
|
||||
}
|
||||
matchStartTime := arena.MatchStartTime
|
||||
currentTime := time.Now()
|
||||
teleopStartTime := game.GetTeleopStartTime(matchStartTime)
|
||||
|
||||
redScore := &arena.RedRealtimeScore.CurrentScore
|
||||
oldRedScore := *redScore
|
||||
blueScore := &arena.BlueRealtimeScore.CurrentScore
|
||||
oldBlueScore := *blueScore
|
||||
|
||||
// Handle scale and switch ownership.
|
||||
scale, redSwitch, blueSwitch := arena.Plc.GetScaleAndSwitches()
|
||||
ownershipChanged := arena.Scale.UpdateState(scale, currentTime)
|
||||
ownershipChanged = arena.RedSwitch.UpdateState(redSwitch, currentTime) || ownershipChanged
|
||||
ownershipChanged = arena.BlueSwitch.UpdateState(blueSwitch, currentTime) || ownershipChanged
|
||||
if arena.MatchState == AutoPeriod {
|
||||
redScore.AutoScaleOwnershipSec, _ = arena.Scale.GetRedSeconds(matchStartTime, currentTime)
|
||||
redScore.AutoSwitchOwnershipSec, _ = arena.RedSwitch.GetRedSeconds(matchStartTime, currentTime)
|
||||
blueScore.AutoScaleOwnershipSec, _ = arena.Scale.GetBlueSeconds(matchStartTime, currentTime)
|
||||
blueScore.AutoSwitchOwnershipSec, _ = arena.BlueSwitch.GetBlueSeconds(matchStartTime, currentTime)
|
||||
redScore.AutoEndSwitchOwnership = arena.RedSwitch.GetOwnedBy() == game.RedAlliance
|
||||
blueScore.AutoEndSwitchOwnership = arena.BlueSwitch.GetOwnedBy() == game.BlueAlliance
|
||||
} else {
|
||||
redScore.TeleopScaleOwnershipSec, redScore.TeleopScaleBoostSec =
|
||||
arena.Scale.GetRedSeconds(teleopStartTime, currentTime)
|
||||
redScore.TeleopSwitchOwnershipSec, redScore.TeleopSwitchBoostSec =
|
||||
arena.RedSwitch.GetRedSeconds(teleopStartTime, currentTime)
|
||||
blueScore.TeleopScaleOwnershipSec, blueScore.TeleopScaleBoostSec =
|
||||
arena.Scale.GetBlueSeconds(teleopStartTime, currentTime)
|
||||
blueScore.TeleopSwitchOwnershipSec, blueScore.TeleopSwitchBoostSec =
|
||||
arena.BlueSwitch.GetBlueSeconds(teleopStartTime, currentTime)
|
||||
}
|
||||
|
||||
// Handle vaults.
|
||||
redForceDistance, redLevitateDistance, redBoostDistance, blueForceDistance, blueLevitateDistance,
|
||||
blueBoostDistance := arena.Plc.GetVaults()
|
||||
arena.RedVault.UpdateCubes(redForceDistance, redLevitateDistance, redBoostDistance)
|
||||
arena.BlueVault.UpdateCubes(blueForceDistance, blueLevitateDistance, blueBoostDistance)
|
||||
redForce, redLevitate, redBoost, blueForce, blueLevitate, blueBoost := arena.Plc.GetPowerUpButtons()
|
||||
arena.RedVault.UpdateButtons(redForce, redLevitate, redBoost, currentTime)
|
||||
arena.BlueVault.UpdateButtons(blueForce, blueLevitate, blueBoost, currentTime)
|
||||
redScore.ForceCubes, redScore.ForceCubesPlayed = arena.RedVault.ForceCubes, arena.RedVault.ForceCubesPlayed
|
||||
redScore.LevitateCubes, redScore.LevitatePlayed = arena.RedVault.LevitateCubes, arena.RedVault.LevitatePlayed
|
||||
redScore.BoostCubes, redScore.BoostCubesPlayed = arena.RedVault.BoostCubes, arena.RedVault.BoostCubesPlayed
|
||||
blueScore.ForceCubes, blueScore.ForceCubesPlayed = arena.BlueVault.ForceCubes, arena.BlueVault.ForceCubesPlayed
|
||||
blueScore.LevitateCubes, blueScore.LevitatePlayed = arena.BlueVault.LevitateCubes, arena.BlueVault.LevitatePlayed
|
||||
blueScore.BoostCubes, blueScore.BoostCubesPlayed = arena.BlueVault.BoostCubes, arena.BlueVault.BoostCubesPlayed
|
||||
|
||||
// Check if a power up has been newly played and trigger the accompanying sound effect if so.
|
||||
newRedPowerUp := arena.RedVault.CheckForNewlyPlayedPowerUp()
|
||||
if newRedPowerUp != "" {
|
||||
arena.playSound("match-" + newRedPowerUp)
|
||||
}
|
||||
newBluePowerUp := arena.BlueVault.CheckForNewlyPlayedPowerUp()
|
||||
if newBluePowerUp != "" {
|
||||
arena.playSound("match-" + newBluePowerUp)
|
||||
}
|
||||
|
||||
if !oldRedScore.Equals(redScore) || !oldBlueScore.Equals(blueScore) || ownershipChanged {
|
||||
arena.RealtimeScoreNotifier.Notify()
|
||||
}
|
||||
}
|
||||
|
||||
func (arena *Arena) handleLeds() {
|
||||
@@ -799,127 +680,29 @@ func (arena *Arena) handleLeds() {
|
||||
arena.Plc.SetStackLights(!redAllianceReady, !blueAllianceReady, greenStackLight)
|
||||
arena.Plc.SetStackBuzzer(redAllianceReady && blueAllianceReady)
|
||||
|
||||
// Turn off scale and each alliance switch if all teams become ready.
|
||||
// Turn off lights if all teams become ready.
|
||||
// TODO(pat): Implement for 2019.
|
||||
if redAllianceReady && blueAllianceReady && !(arena.lastRedAllianceReady && arena.lastBlueAllianceReady) {
|
||||
arena.ScaleLeds.SetMode(led.OffMode, led.OffMode)
|
||||
//arena.ScaleLeds.SetMode(led.OffMode, led.OffMode)
|
||||
} else if !(redAllianceReady && blueAllianceReady) && arena.lastRedAllianceReady &&
|
||||
arena.lastBlueAllianceReady {
|
||||
arena.ScaleLeds.SetMode(led.GreenMode, led.GreenMode)
|
||||
//arena.ScaleLeds.SetMode(led.GreenMode, led.GreenMode)
|
||||
}
|
||||
if redAllianceReady && !arena.lastRedAllianceReady {
|
||||
arena.RedSwitchLeds.SetMode(led.OffMode, led.OffMode)
|
||||
//arena.RedSwitchLeds.SetMode(led.OffMode, led.OffMode)
|
||||
} else if !redAllianceReady && arena.lastRedAllianceReady {
|
||||
arena.RedSwitchLeds.SetMode(led.RedMode, led.RedMode)
|
||||
//arena.RedSwitchLeds.SetMode(led.RedMode, led.RedMode)
|
||||
}
|
||||
arena.lastRedAllianceReady = redAllianceReady
|
||||
if blueAllianceReady && !arena.lastBlueAllianceReady {
|
||||
arena.BlueSwitchLeds.SetMode(led.OffMode, led.OffMode)
|
||||
//arena.BlueSwitchLeds.SetMode(led.OffMode, led.OffMode)
|
||||
} else if !blueAllianceReady && arena.lastBlueAllianceReady {
|
||||
arena.BlueSwitchLeds.SetMode(led.BlueMode, led.BlueMode)
|
||||
//arena.BlueSwitchLeds.SetMode(led.BlueMode, led.BlueMode)
|
||||
}
|
||||
arena.lastBlueAllianceReady = blueAllianceReady
|
||||
|
||||
case WarmupPeriod:
|
||||
arena.Plc.SetStackLights(false, false, true)
|
||||
arena.ScaleLeds.SetMode(arena.warmupLedMode, arena.warmupLedMode)
|
||||
arena.RedSwitchLeds.SetMode(arena.warmupLedMode, arena.warmupLedMode)
|
||||
arena.BlueSwitchLeds.SetMode(arena.warmupLedMode, arena.warmupLedMode)
|
||||
case AutoPeriod:
|
||||
fallthrough
|
||||
case TeleopPeriod:
|
||||
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)
|
||||
arena.BlueSwitchLeds.SetMode(led.OffMode, led.OffMode)
|
||||
case PostMatch:
|
||||
arena.Plc.SetStackLights(false, false, false)
|
||||
mode := led.FadeSingleMode
|
||||
if arena.FieldReset {
|
||||
mode = led.GreenMode
|
||||
} else if arena.FieldVolunteers {
|
||||
mode = led.PurpleMode
|
||||
}
|
||||
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) {
|
||||
// Assume the simplest mode to start and consider others in order of increasing complexity.
|
||||
redMode := led.NotOwnedMode
|
||||
blueMode := led.NotOwnedMode
|
||||
|
||||
// Upgrade the mode to ownership based on the physical state of the switch or scale.
|
||||
if seesaw.GetOwnedBy() == game.RedAlliance && seesaw.Kind != game.BlueAlliance {
|
||||
redMode = led.OwnedMode
|
||||
} else if seesaw.GetOwnedBy() == game.BlueAlliance && seesaw.Kind != game.RedAlliance {
|
||||
blueMode = led.OwnedMode
|
||||
}
|
||||
|
||||
// Upgrade the mode if there is an applicable power up.
|
||||
powerUp := game.GetActivePowerUp(time.Now())
|
||||
if powerUp != nil && (seesaw.Kind == game.NeitherAlliance && powerUp.Level >= 2 ||
|
||||
seesaw.Kind == powerUp.Alliance && (powerUp.Level == 1 || powerUp.Level == 3)) {
|
||||
if powerUp.Effect == game.Boost {
|
||||
if powerUp.Alliance == game.RedAlliance {
|
||||
redMode = led.BoostMode
|
||||
} else {
|
||||
blueMode = led.BoostMode
|
||||
}
|
||||
} else {
|
||||
if powerUp.Alliance == game.RedAlliance {
|
||||
redMode = led.ForceMode
|
||||
} else {
|
||||
blueMode = led.ForceMode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if seesaw.NearIsRed {
|
||||
leds.SetMode(redMode, blueMode)
|
||||
} else {
|
||||
leds.SetMode(blueMode, redMode)
|
||||
}
|
||||
}
|
||||
|
||||
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])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,13 +8,10 @@ package field
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena/game"
|
||||
"github.com/Team254/cheesy-arena/led"
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"github.com/Team254/cheesy-arena/network"
|
||||
"github.com/Team254/cheesy-arena/vaultled"
|
||||
"github.com/Team254/cheesy-arena/websocket"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ArenaNotifiers struct {
|
||||
@@ -41,8 +38,6 @@ type DisplayConfigurationMessage struct {
|
||||
}
|
||||
|
||||
type LedModeMessage struct {
|
||||
LedMode led.Mode
|
||||
VaultLedMode vaultled.Mode
|
||||
}
|
||||
|
||||
type MatchTimeMessage struct {
|
||||
@@ -128,7 +123,7 @@ func (arena *Arena) generateDisplayConfigurationMessage() interface{} {
|
||||
}
|
||||
|
||||
func (arena *Arena) generateLedModeMessage() interface{} {
|
||||
return &LedModeMessage{arena.ScaleLeds.GetCurrentMode(), arena.RedVaultLeds.CurrentForceMode}
|
||||
return &LedModeMessage{}
|
||||
}
|
||||
|
||||
func (arena *Arena) generateLowerThirdMessage() interface{} {
|
||||
@@ -167,15 +162,11 @@ func (arena *Arena) generateMatchTimingMessage() interface{} {
|
||||
|
||||
func (arena *Arena) generateRealtimeScoreMessage() interface{} {
|
||||
fields := struct {
|
||||
Red *audienceAllianceScoreFields
|
||||
Blue *audienceAllianceScoreFields
|
||||
ScaleOwnedBy game.Alliance
|
||||
Red *audienceAllianceScoreFields
|
||||
Blue *audienceAllianceScoreFields
|
||||
}{}
|
||||
fields.Red = getAudienceAllianceScoreFields(arena.RedRealtimeScore, arena.RedScoreSummary(),
|
||||
arena.RedVault, arena.RedSwitch)
|
||||
fields.Blue = getAudienceAllianceScoreFields(arena.BlueRealtimeScore, arena.BlueScoreSummary(),
|
||||
arena.BlueVault, arena.BlueSwitch)
|
||||
fields.ScaleOwnedBy = arena.Scale.GetOwnedBy()
|
||||
fields.Red = getAudienceAllianceScoreFields(arena.RedRealtimeScore, arena.RedScoreSummary())
|
||||
fields.Blue = getAudienceAllianceScoreFields(arena.BlueRealtimeScore, arena.BlueScoreSummary())
|
||||
return &fields
|
||||
}
|
||||
|
||||
@@ -237,27 +228,11 @@ func (arena *Arena) generateScoringStatusMessage() interface{} {
|
||||
}
|
||||
|
||||
// Constructs the data object for one alliance sent to the audience display for the realtime scoring overlay.
|
||||
func getAudienceAllianceScoreFields(allianceScore *RealtimeScore, allianceScoreSummary *game.ScoreSummary,
|
||||
allianceVault *game.Vault, allianceSwitch *game.Seesaw) *audienceAllianceScoreFields {
|
||||
func getAudienceAllianceScoreFields(allianceScore *RealtimeScore,
|
||||
allianceScoreSummary *game.ScoreSummary) *audienceAllianceScoreFields {
|
||||
fields := new(audienceAllianceScoreFields)
|
||||
fields.RealtimeScore = allianceScore
|
||||
fields.Score = allianceScoreSummary.Score
|
||||
if allianceVault.ForcePowerUp != nil {
|
||||
fields.ForceState = allianceVault.ForcePowerUp.GetState(time.Now())
|
||||
} else {
|
||||
fields.ForceState = game.Unplayed
|
||||
}
|
||||
if allianceVault.LevitatePlayed {
|
||||
fields.LevitateState = game.Expired
|
||||
} else {
|
||||
fields.LevitateState = game.Unplayed
|
||||
}
|
||||
if allianceVault.BoostPowerUp != nil {
|
||||
fields.BoostState = allianceVault.BoostPowerUp.GetState(time.Now())
|
||||
} else {
|
||||
fields.BoostState = game.Unplayed
|
||||
}
|
||||
fields.SwitchOwnedBy = allianceSwitch.GetOwnedBy()
|
||||
return fields
|
||||
}
|
||||
|
||||
|
||||
@@ -11,23 +11,23 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
port = 5568
|
||||
sourceName = "Cheesy Arena"
|
||||
packetTimeoutSec = 1
|
||||
numPixels = 114
|
||||
pixelDataOffset = 126
|
||||
nearStripUniverse = 1
|
||||
farStripUniverse = 2
|
||||
advatekPort = 5568
|
||||
advatekSourceName = "Cheesy Arena"
|
||||
advatekPacketTimeoutSec = 1
|
||||
advatekNumPixels = 114
|
||||
advatekPixelDataOffset = 126
|
||||
advatekNearStripUniverse = 1
|
||||
advatekFarStripUniverse = 2
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
nearStrip strip
|
||||
farStrip strip
|
||||
type AdvatekController struct {
|
||||
nearStrip advatekStrip
|
||||
farStrip advatekStrip
|
||||
conn net.Conn
|
||||
packet []byte
|
||||
}
|
||||
|
||||
func (controller *Controller) SetAddress(address string) error {
|
||||
func (controller *AdvatekController) SetAddress(address string) error {
|
||||
if controller.conn != nil {
|
||||
controller.conn.Close()
|
||||
controller.conn = nil
|
||||
@@ -35,7 +35,7 @@ func (controller *Controller) SetAddress(address string) error {
|
||||
|
||||
if address != "" {
|
||||
var err error
|
||||
if controller.conn, err = net.Dial("udp4", fmt.Sprintf("%s:%d", address, port)); err != nil {
|
||||
if controller.conn, err = net.Dial("udp4", fmt.Sprintf("%s:%d", address, advatekPort)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func (controller *Controller) SetAddress(address string) error {
|
||||
}
|
||||
|
||||
// Sets the current LED sequence mode and resets the intra-sequence counter to the beginning.
|
||||
func (controller *Controller) SetMode(nearMode, farMode Mode) {
|
||||
func (controller *AdvatekController) SetMode(nearMode, farMode StripMode) {
|
||||
if nearMode != controller.nearStrip.currentMode {
|
||||
controller.nearStrip.currentMode = nearMode
|
||||
controller.nearStrip.counter = 0
|
||||
@@ -56,7 +56,7 @@ func (controller *Controller) SetMode(nearMode, farMode Mode) {
|
||||
}
|
||||
|
||||
// Returns the current mode if both sides are in the same mode, or off otherwise.
|
||||
func (controller *Controller) GetCurrentMode() Mode {
|
||||
func (controller *AdvatekController) GetCurrentMode() StripMode {
|
||||
if controller.nearStrip.currentMode == controller.farStrip.currentMode {
|
||||
return controller.nearStrip.currentMode
|
||||
} else {
|
||||
@@ -64,16 +64,9 @@ func (controller *Controller) GetCurrentMode() Mode {
|
||||
}
|
||||
}
|
||||
|
||||
// Sets which side of the scale or switch belongs to which alliance. A value of true indicates that the side nearest the
|
||||
// scoring table is red.
|
||||
func (controller *Controller) SetSidedness(nearIsRed bool) {
|
||||
controller.nearStrip.isRed = nearIsRed
|
||||
controller.farStrip.isRed = !nearIsRed
|
||||
}
|
||||
|
||||
// Advances the pixel values through the current sequence and sends a packet if necessary. Should be called from a timed
|
||||
// loop.
|
||||
func (controller *Controller) Update() error {
|
||||
func (controller *AdvatekController) Update() error {
|
||||
if controller.conn == nil {
|
||||
// This controller is not configured; do nothing.
|
||||
return nil
|
||||
@@ -84,17 +77,17 @@ func (controller *Controller) Update() error {
|
||||
|
||||
// Create the template packet if it doesn't already exist.
|
||||
if len(controller.packet) == 0 {
|
||||
controller.packet = createBlankPacket(numPixels)
|
||||
controller.packet = createBlankAdvatekPacket(advatekNumPixels)
|
||||
}
|
||||
|
||||
// Send packets if the pixel values have changed.
|
||||
if controller.nearStrip.shouldSendPacket() {
|
||||
controller.nearStrip.populatePacketPixels(controller.packet[pixelDataOffset:])
|
||||
controller.sendPacket(nearStripUniverse)
|
||||
controller.nearStrip.populatePacketPixels(controller.packet[advatekPixelDataOffset:])
|
||||
controller.sendPacket(advatekNearStripUniverse)
|
||||
}
|
||||
if controller.farStrip.shouldSendPacket() {
|
||||
controller.farStrip.populatePacketPixels(controller.packet[pixelDataOffset:])
|
||||
controller.sendPacket(farStripUniverse)
|
||||
controller.farStrip.populatePacketPixels(controller.packet[advatekPixelDataOffset:])
|
||||
controller.sendPacket(advatekFarStripUniverse)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -102,8 +95,8 @@ 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 := pixelDataOffset + 3*numPixels
|
||||
func createBlankAdvatekPacket(numPixels int) []byte {
|
||||
size := advatekPixelDataOffset + 3*numPixels
|
||||
packet := make([]byte, size)
|
||||
|
||||
// Preamble size
|
||||
@@ -140,7 +133,7 @@ func createBlankPacket(numPixels int) []byte {
|
||||
packet[21] = 0x04
|
||||
|
||||
// Component ID
|
||||
for i, b := range []byte(sourceName) {
|
||||
for i, b := range []byte(advatekSourceName) {
|
||||
packet[22+i] = b
|
||||
}
|
||||
|
||||
@@ -156,7 +149,7 @@ func createBlankPacket(numPixels int) []byte {
|
||||
packet[43] = 0x02
|
||||
|
||||
// Source name
|
||||
for i, b := range []byte(sourceName) {
|
||||
for i, b := range []byte(advatekSourceName) {
|
||||
packet[44+i] = b
|
||||
}
|
||||
|
||||
@@ -208,7 +201,7 @@ func createBlankPacket(numPixels int) []byte {
|
||||
return packet
|
||||
}
|
||||
|
||||
func (controller *Controller) sendPacket(dmxUniverse int) error {
|
||||
func (controller *AdvatekController) sendPacket(dmxUniverse int) error {
|
||||
// Update non-static packet fields.
|
||||
controller.packet[111]++
|
||||
controller.packet[113] = byte(dmxUniverse >> 8)
|
||||
238
led/advatek_strip.go
Normal file
238
led/advatek_strip.go
Normal file
@@ -0,0 +1,238 @@
|
||||
// Copyright 2018 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
//
|
||||
// Represents an independently controlled LED strip.
|
||||
|
||||
package led
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
type advatekStrip struct {
|
||||
currentMode StripMode
|
||||
isRed bool
|
||||
pixels [advatekNumPixels][3]byte
|
||||
oldPixels [advatekNumPixels][3]byte
|
||||
counter int
|
||||
lastPacketTime time.Time
|
||||
}
|
||||
|
||||
// Calculates the current pixel values depending on the mode and elapsed counter cycles.
|
||||
func (strip *advatekStrip) updatePixels() {
|
||||
switch strip.currentMode {
|
||||
case RedMode:
|
||||
strip.updateSingleColorMode(Red)
|
||||
case GreenMode:
|
||||
strip.updateSingleColorMode(Green)
|
||||
case BlueMode:
|
||||
strip.updateSingleColorMode(Blue)
|
||||
case WhiteMode:
|
||||
strip.updateSingleColorMode(White)
|
||||
case PurpleMode:
|
||||
strip.updateSingleColorMode(Purple)
|
||||
case ChaseMode:
|
||||
strip.updateChaseMode()
|
||||
case RandomMode:
|
||||
strip.updateRandomMode()
|
||||
case FadeRedBlueMode:
|
||||
strip.updateFadeRedBlueMode()
|
||||
case FadeSingleMode:
|
||||
strip.updateFadeSingleMode()
|
||||
case GradientMode:
|
||||
strip.updateGradientMode()
|
||||
case BlinkMode:
|
||||
strip.updateBlinkMode()
|
||||
default:
|
||||
strip.updateOffMode()
|
||||
}
|
||||
strip.counter++
|
||||
}
|
||||
|
||||
// Returns true if the pixel data has changed or it has been too long since the last packet was sent.
|
||||
func (strip *advatekStrip) shouldSendPacket() bool {
|
||||
for i := 0; i < advatekNumPixels; i++ {
|
||||
if strip.pixels[i] != strip.oldPixels[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return time.Since(strip.lastPacketTime).Seconds() > advatekPacketTimeoutSec
|
||||
}
|
||||
|
||||
// Writes the pixel RGB values into the given packet in preparation for sending.
|
||||
func (strip *advatekStrip) populatePacketPixels(pixelData []byte) {
|
||||
for i, pixel := range strip.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.
|
||||
strip.oldPixels = strip.pixels
|
||||
strip.lastPacketTime = time.Now()
|
||||
}
|
||||
|
||||
// Returns the primary color (red or blue) of this strip.
|
||||
func (strip *advatekStrip) getColor() Color {
|
||||
if strip.isRed {
|
||||
return Red
|
||||
}
|
||||
return Blue
|
||||
}
|
||||
|
||||
// Returns the opposite primary color (red or blue) to this strip.
|
||||
func (strip *advatekStrip) getOppositeColor() Color {
|
||||
if strip.isRed {
|
||||
return Blue
|
||||
}
|
||||
return Red
|
||||
}
|
||||
|
||||
// Returns a color partway between purple and the primary color (red or blue) of this strip.
|
||||
func (strip *advatekStrip) getMidColor() Color {
|
||||
if strip.isRed {
|
||||
return PurpleBlue
|
||||
}
|
||||
return PurpleRed
|
||||
}
|
||||
|
||||
// Returns a dim version of the primary color (red or blue) of this strip.
|
||||
func (strip *advatekStrip) getDimColor() Color {
|
||||
if strip.isRed {
|
||||
return DimRed
|
||||
}
|
||||
return DimBlue
|
||||
}
|
||||
|
||||
// Returns a dim version of the opposite primary color (red or blue) of this strip.
|
||||
func (strip *advatekStrip) getDimOppositeColor() Color {
|
||||
if strip.isRed {
|
||||
return DimBlue
|
||||
}
|
||||
return DimRed
|
||||
}
|
||||
|
||||
// Returns the starting offset for the gradient mode for this strip.
|
||||
func (strip *advatekStrip) getGradientStartOffset() int {
|
||||
if strip.isRed {
|
||||
return advatekNumPixels / 3
|
||||
}
|
||||
return 2 * advatekNumPixels / 3
|
||||
}
|
||||
|
||||
func (strip *advatekStrip) updateOffMode() {
|
||||
for i := 0; i < advatekNumPixels; i++ {
|
||||
strip.pixels[i] = Colors[Black]
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *advatekStrip) updateSingleColorMode(color Color) {
|
||||
for i := 0; i < advatekNumPixels; i++ {
|
||||
strip.pixels[i] = Colors[color]
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *advatekStrip) updateChaseMode() {
|
||||
if strip.counter == int(Black)*advatekNumPixels { // Ignore colors listed after white.
|
||||
strip.counter = 0
|
||||
}
|
||||
color := Color(strip.counter / advatekNumPixels)
|
||||
pixelIndex := strip.counter % advatekNumPixels
|
||||
strip.pixels[pixelIndex] = Colors[color]
|
||||
}
|
||||
|
||||
func (strip *advatekStrip) updateRandomMode() {
|
||||
if strip.counter%10 != 0 {
|
||||
return
|
||||
}
|
||||
for i := 0; i < advatekNumPixels; i++ {
|
||||
strip.pixels[i] = Colors[Color(rand.Intn(int(Black)))] // Ignore colors listed after white.
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *advatekStrip) updateFadeRedBlueMode() {
|
||||
fadeCycles := 40
|
||||
holdCycles := 10
|
||||
if strip.counter == 4*holdCycles+4*fadeCycles {
|
||||
strip.counter = 0
|
||||
}
|
||||
|
||||
for i := 0; i < advatekNumPixels; i++ {
|
||||
if strip.counter < holdCycles {
|
||||
strip.pixels[i] = Colors[Black]
|
||||
} else if 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]
|
||||
} else if strip.counter < 2*holdCycles+2*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]
|
||||
} else if strip.counter < 3*holdCycles+3*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]
|
||||
} else if strip.counter < 4*holdCycles+4*fadeCycles {
|
||||
strip.pixels[i] = getFadeColor(Blue, Black, strip.counter-4*holdCycles-3*fadeCycles, fadeCycles)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *advatekStrip) updateFadeSingleMode() {
|
||||
offCycles := 50
|
||||
fadeCycles := 100
|
||||
if strip.counter == offCycles+2*fadeCycles {
|
||||
strip.counter = 0
|
||||
}
|
||||
|
||||
for i := 0; i < advatekNumPixels; i++ {
|
||||
if strip.counter < offCycles {
|
||||
strip.pixels[i] = Colors[Black]
|
||||
} else if 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *advatekStrip) updateGradientMode() {
|
||||
for i := 0; i < advatekNumPixels; i++ {
|
||||
strip.pixels[advatekNumPixels-i-1] = getGradientColor(i+strip.counter, 75)
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *advatekStrip) updateBlinkMode() {
|
||||
divisor := 10
|
||||
for i := 0; i < advatekNumPixels; i++ {
|
||||
if strip.counter%divisor < divisor/2 {
|
||||
strip.pixels[i] = Colors[White]
|
||||
} else {
|
||||
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]
|
||||
var fadeColor [3]byte
|
||||
for i := 0; i < 3; i++ {
|
||||
fadeColor[i] = byte(int(from[i]) + numerator*(int(to[i])-int(from[i]))/denominator)
|
||||
}
|
||||
return fadeColor
|
||||
}
|
||||
|
||||
// Calculates the value of a single pixel in a gradient.
|
||||
func getGradientColor(offset, numPixels int) [3]byte {
|
||||
offset %= numPixels
|
||||
if 3*offset < numPixels {
|
||||
return getFadeColor(Red, Green, 3*offset, numPixels)
|
||||
} else if 3*offset < 2*numPixels {
|
||||
return getFadeColor(Green, Blue, 3*offset-numPixels, numPixels)
|
||||
} else {
|
||||
return getFadeColor(Blue, Red, 3*offset-2*numPixels, numPixels)
|
||||
}
|
||||
}
|
||||
@@ -3,34 +3,33 @@
|
||||
//
|
||||
// Represents a Philips Color Kinetics LED controller with one output, as used in the 2018 vault.
|
||||
|
||||
package vaultled
|
||||
package led
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena/led"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
port = 6038
|
||||
packetTimeoutSec = 1
|
||||
numPixels = 17
|
||||
pixelDataOffset = 21
|
||||
colorKineticsPort = 6038
|
||||
colorKineticsPacketTimeoutSec = 1
|
||||
colorKineticsNumPixels = 17
|
||||
colorKineticsPixelDataOffset = 21
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
CurrentForceMode Mode
|
||||
CurrentLevitateMode Mode
|
||||
CurrentBoostMode Mode
|
||||
pixels [numPixels][3]byte
|
||||
oldPixels [numPixels][3]byte
|
||||
type ColorKineticsController struct {
|
||||
CurrentForceMode VaultMode
|
||||
CurrentLevitateMode VaultMode
|
||||
CurrentBoostMode VaultMode
|
||||
pixels [colorKineticsNumPixels][3]byte
|
||||
oldPixels [colorKineticsNumPixels][3]byte
|
||||
conn net.Conn
|
||||
packet []byte
|
||||
lastPacketTime time.Time
|
||||
}
|
||||
|
||||
func (controller *Controller) SetAddress(address string) error {
|
||||
func (controller *ColorKineticsController) SetAddress(address string) error {
|
||||
if controller.conn != nil {
|
||||
controller.conn.Close()
|
||||
controller.conn = nil
|
||||
@@ -38,7 +37,7 @@ func (controller *Controller) SetAddress(address string) error {
|
||||
|
||||
if address != "" {
|
||||
var err error
|
||||
if controller.conn, err = net.Dial("udp4", fmt.Sprintf("%s:%d", address, port)); err != nil {
|
||||
if controller.conn, err = net.Dial("udp4", fmt.Sprintf("%s:%d", address, colorKineticsPort)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -47,32 +46,32 @@ func (controller *Controller) SetAddress(address string) error {
|
||||
}
|
||||
|
||||
// Sets the current mode for the section of LEDs corresponding to the force powerup.
|
||||
func (controller *Controller) SetForceMode(mode Mode) {
|
||||
func (controller *ColorKineticsController) SetForceMode(mode VaultMode) {
|
||||
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) {
|
||||
func (controller *ColorKineticsController) SetLevitateMode(mode VaultMode) {
|
||||
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) {
|
||||
func (controller *ColorKineticsController) SetBoostMode(mode VaultMode) {
|
||||
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) {
|
||||
func (controller *ColorKineticsController) SetAllModes(mode VaultMode) {
|
||||
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 {
|
||||
func (controller *ColorKineticsController) Update() error {
|
||||
if controller.conn == nil {
|
||||
// This controller is not configured; do nothing.
|
||||
return nil
|
||||
@@ -80,47 +79,47 @@ func (controller *Controller) Update() error {
|
||||
|
||||
// Create the template packet if it doesn't already exist.
|
||||
if len(controller.packet) == 0 {
|
||||
controller.packet = createBlankPacket(numPixels)
|
||||
controller.packet = createBlankColorKineticsPacket(colorKineticsPort)
|
||||
}
|
||||
|
||||
// Send packets if the pixel values have changed.
|
||||
if controller.shouldSendPacket() {
|
||||
controller.populatePacketPixels(controller.packet[pixelDataOffset:])
|
||||
controller.populatePacketPixels(controller.packet[colorKineticsPixelDataOffset:])
|
||||
controller.sendPacket()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (controller *Controller) setPixels(offset int, mode Mode) {
|
||||
func (controller *ColorKineticsController) setPixels(offset int, mode VaultMode) {
|
||||
for i := 0; i < 5; i++ {
|
||||
controller.pixels[offset+i] = led.Colors[led.Black]
|
||||
controller.pixels[offset+i] = Colors[Black]
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case ThreeCubeMode:
|
||||
controller.pixels[offset+3] = led.Colors[led.Yellow]
|
||||
controller.pixels[offset+3] = Colors[Yellow]
|
||||
fallthrough
|
||||
case TwoCubeMode:
|
||||
controller.pixels[offset+2] = led.Colors[led.Yellow]
|
||||
controller.pixels[offset+2] = Colors[Yellow]
|
||||
fallthrough
|
||||
case OneCubeMode:
|
||||
controller.pixels[offset+1] = led.Colors[led.Yellow]
|
||||
controller.pixels[offset+1] = Colors[Yellow]
|
||||
case RedPlayedMode:
|
||||
for i := 0; i < 5; i++ {
|
||||
controller.pixels[offset+i] = led.Colors[led.Red]
|
||||
controller.pixels[offset+i] = Colors[Red]
|
||||
}
|
||||
case BluePlayedMode:
|
||||
for i := 0; i < 5; i++ {
|
||||
controller.pixels[offset+i] = led.Colors[led.Blue]
|
||||
controller.pixels[offset+i] = Colors[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
|
||||
func createBlankColorKineticsPacket(numPixels int) []byte {
|
||||
size := colorKineticsPixelDataOffset + 3*numPixels
|
||||
packet := make([]byte, size)
|
||||
|
||||
// Magic sequence
|
||||
@@ -167,17 +166,17 @@ func createBlankPacket(numPixels int) []byte {
|
||||
}
|
||||
|
||||
// Returns true if the pixel data has changed.
|
||||
func (controller *Controller) shouldSendPacket() bool {
|
||||
for i := 0; i < numPixels; i++ {
|
||||
func (controller *ColorKineticsController) shouldSendPacket() bool {
|
||||
for i := 0; i < colorKineticsNumPixels; i++ {
|
||||
if controller.pixels[i] != controller.oldPixels[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return time.Since(controller.lastPacketTime).Seconds() > packetTimeoutSec
|
||||
return time.Since(controller.lastPacketTime).Seconds() > colorKineticsPacketTimeoutSec
|
||||
}
|
||||
|
||||
// Writes the pixel RGB values into the given packet in preparation for sending.
|
||||
func (controller *Controller) populatePacketPixels(pixelData []byte) {
|
||||
func (controller *ColorKineticsController) populatePacketPixels(pixelData []byte) {
|
||||
for i, pixel := range controller.pixels {
|
||||
pixelData[3*i] = pixel[0]
|
||||
pixelData[3*i+1] = pixel[1]
|
||||
@@ -189,7 +188,7 @@ func (controller *Controller) populatePacketPixels(pixelData []byte) {
|
||||
controller.lastPacketTime = time.Now()
|
||||
}
|
||||
|
||||
func (controller *Controller) sendPacket() error {
|
||||
func (controller *ColorKineticsController) sendPacket() error {
|
||||
_, err := controller.conn.Write(controller.packet)
|
||||
if err != nil {
|
||||
return err
|
||||
391
led/strip.go
391
led/strip.go
@@ -1,391 +0,0 @@
|
||||
// Copyright 2018 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
//
|
||||
// Represents an independently controlled LED strip making up one half of a scale or switch LED array.
|
||||
|
||||
package led
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
type strip struct {
|
||||
currentMode Mode
|
||||
isRed bool
|
||||
pixels [numPixels][3]byte
|
||||
oldPixels [numPixels][3]byte
|
||||
counter int
|
||||
lastPacketTime time.Time
|
||||
}
|
||||
|
||||
// Calculates the current pixel values depending on the mode and elapsed counter cycles.
|
||||
func (strip *strip) updatePixels() {
|
||||
switch strip.currentMode {
|
||||
case RedMode:
|
||||
strip.updateSingleColorMode(Red)
|
||||
case GreenMode:
|
||||
strip.updateSingleColorMode(Green)
|
||||
case BlueMode:
|
||||
strip.updateSingleColorMode(Blue)
|
||||
case WhiteMode:
|
||||
strip.updateSingleColorMode(White)
|
||||
case PurpleMode:
|
||||
strip.updateSingleColorMode(Purple)
|
||||
case ChaseMode:
|
||||
strip.updateChaseMode()
|
||||
case WarmupMode:
|
||||
strip.updateWarmupMode()
|
||||
case Warmup2Mode:
|
||||
strip.updateWarmup2Mode()
|
||||
case Warmup3Mode:
|
||||
strip.updateWarmup3Mode()
|
||||
case Warmup4Mode:
|
||||
strip.updateWarmup4Mode()
|
||||
case OwnedMode:
|
||||
strip.updateOwnedMode()
|
||||
case NotOwnedMode:
|
||||
strip.updateNotOwnedMode()
|
||||
case ForceMode:
|
||||
strip.updateForceMode()
|
||||
case BoostMode:
|
||||
strip.updateBoostMode()
|
||||
case RandomMode:
|
||||
strip.updateRandomMode()
|
||||
case FadeRedBlueMode:
|
||||
strip.updateFadeRedBlueMode()
|
||||
case FadeSingleMode:
|
||||
strip.updateFadeSingleMode()
|
||||
case GradientMode:
|
||||
strip.updateGradientMode()
|
||||
case BlinkMode:
|
||||
strip.updateBlinkMode()
|
||||
default:
|
||||
strip.updateOffMode()
|
||||
}
|
||||
strip.counter++
|
||||
}
|
||||
|
||||
// Returns true if the pixel data has changed or it has been too long since the last packet was sent.
|
||||
func (strip *strip) shouldSendPacket() bool {
|
||||
for i := 0; i < numPixels; i++ {
|
||||
if strip.pixels[i] != strip.oldPixels[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return time.Since(strip.lastPacketTime).Seconds() > packetTimeoutSec
|
||||
}
|
||||
|
||||
// Writes the pixel RGB values into the given packet in preparation for sending.
|
||||
func (strip *strip) populatePacketPixels(pixelData []byte) {
|
||||
for i, pixel := range strip.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.
|
||||
strip.oldPixels = strip.pixels
|
||||
strip.lastPacketTime = time.Now()
|
||||
}
|
||||
|
||||
// Returns the primary color (red or blue) of this strip.
|
||||
func (strip *strip) getColor() Color {
|
||||
if strip.isRed {
|
||||
return Red
|
||||
}
|
||||
return Blue
|
||||
}
|
||||
|
||||
// Returns the opposite primary color (red or blue) to this strip.
|
||||
func (strip *strip) getOppositeColor() Color {
|
||||
if strip.isRed {
|
||||
return Blue
|
||||
}
|
||||
return Red
|
||||
}
|
||||
|
||||
// Returns a color partway between purple and the primary color (red or blue) of this strip.
|
||||
func (strip *strip) getMidColor() Color {
|
||||
if strip.isRed {
|
||||
return PurpleBlue
|
||||
}
|
||||
return PurpleRed
|
||||
}
|
||||
|
||||
// Returns a dim version of the primary color (red or blue) of this strip.
|
||||
func (strip *strip) getDimColor() Color {
|
||||
if strip.isRed {
|
||||
return DimRed
|
||||
}
|
||||
return DimBlue
|
||||
}
|
||||
|
||||
// Returns a dim version of the opposite primary color (red or blue) of this strip.
|
||||
func (strip *strip) getDimOppositeColor() Color {
|
||||
if strip.isRed {
|
||||
return DimBlue
|
||||
}
|
||||
return DimRed
|
||||
}
|
||||
|
||||
// Returns the starting offset for the gradient mode for this strip.
|
||||
func (strip *strip) getGradientStartOffset() int {
|
||||
if strip.isRed {
|
||||
return numPixels / 3
|
||||
}
|
||||
return 2 * numPixels / 3
|
||||
}
|
||||
|
||||
func (strip *strip) updateOffMode() {
|
||||
for i := 0; i < numPixels; i++ {
|
||||
strip.pixels[i] = Colors[Black]
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *strip) updateSingleColorMode(color Color) {
|
||||
for i := 0; i < numPixels; i++ {
|
||||
strip.pixels[i] = Colors[color]
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *strip) updateChaseMode() {
|
||||
if strip.counter == int(Black)*numPixels { // Ignore colors listed after white.
|
||||
strip.counter = 0
|
||||
}
|
||||
color := Color(strip.counter / numPixels)
|
||||
pixelIndex := strip.counter % numPixels
|
||||
strip.pixels[pixelIndex] = Colors[color]
|
||||
}
|
||||
|
||||
func (strip *strip) updateWarmupMode() {
|
||||
endCounter := 250
|
||||
if strip.counter == 0 {
|
||||
// Show solid white to start.
|
||||
for i := 0; i < numPixels; i++ {
|
||||
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()]
|
||||
}
|
||||
} else {
|
||||
// Prevent the counter from rolling over.
|
||||
strip.counter = endCounter
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *strip) updateWarmup2Mode() {
|
||||
startCounter := 100
|
||||
endCounter := 250
|
||||
if strip.counter < startCounter {
|
||||
// Show solid purple to start.
|
||||
for i := 0; i < numPixels; i++ {
|
||||
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,
|
||||
endCounter-startCounter)
|
||||
}
|
||||
} else {
|
||||
// Prevent the counter from rolling over.
|
||||
strip.counter = endCounter
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *strip) updateWarmup3Mode() {
|
||||
startCounter := 50
|
||||
middleCounter := 225
|
||||
endCounter := 250
|
||||
if strip.counter < startCounter {
|
||||
// Show solid purple to start.
|
||||
for i := 0; i < numPixels; i++ {
|
||||
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,
|
||||
middleCounter-startCounter)
|
||||
}
|
||||
} else if strip.counter <= endCounter {
|
||||
for i := 0; i < numPixels; i++ {
|
||||
strip.pixels[i] = getFadeColor(strip.getMidColor(), strip.getColor(), strip.counter-middleCounter,
|
||||
endCounter-middleCounter)
|
||||
}
|
||||
} else {
|
||||
// Maintain the current value and prevent the counter from rolling over.
|
||||
strip.counter = endCounter
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *strip) updateWarmup4Mode() {
|
||||
middleCounter := 100
|
||||
for i := 0; i < numPixels; i++ {
|
||||
strip.pixels[numPixels-i-1] = getGradientColor(i+strip.counter+strip.getGradientStartOffset(), numPixels/2)
|
||||
}
|
||||
if strip.counter >= middleCounter {
|
||||
for i := 0; i < numPixels; i++ {
|
||||
if i < strip.counter-middleCounter {
|
||||
strip.pixels[i] = Colors[strip.getColor()]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *strip) updateOwnedMode() {
|
||||
speedDivisor := 30
|
||||
pixelSpacing := 4
|
||||
if strip.counter%speedDivisor != 0 {
|
||||
return
|
||||
}
|
||||
for i := 0; i < numPixels; i++ {
|
||||
switch (i + strip.counter/speedDivisor) % pixelSpacing {
|
||||
case 0:
|
||||
fallthrough
|
||||
case 1:
|
||||
strip.pixels[len(strip.pixels)-i-1] = Colors[strip.getColor()]
|
||||
default:
|
||||
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()]
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *strip) updateForceMode() {
|
||||
speedDivisor := 30
|
||||
pixelSpacing := 7
|
||||
if strip.counter%speedDivisor != 0 {
|
||||
return
|
||||
}
|
||||
for i := 0; i < numPixels; i++ {
|
||||
switch (i + strip.counter/speedDivisor) % pixelSpacing {
|
||||
case 2:
|
||||
fallthrough
|
||||
case 4:
|
||||
strip.pixels[i] = Colors[strip.getColor()]
|
||||
case 3:
|
||||
strip.pixels[i] = Colors[strip.getDimOppositeColor()]
|
||||
default:
|
||||
strip.pixels[i] = Colors[Black]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *strip) updateBoostMode() {
|
||||
speedDivisor := 4
|
||||
pixelSpacing := 4
|
||||
if strip.counter%speedDivisor != 0 {
|
||||
return
|
||||
}
|
||||
for i := 0; i < numPixels; i++ {
|
||||
if i%pixelSpacing == strip.counter/speedDivisor%pixelSpacing {
|
||||
strip.pixels[i] = Colors[strip.getColor()]
|
||||
} else {
|
||||
strip.pixels[i] = Colors[Black]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *strip) updateRandomMode() {
|
||||
if strip.counter%10 != 0 {
|
||||
return
|
||||
}
|
||||
for i := 0; i < numPixels; i++ {
|
||||
strip.pixels[i] = Colors[Color(rand.Intn(int(Black)))] // Ignore colors listed after white.
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *strip) updateFadeRedBlueMode() {
|
||||
fadeCycles := 40
|
||||
holdCycles := 10
|
||||
if strip.counter == 4*holdCycles+4*fadeCycles {
|
||||
strip.counter = 0
|
||||
}
|
||||
|
||||
for i := 0; i < numPixels; i++ {
|
||||
if strip.counter < holdCycles {
|
||||
strip.pixels[i] = Colors[Black]
|
||||
} else if 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]
|
||||
} else if strip.counter < 2*holdCycles+2*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]
|
||||
} else if strip.counter < 3*holdCycles+3*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]
|
||||
} else if strip.counter < 4*holdCycles+4*fadeCycles {
|
||||
strip.pixels[i] = getFadeColor(Blue, Black, strip.counter-4*holdCycles-3*fadeCycles, fadeCycles)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *strip) updateFadeSingleMode() {
|
||||
offCycles := 50
|
||||
fadeCycles := 100
|
||||
if strip.counter == offCycles+2*fadeCycles {
|
||||
strip.counter = 0
|
||||
}
|
||||
|
||||
for i := 0; i < numPixels; i++ {
|
||||
if strip.counter < offCycles {
|
||||
strip.pixels[i] = Colors[Black]
|
||||
} else if 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *strip) updateGradientMode() {
|
||||
for i := 0; i < numPixels; i++ {
|
||||
strip.pixels[numPixels-i-1] = getGradientColor(i+strip.counter, 75)
|
||||
}
|
||||
}
|
||||
|
||||
func (strip *strip) updateBlinkMode() {
|
||||
divisor := 10
|
||||
for i := 0; i < numPixels; i++ {
|
||||
if strip.counter%divisor < divisor/2 {
|
||||
strip.pixels[i] = Colors[White]
|
||||
} else {
|
||||
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]
|
||||
var fadeColor [3]byte
|
||||
for i := 0; i < 3; i++ {
|
||||
fadeColor[i] = byte(int(from[i]) + numerator*(int(to[i])-int(from[i]))/denominator)
|
||||
}
|
||||
return fadeColor
|
||||
}
|
||||
|
||||
// Calculates the value of a single pixel in a gradient.
|
||||
func getGradientColor(offset, numPixels int) [3]byte {
|
||||
offset %= numPixels
|
||||
if 3*offset < numPixels {
|
||||
return getFadeColor(Red, Green, 3*offset, numPixels)
|
||||
} else if 3*offset < 2*numPixels {
|
||||
return getFadeColor(Green, Blue, 3*offset-numPixels, numPixels)
|
||||
} else {
|
||||
return getFadeColor(Blue, Red, 3*offset-2*numPixels, numPixels)
|
||||
}
|
||||
}
|
||||
@@ -5,24 +5,16 @@
|
||||
|
||||
package led
|
||||
|
||||
type Mode int
|
||||
type StripMode int
|
||||
|
||||
const (
|
||||
OffMode Mode = iota
|
||||
OffMode StripMode = iota
|
||||
RedMode
|
||||
GreenMode
|
||||
BlueMode
|
||||
WhiteMode
|
||||
PurpleMode
|
||||
ChaseMode
|
||||
WarmupMode
|
||||
Warmup2Mode
|
||||
Warmup3Mode
|
||||
Warmup4Mode
|
||||
OwnedMode
|
||||
NotOwnedMode
|
||||
ForceMode
|
||||
BoostMode
|
||||
RandomMode
|
||||
FadeRedBlueMode
|
||||
FadeSingleMode
|
||||
@@ -30,7 +22,7 @@ const (
|
||||
BlinkMode
|
||||
)
|
||||
|
||||
var ModeNames = map[Mode]string{
|
||||
var StripModeNames = map[StripMode]string{
|
||||
OffMode: "Off",
|
||||
RedMode: "Red",
|
||||
GreenMode: "Green",
|
||||
@@ -38,14 +30,6 @@ var ModeNames = map[Mode]string{
|
||||
WhiteMode: "White",
|
||||
PurpleMode: "Purple",
|
||||
ChaseMode: "Chase",
|
||||
WarmupMode: "Warmup",
|
||||
Warmup2Mode: "Warmup Purple",
|
||||
Warmup3Mode: "Warmup Sneaky",
|
||||
Warmup4Mode: "Warmup Gradient",
|
||||
OwnedMode: "Owned",
|
||||
NotOwnedMode: "Not Owned",
|
||||
ForceMode: "Force",
|
||||
BoostMode: "Boost",
|
||||
RandomMode: "Random",
|
||||
FadeRedBlueMode: "Fade Red/Blue",
|
||||
FadeSingleMode: "Fade Single",
|
||||
@@ -3,12 +3,12 @@
|
||||
//
|
||||
// Contains the set of display modes for the vault LEDs.
|
||||
|
||||
package vaultled
|
||||
package led
|
||||
|
||||
type Mode int
|
||||
type VaultMode int
|
||||
|
||||
const (
|
||||
OffMode Mode = iota
|
||||
VaultOffMode VaultMode = iota
|
||||
OneCubeMode
|
||||
TwoCubeMode
|
||||
ThreeCubeMode
|
||||
@@ -16,8 +16,8 @@ const (
|
||||
BluePlayedMode
|
||||
)
|
||||
|
||||
var ModeNames = map[Mode]string{
|
||||
OffMode: "Off",
|
||||
var VaultModeNames = map[VaultMode]string{
|
||||
VaultOffMode: "Off",
|
||||
OneCubeMode: "One Cube",
|
||||
TwoCubeMode: "Two Cubes",
|
||||
ThreeCubeMode: "Three Cubes",
|
||||
@@ -28,11 +28,6 @@ type EventSettings struct {
|
||||
PlcAddress string
|
||||
AdminPassword string
|
||||
ReaderPassword string
|
||||
ScaleLedAddress string
|
||||
RedSwitchLedAddress string
|
||||
BlueSwitchLedAddress string
|
||||
RedVaultLedAddress string
|
||||
BlueVaultLedAddress string
|
||||
}
|
||||
|
||||
const eventSettingsId = 0
|
||||
|
||||
@@ -4,6 +4,26 @@ package plc
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[heartbeat-0]
|
||||
_ = x[matchReset-1]
|
||||
_ = x[stackLightGreen-2]
|
||||
_ = x[stackLightOrange-3]
|
||||
_ = x[stackLightRed-4]
|
||||
_ = x[stackLightBlue-5]
|
||||
_ = x[stackLightBuzzer-6]
|
||||
_ = x[red1EthernetDisable-7]
|
||||
_ = x[red2EthernetDisable-8]
|
||||
_ = x[red3EthernetDisable-9]
|
||||
_ = x[blue1EthernetDisable-10]
|
||||
_ = x[blue2EthernetDisable-11]
|
||||
_ = x[blue3EthernetDisable-12]
|
||||
_ = x[coilCount-13]
|
||||
}
|
||||
|
||||
const _coil_name = "heartbeatmatchResetstackLightGreenstackLightOrangestackLightRedstackLightBluestackLightBuzzerred1EthernetDisablered2EthernetDisablered3EthernetDisableblue1EthernetDisableblue2EthernetDisableblue3EthernetDisablecoilCount"
|
||||
|
||||
var _coil_index = [...]uint8{0, 9, 19, 34, 50, 63, 77, 93, 112, 131, 150, 170, 190, 210, 219}
|
||||
|
||||
@@ -4,9 +4,29 @@ package plc
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _input_name = "fieldEstopredEstop1redEstop2redEstop3blueEstop1blueEstop2blueEstop3redConnected1redConnected2redConnected3blueConnected1blueConnected2blueConnected3scaleNearscaleFarredSwitchNearredSwitchFarblueSwitchNearblueSwitchFarredForceActivateredLevitateActivateredBoostActivateblueForceActivateblueLevitateActivateblueBoostActivateinputCount"
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[fieldEstop-0]
|
||||
_ = x[redEstop1-1]
|
||||
_ = x[redEstop2-2]
|
||||
_ = x[redEstop3-3]
|
||||
_ = x[blueEstop1-4]
|
||||
_ = x[blueEstop2-5]
|
||||
_ = x[blueEstop3-6]
|
||||
_ = x[redConnected1-7]
|
||||
_ = x[redConnected2-8]
|
||||
_ = x[redConnected3-9]
|
||||
_ = x[blueConnected1-10]
|
||||
_ = x[blueConnected2-11]
|
||||
_ = x[blueConnected3-12]
|
||||
_ = x[inputCount-13]
|
||||
}
|
||||
|
||||
var _input_index = [...]uint16{0, 10, 19, 28, 37, 47, 57, 67, 80, 93, 106, 120, 134, 148, 157, 165, 178, 190, 204, 217, 233, 252, 268, 285, 305, 322, 332}
|
||||
const _input_name = "fieldEstopredEstop1redEstop2redEstop3blueEstop1blueEstop2blueEstop3redConnected1redConnected2redConnected3blueConnected1blueConnected2blueConnected3inputCount"
|
||||
|
||||
var _input_index = [...]uint8{0, 10, 19, 28, 37, 47, 57, 67, 80, 93, 106, 120, 134, 148, 158}
|
||||
|
||||
func (i input) String() string {
|
||||
if i < 0 || i >= input(len(_input_index)-1) {
|
||||
|
||||
44
plc/plc.go
44
plc/plc.go
@@ -52,18 +52,6 @@ const (
|
||||
blueConnected1
|
||||
blueConnected2
|
||||
blueConnected3
|
||||
scaleNear
|
||||
scaleFar
|
||||
redSwitchNear
|
||||
redSwitchFar
|
||||
blueSwitchNear
|
||||
blueSwitchFar
|
||||
redForceActivate
|
||||
redLevitateActivate
|
||||
redBoostActivate
|
||||
blueForceActivate
|
||||
blueLevitateActivate
|
||||
blueBoostActivate
|
||||
inputCount
|
||||
)
|
||||
|
||||
@@ -77,12 +65,6 @@ const (
|
||||
blue1Bandwidth
|
||||
blue2Bandwidth
|
||||
blue3Bandwidth
|
||||
redForceDistance
|
||||
redLevitateDistance
|
||||
redBoostDistance
|
||||
blueForceDistance
|
||||
blueLevitateDistance
|
||||
blueBoostDistance
|
||||
registerCount
|
||||
)
|
||||
|
||||
@@ -180,32 +162,6 @@ func (plc *Plc) GetTeamEstops() ([3]bool, [3]bool) {
|
||||
return redEstops, blueEstops
|
||||
}
|
||||
|
||||
// Returns the state of the scale and the red and blue switches.
|
||||
func (plc *Plc) GetScaleAndSwitches() ([2]bool, [2]bool, [2]bool) {
|
||||
var scale, redSwitch, blueSwitch [2]bool
|
||||
|
||||
scale[0] = plc.inputs[scaleNear]
|
||||
scale[1] = plc.inputs[scaleFar]
|
||||
redSwitch[0] = plc.inputs[redSwitchNear]
|
||||
redSwitch[1] = plc.inputs[redSwitchFar]
|
||||
blueSwitch[0] = plc.inputs[blueSwitchNear]
|
||||
blueSwitch[1] = plc.inputs[blueSwitchFar]
|
||||
|
||||
return scale, redSwitch, blueSwitch
|
||||
}
|
||||
|
||||
// Returns the state of the red and blue vault power cube sensors.
|
||||
func (plc *Plc) GetVaults() (uint16, uint16, uint16, uint16, uint16, uint16) {
|
||||
return plc.registers[redForceDistance], plc.registers[redLevitateDistance], plc.registers[redBoostDistance],
|
||||
plc.registers[blueForceDistance], plc.registers[blueLevitateDistance], plc.registers[blueBoostDistance]
|
||||
}
|
||||
|
||||
// Returns the state of the red and blue power up buttons on the vaults.
|
||||
func (plc *Plc) GetPowerUpButtons() (bool, bool, bool, bool, bool, bool) {
|
||||
return plc.inputs[redForceActivate], plc.inputs[redLevitateActivate], plc.inputs[redBoostActivate],
|
||||
plc.inputs[blueForceActivate], plc.inputs[blueLevitateActivate], plc.inputs[blueBoostActivate]
|
||||
}
|
||||
|
||||
// Set the on/off state of the stack lights on the scoring table.
|
||||
func (plc *Plc) SetStackLights(red, blue, green bool) {
|
||||
plc.coils[stackLightRed] = red
|
||||
|
||||
@@ -4,9 +4,22 @@ package plc
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _register_name = "red1Bandwidthred2Bandwidthred3Bandwidthblue1Bandwidthblue2Bandwidthblue3BandwidthredForceDistanceredLevitateDistanceredBoostDistanceblueForceDistanceblueLevitateDistanceblueBoostDistanceregisterCount"
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[red1Bandwidth-0]
|
||||
_ = x[red2Bandwidth-1]
|
||||
_ = x[red3Bandwidth-2]
|
||||
_ = x[blue1Bandwidth-3]
|
||||
_ = x[blue2Bandwidth-4]
|
||||
_ = x[blue3Bandwidth-5]
|
||||
_ = x[registerCount-6]
|
||||
}
|
||||
|
||||
var _register_index = [...]uint8{0, 13, 26, 39, 53, 67, 81, 97, 116, 132, 149, 169, 186, 199}
|
||||
const _register_name = "red1Bandwidthred2Bandwidthred3Bandwidthblue1Bandwidthblue2Bandwidthblue3BandwidthregisterCount"
|
||||
|
||||
var _register_index = [...]uint8{0, 13, 26, 39, 53, 67, 81, 94}
|
||||
|
||||
func (i register) String() string {
|
||||
if i < 0 || i >= register(len(_register_index)-1) {
|
||||
|
||||
@@ -53,30 +53,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<div class="well">
|
||||
<legend>Switch/Scale LEDs</legend>
|
||||
{{range $i, $name := .LedModeNames}}
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="ledMode" value="{{$i}}" onclick="setLedMode();">{{$name}}
|
||||
</label>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<div class="well">
|
||||
<legend>Vault LEDs</legend>
|
||||
{{range $i, $name := .VaultLedModeNames}}
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="vaultLedMode" value="{{$i}}" onclick="setLedMode();">{{$name}}
|
||||
</label>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{define "script"}}
|
||||
|
||||
@@ -211,39 +211,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>LEDs</legend>
|
||||
<div class="form-group">
|
||||
<label class="col-lg-5 control-label">Scale Controller Address</label>
|
||||
<div class="col-lg-7">
|
||||
<input type="text" class="form-control" name="scaleLedAddress" value="{{.ScaleLedAddress}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-lg-5 control-label">Red Switch Controller Address</label>
|
||||
<div class="col-lg-7">
|
||||
<input type="text" class="form-control" name="redSwitchLedAddress" value="{{.RedSwitchLedAddress}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-lg-5 control-label">Blue Switch Controller Address</label>
|
||||
<div class="col-lg-7">
|
||||
<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">
|
||||
<button type="submit" class="btn btn-info">Save</button>
|
||||
|
||||
@@ -10,7 +10,6 @@ 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"
|
||||
"github.com/Team254/cheesy-arena/websocket"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"io"
|
||||
@@ -35,10 +34,10 @@ func (web *Web) ledPlcGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
InputNames []string
|
||||
RegisterNames []string
|
||||
CoilNames []string
|
||||
LedModeNames map[led.Mode]string
|
||||
VaultLedModeNames map[vaultled.Mode]string
|
||||
}{web.arena.EventSettings, plc.GetInputNames(), plc.GetRegisterNames(), plc.GetCoilNames(), led.ModeNames,
|
||||
vaultled.ModeNames}
|
||||
LedModeNames map[led.StripMode]string
|
||||
VaultLedModeNames map[led.VaultMode]string
|
||||
}{web.arena.EventSettings, plc.GetInputNames(), plc.GetRegisterNames(), plc.GetCoilNames(), led.StripModeNames,
|
||||
led.VaultModeNames}
|
||||
err = template.ExecuteTemplate(w, "base", data)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
@@ -87,13 +86,6 @@ func (web *Web) ledPlcWebsocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ws.WriteError(err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
web.arena.ScaleLeds.SetMode(modeMessage.LedMode, modeMessage.LedMode)
|
||||
web.arena.RedSwitchLeds.SetMode(modeMessage.LedMode, modeMessage.LedMode)
|
||||
web.arena.BlueSwitchLeds.SetMode(modeMessage.LedMode, modeMessage.LedMode)
|
||||
web.arena.RedVaultLeds.SetAllModes(modeMessage.VaultLedMode)
|
||||
web.arena.BlueVaultLeds.SetAllModes(modeMessage.VaultLedMode)
|
||||
web.arena.LedModeNotifier.Notify()
|
||||
default:
|
||||
ws.WriteError(fmt.Sprintf("Invalid message type '%s'.", messageType))
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/Team254/cheesy-arena/field"
|
||||
"github.com/Team254/cheesy-arena/led"
|
||||
"github.com/Team254/cheesy-arena/vaultled"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
@@ -26,16 +24,8 @@ func TestSetupLedPlcWebsocket(t *testing.T) {
|
||||
ws := websocket.NewTestWebsocket(conn)
|
||||
|
||||
// Should get a few status updates right after connection.
|
||||
ledModeMessage := readLedModes(t, ws)
|
||||
assert.Equal(t, led.GreenMode, ledModeMessage.LedMode)
|
||||
assert.Equal(t, vaultled.OffMode, ledModeMessage.VaultLedMode)
|
||||
readLedModes(t, ws)
|
||||
readWebsocketType(t, ws, "plcIoChange")
|
||||
|
||||
// Change the LED modes and verify that the new modes are broadcast back.
|
||||
ws.Write("setLedMode", field.LedModeMessage{LedMode: led.RandomMode, VaultLedMode: vaultled.BluePlayedMode})
|
||||
ledModeMessage = readLedModes(t, ws)
|
||||
assert.Equal(t, led.RandomMode, ledModeMessage.LedMode)
|
||||
assert.Equal(t, vaultled.BluePlayedMode, ledModeMessage.VaultLedMode)
|
||||
}
|
||||
|
||||
func readLedModes(t *testing.T, ws *websocket.Websocket) *field.LedModeMessage {
|
||||
|
||||
@@ -66,11 +66,6 @@ func (web *Web) settingsPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
eventSettings.PlcAddress = r.PostFormValue("plcAddress")
|
||||
eventSettings.AdminPassword = r.PostFormValue("adminPassword")
|
||||
eventSettings.ReaderPassword = r.PostFormValue("readerPassword")
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user