diff --git a/db/migrations/20140524160241_CreateEventSettings.sql b/db/migrations/20140524160241_CreateEventSettings.sql index e1000af..b75106b 100644 --- a/db/migrations/20140524160241_CreateEventSettings.sql +++ b/db/migrations/20140524160241_CreateEventSettings.sql @@ -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 diff --git a/field/arena.go b/field/arena.go index 472cf23..c4226be 100644 --- a/field/arena.go +++ b/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]) } } diff --git a/field/arena_notifiers.go b/field/arena_notifiers.go index b1b8e18..8260f5c 100644 --- a/field/arena_notifiers.go +++ b/field/arena_notifiers.go @@ -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 } diff --git a/led/controller.go b/led/advatek_controller.go similarity index 75% rename from led/controller.go rename to led/advatek_controller.go index 6603bd7..a95ce98 100644 --- a/led/controller.go +++ b/led/advatek_controller.go @@ -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) diff --git a/led/advatek_strip.go b/led/advatek_strip.go new file mode 100644 index 0000000..2bb08cd --- /dev/null +++ b/led/advatek_strip.go @@ -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) + } +} diff --git a/vaultled/controller.go b/led/color_kinetics_controller.go similarity index 63% rename from vaultled/controller.go rename to led/color_kinetics_controller.go index 1bdea42..03d2b48 100644 --- a/vaultled/controller.go +++ b/led/color_kinetics_controller.go @@ -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 diff --git a/led/strip.go b/led/strip.go deleted file mode 100644 index 87f6e35..0000000 --- a/led/strip.go +++ /dev/null @@ -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) - } -} diff --git a/led/mode.go b/led/strip_mode.go similarity index 61% rename from led/mode.go rename to led/strip_mode.go index ffea02c..41dd6d1 100644 --- a/led/mode.go +++ b/led/strip_mode.go @@ -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", diff --git a/vaultled/mode.go b/led/vault_mode.go similarity index 75% rename from vaultled/mode.go rename to led/vault_mode.go index 32a9518..36b4244 100644 --- a/vaultled/mode.go +++ b/led/vault_mode.go @@ -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", diff --git a/model/event_settings.go b/model/event_settings.go index 068282b..456400d 100644 --- a/model/event_settings.go +++ b/model/event_settings.go @@ -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 diff --git a/plc/coil_string.go b/plc/coil_string.go index 3ca5064..5459399 100644 --- a/plc/coil_string.go +++ b/plc/coil_string.go @@ -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} diff --git a/plc/input_string.go b/plc/input_string.go index 0967c1c..aeedd69 100644 --- a/plc/input_string.go +++ b/plc/input_string.go @@ -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) { diff --git a/plc/plc.go b/plc/plc.go index db5dee3..739874b 100644 --- a/plc/plc.go +++ b/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 diff --git a/plc/register_string.go b/plc/register_string.go index 032ee29..5931c6c 100644 --- a/plc/register_string.go +++ b/plc/register_string.go @@ -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) { diff --git a/templates/setup_led_plc.html b/templates/setup_led_plc.html index 541a157..3a8da19 100644 --- a/templates/setup_led_plc.html +++ b/templates/setup_led_plc.html @@ -53,30 +53,6 @@ -