Hook LED modes up to field state.

This commit is contained in:
Patrick Fairbank
2018-07-21 22:28:22 -07:00
parent 5f457f96ec
commit 738b5a0e7b
11 changed files with 206 additions and 109 deletions

View File

@@ -12,6 +12,7 @@ import (
"github.com/Team254/cheesy-arena/model"
"github.com/Team254/cheesy-arena/partner"
"log"
"math/rand"
"time"
)
@@ -73,14 +74,15 @@ type Arena struct {
AllianceSelectionNotifier *Notifier
LowerThirdNotifier *Notifier
ReloadDisplaysNotifier *Notifier
ScaleLeds led.Controller
RedSwitchLeds led.Controller
BlueSwitchLeds led.Controller
Scale *game.Seesaw
RedSwitch *game.Seesaw
BlueSwitch *game.Seesaw
RedVault *game.Vault
BlueVault *game.Vault
ScaleLeds led.Controller
RedSwitchLeds led.Controller
BlueSwitchLeds led.Controller
warmupLedMode led.Mode
}
type ArenaStatus struct {
@@ -234,9 +236,9 @@ func (arena *Arena) LoadMatch(match *model.Match) error {
game.ResetPowerUps()
// Set a consistent initial value for field element sidedness.
arena.Scale.SetSidedness(true)
arena.RedSwitch.SetSidedness(true)
arena.BlueSwitch.SetSidedness(true)
arena.Scale.NearIsRed = true
arena.RedSwitch.NearIsRed = true
arena.BlueSwitch.NearIsRed = true
arena.ScaleLeds.SetSidedness(true)
arena.RedSwitchLeds.SetSidedness(true)
arena.BlueSwitchLeds.SetSidedness(true)
@@ -321,9 +323,9 @@ func (arena *Arena) StartMatch() error {
// Configure the field elements with the game-specific data.
switchNearIsRed := arena.CurrentMatch.GameSpecificData[0] == 'L'
scaleNearIsRed := arena.CurrentMatch.GameSpecificData[1] == 'L'
arena.Scale.SetSidedness(scaleNearIsRed)
arena.RedSwitch.SetSidedness(switchNearIsRed)
arena.BlueSwitch.SetSidedness(switchNearIsRed)
arena.Scale.NearIsRed = scaleNearIsRed
arena.RedSwitch.NearIsRed = switchNearIsRed
arena.BlueSwitch.NearIsRed = switchNearIsRed
arena.ScaleLeds.SetSidedness(scaleNearIsRed)
arena.RedSwitchLeds.SetSidedness(switchNearIsRed)
arena.BlueSwitchLeds.SetSidedness(switchNearIsRed)
@@ -411,12 +413,12 @@ func (arena *Arena) Update() {
arena.AudienceDisplayScreen = "match"
arena.AudienceDisplayNotifier.Notify(nil)
arena.sendGameSpecificDataPacket()
arena.ScaleLeds.SetMode(led.WarmupMode, led.WarmupMode)
arena.RedSwitchLeds.SetMode(led.WarmupMode, led.WarmupMode)
arena.BlueSwitchLeds.SetMode(led.WarmupMode, led.WarmupMode)
if !arena.MuteMatchSounds {
arena.PlaySoundNotifier.Notify("match-warmup")
}
// 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
@@ -509,10 +511,7 @@ func (arena *Arena) Update() {
// Handle field sensors/lights/motors.
arena.handlePlcInput()
arena.handlePlcOutput()
arena.ScaleLeds.Update()
arena.RedSwitchLeds.Update()
arena.BlueSwitchLeds.Update()
arena.handleLeds()
}
// Loops indefinitely to track and update the arena components.
@@ -751,6 +750,73 @@ func (arena *Arena) handlePlcOutput() {
// TODO(patrick): Update for 2018.
}
func (arena *Arena) handleLeds() {
switch arena.MatchState {
case WarmupPeriod:
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:
fallthrough
case EndgamePeriod:
handleSeesawTeleopLeds(arena.Scale, &arena.ScaleLeds)
handleSeesawTeleopLeds(arena.RedSwitch, &arena.RedSwitchLeds)
handleSeesawTeleopLeds(arena.BlueSwitch, &arena.BlueSwitchLeds)
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.ScaleLeds.SetMode(led.FadeSingleMode, led.FadeSingleMode)
arena.RedSwitchLeds.SetMode(led.FadeSingleMode, led.FadeSingleMode)
arena.BlueSwitchLeds.SetMode(led.FadeSingleMode, led.FadeSingleMode)
}
arena.ScaleLeds.Update()
arena.RedSwitchLeds.Update()
arena.BlueSwitchLeds.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 (arena *Arena) handleEstop(station string, state bool) {
allianceStation := arena.AllianceStations[station]
if state {

View File

@@ -12,11 +12,11 @@ import (
const powerUpDurationSec = 10
// Power up type/effect enum.
type effect int
type PowerUpEffect int
const (
force effect = iota
boost
Force PowerUpEffect = iota
Boost
)
// Power up state enum.
@@ -31,8 +31,8 @@ const (
type PowerUp struct {
Alliance
effect
level int
Effect PowerUpEffect
Level int
startTime time.Time
}
@@ -57,7 +57,7 @@ func (powerUp *PowerUp) getEndTime() time.Time {
}
// Returns the current active power up, or nil if there isn't one.
func getActivePowerUp(currentTime time.Time) *PowerUp {
func GetActivePowerUp(currentTime time.Time) *PowerUp {
for _, powerUp := range powerUpUses {
if powerUp.GetState(currentTime) == Active {
return powerUp

View File

@@ -31,13 +31,13 @@ func TestPowerUpActivate(t *testing.T) {
assert.Equal(t, timeAfterStart(45), powerUp2.startTime)
}
assert.Nil(t, getActivePowerUp(timeAfterStart(29.9)))
assert.Equal(t, powerUp1, getActivePowerUp(timeAfterStart(30.1)))
assert.Equal(t, powerUp1, getActivePowerUp(timeAfterStart(39.9)))
assert.Nil(t, getActivePowerUp(timeAfterStart(42)))
assert.Equal(t, powerUp2, getActivePowerUp(timeAfterStart(45.1)))
assert.Equal(t, powerUp2, getActivePowerUp(timeAfterStart(54.9)))
assert.Nil(t, getActivePowerUp(timeAfterStart(55.1)))
assert.Nil(t, GetActivePowerUp(timeAfterStart(29.9)))
assert.Equal(t, powerUp1, GetActivePowerUp(timeAfterStart(30.1)))
assert.Equal(t, powerUp1, GetActivePowerUp(timeAfterStart(39.9)))
assert.Nil(t, GetActivePowerUp(timeAfterStart(42)))
assert.Equal(t, powerUp2, GetActivePowerUp(timeAfterStart(45.1)))
assert.Equal(t, powerUp2, GetActivePowerUp(timeAfterStart(54.9)))
assert.Nil(t, GetActivePowerUp(timeAfterStart(55.1)))
}
func TestPowerUpQueue(t *testing.T) {
@@ -56,8 +56,8 @@ func TestPowerUpQueue(t *testing.T) {
powerUp3 := &PowerUp{Alliance: RedAlliance}
assert.NotNil(t, maybeActivatePowerUp(powerUp3, timeAfterStart(81)))
assert.Equal(t, powerUp1, getActivePowerUp(timeAfterStart(69.9)))
assert.Equal(t, powerUp2, getActivePowerUp(timeAfterStart(70.1)))
assert.Equal(t, powerUp1, GetActivePowerUp(timeAfterStart(69.9)))
assert.Equal(t, powerUp2, GetActivePowerUp(timeAfterStart(70.1)))
}
func timeAfterStart(sec float32) time.Time {

View File

@@ -19,7 +19,7 @@ const (
type Seesaw struct {
Kind Alliance // Red or blue indicates that it is a switch; neither indicates the scale.
nearIsRed bool
NearIsRed bool
ownerships []*Ownership
}
@@ -30,27 +30,21 @@ type Ownership struct {
endTime *time.Time
}
// 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 (seesaw *Seesaw) SetSidedness(nearIsRed bool) {
seesaw.nearIsRed = nearIsRed
}
// Updates the internal timing state of the scale or switch given the current state of the sensors.
func (seesaw *Seesaw) UpdateState(state [2]bool, currentTime time.Time) {
ownedBy := NeitherAlliance
// Check if there is an active force power up for this seesaw.
currentPowerUp := getActivePowerUp(currentTime)
if currentPowerUp != nil && currentPowerUp.effect == force &&
(seesaw.Kind == NeitherAlliance && currentPowerUp.level >= 2 ||
(seesaw.Kind == currentPowerUp.Alliance && (currentPowerUp.level == 1 || currentPowerUp.level == 3))) {
currentPowerUp := GetActivePowerUp(currentTime)
if currentPowerUp != nil && currentPowerUp.Effect == Force &&
(seesaw.Kind == NeitherAlliance && currentPowerUp.Level >= 2 ||
(seesaw.Kind == currentPowerUp.Alliance && (currentPowerUp.Level == 1 || currentPowerUp.Level == 3))) {
ownedBy = currentPowerUp.Alliance
} else {
// Determine current ownership from sensor state.
if state[0] && !state[1] && seesaw.nearIsRed || state[1] && !state[0] && !seesaw.nearIsRed {
if state[0] && !state[1] && seesaw.NearIsRed || state[1] && !state[0] && !seesaw.NearIsRed {
ownedBy = RedAlliance
} else if state[0] && !state[1] && !seesaw.nearIsRed || state[1] && !state[0] && seesaw.nearIsRed {
} else if state[0] && !state[1] && !seesaw.NearIsRed || state[1] && !state[0] && seesaw.NearIsRed {
ownedBy = BlueAlliance
}
}
@@ -131,9 +125,9 @@ func (ownership *Ownership) getSeconds(startTime, endTime time.Time, ignoreBoost
// Find the boost power up applicable to this seesaw and alliance, if it exists.
var boostPowerUp *PowerUp
for _, powerUp := range powerUpUses {
if powerUp.effect == boost && ownership.ownedBy == powerUp.Alliance {
if ownership.seesaw.Kind == NeitherAlliance && powerUp.level >= 2 ||
ownership.seesaw.Kind != NeitherAlliance && (powerUp.level == 1 || powerUp.level == 3) {
if powerUp.Effect == Boost && ownership.ownedBy == powerUp.Alliance {
if ownership.seesaw.Kind == NeitherAlliance && powerUp.Level >= 2 ||
ownership.seesaw.Kind != NeitherAlliance && (powerUp.Level == 1 || powerUp.Level == 3) {
boostPowerUp = powerUp
break
}

View File

@@ -32,7 +32,7 @@ func TestSecondCounting(t *testing.T) {
ResetPowerUps()
redSwitch := &Seesaw{Kind: RedAlliance}
redSwitch.SetSidedness(true)
redSwitch.NearIsRed = true
// Test that there is no accumulation before the start of the match.
redSwitch.UpdateState([2]bool{true, false}, timeAfterStart(-20))
@@ -70,14 +70,14 @@ func TestForce(t *testing.T) {
ResetPowerUps()
blueSwitch := &Seesaw{Kind: BlueAlliance}
blueSwitch.SetSidedness(true)
blueSwitch.NearIsRed = true
scale := &Seesaw{Kind: NeitherAlliance}
scale.SetSidedness(true)
scale.NearIsRed = true
// Force switch only.
blueSwitch.UpdateState([2]bool{true, false}, timeAfterStart(0))
scale.UpdateState([2]bool{true, false}, timeAfterStart(0))
powerUp := &PowerUp{Alliance: BlueAlliance, effect: force, level: 1}
powerUp := &PowerUp{Alliance: BlueAlliance, Effect: Force, Level: 1}
maybeActivatePowerUp(powerUp, timeAfterStart(2.5))
blueSwitch.UpdateState([2]bool{true, false}, timeAfterStart(2.5))
scale.UpdateState([2]bool{true, false}, timeAfterStart(2.5))
@@ -91,7 +91,7 @@ func TestForce(t *testing.T) {
assert.Equal(t, 0.0, scale.GetBlueSeconds(timeAfterStart(0), timeAfterStart(15)))
// Force scale only.
powerUp = &PowerUp{Alliance: BlueAlliance, effect: force, level: 2}
powerUp = &PowerUp{Alliance: BlueAlliance, Effect: Force, Level: 2}
maybeActivatePowerUp(powerUp, timeAfterStart(20))
blueSwitch.UpdateState([2]bool{true, false}, timeAfterStart(20))
scale.UpdateState([2]bool{true, false}, timeAfterStart(20))
@@ -101,7 +101,7 @@ func TestForce(t *testing.T) {
assert.Equal(t, 10.0, scale.GetBlueSeconds(timeAfterStart(20), timeAfterStart(40)))
// Force both switch and scale.
powerUp = &PowerUp{Alliance: BlueAlliance, effect: force, level: 3}
powerUp = &PowerUp{Alliance: BlueAlliance, Effect: Force, Level: 3}
maybeActivatePowerUp(powerUp, timeAfterStart(50))
blueSwitch.UpdateState([2]bool{true, false}, timeAfterStart(50))
scale.UpdateState([2]bool{true, false}, timeAfterStart(50))
@@ -115,14 +115,14 @@ func TestBoost(t *testing.T) {
ResetPowerUps()
blueSwitch := &Seesaw{Kind: BlueAlliance}
blueSwitch.SetSidedness(true)
blueSwitch.NearIsRed = true
scale := &Seesaw{Kind: NeitherAlliance}
scale.SetSidedness(false)
scale.NearIsRed = false
// Test within continuous ownership period.
blueSwitch.UpdateState([2]bool{false, true}, timeAfterStart(20))
scale.UpdateState([2]bool{true, false}, timeAfterStart(20))
powerUp := &PowerUp{Alliance: BlueAlliance, effect: boost, level: 2}
powerUp := &PowerUp{Alliance: BlueAlliance, Effect: Boost, Level: 2}
maybeActivatePowerUp(powerUp, timeAfterStart(25))
assert.Equal(t, 5.0, scale.GetBlueSeconds(timeAfterStart(0), timeAfterStart(25)))
assert.Equal(t, 6.0, scale.GetBlueSeconds(timeAfterStart(0), timeAfterStart(25.5)))
@@ -136,7 +136,7 @@ func TestBoost(t *testing.T) {
ResetPowerUps()
blueSwitch.UpdateState([2]bool{false, false}, timeAfterStart(44))
scale.UpdateState([2]bool{false, false}, timeAfterStart(44))
powerUp = &PowerUp{Alliance: BlueAlliance, effect: boost, level: 3}
powerUp = &PowerUp{Alliance: BlueAlliance, Effect: Boost, Level: 3}
maybeActivatePowerUp(powerUp, timeAfterStart(45))
assert.Equal(t, 0.0, blueSwitch.GetBlueSeconds(timeAfterStart(45), timeAfterStart(50)))
assert.Equal(t, 0.0, scale.GetBlueSeconds(timeAfterStart(45), timeAfterStart(50)))
@@ -151,7 +151,7 @@ func TestBoost(t *testing.T) {
ResetPowerUps()
scale.UpdateState([2]bool{false, true}, timeAfterStart(65))
assert.Equal(t, 5.0, scale.GetRedSeconds(timeAfterStart(65), timeAfterStart(70)))
powerUp = &PowerUp{Alliance: RedAlliance, effect: boost, level: 2}
powerUp = &PowerUp{Alliance: RedAlliance, Effect: Boost, Level: 2}
maybeActivatePowerUp(powerUp, timeAfterStart(70))
scale.UpdateState([2]bool{false, false}, timeAfterStart(72.5))
assert.Equal(t, 10.0, scale.GetRedSeconds(timeAfterStart(65), timeAfterStart(72.5)))
@@ -163,7 +163,7 @@ func TestBoost(t *testing.T) {
// Test with just the switch.
blueSwitch.UpdateState([2]bool{false, true}, timeAfterStart(100))
scale.UpdateState([2]bool{true, false}, timeAfterStart(100))
powerUp = &PowerUp{Alliance: BlueAlliance, effect: boost, level: 1}
powerUp = &PowerUp{Alliance: BlueAlliance, Effect: Boost, Level: 1}
maybeActivatePowerUp(powerUp, timeAfterStart(100))
assert.Equal(t, 20.0, blueSwitch.GetBlueSeconds(timeAfterStart(100), timeAfterStart(110)))
assert.Equal(t, 10.0, scale.GetBlueSeconds(timeAfterStart(100), timeAfterStart(110)))

View File

@@ -35,16 +35,16 @@ func (vault *Vault) UpdateButtons(forceButton, levitateButton, boostButton bool,
}
if forceButton && vault.ForceCubes > 0 && vault.ForcePowerUp == nil {
vault.ForcePowerUp = maybeActivatePowerUp(&PowerUp{effect: force, Alliance: vault.Alliance,
level: vault.ForceCubes}, currentTime)
vault.ForcePowerUp = maybeActivatePowerUp(&PowerUp{Effect: Force, Alliance: vault.Alliance,
Level: vault.ForceCubes}, currentTime)
if vault.ForcePowerUp != nil {
vault.newlyPlayedPowerUp = "force"
}
}
if boostButton && vault.BoostCubes > 0 && vault.BoostPowerUp == nil {
vault.BoostPowerUp = maybeActivatePowerUp(&PowerUp{effect: boost, Alliance: vault.Alliance,
level: vault.BoostCubes}, currentTime)
vault.BoostPowerUp = maybeActivatePowerUp(&PowerUp{Effect: Boost, Alliance: vault.Alliance,
Level: vault.BoostCubes}, currentTime)
if vault.BoostPowerUp != nil {
vault.newlyPlayedPowerUp = "boost"
}

View File

@@ -87,8 +87,8 @@ func TestVaultForce(t *testing.T) {
vault.UpdateButtons(true, false, false, time.Now())
if assert.NotNil(t, vault.ForcePowerUp) {
assert.Equal(t, BlueAlliance, vault.ForcePowerUp.Alliance)
assert.Equal(t, force, vault.ForcePowerUp.effect)
assert.Equal(t, 1, vault.ForcePowerUp.level)
assert.Equal(t, Force, vault.ForcePowerUp.Effect)
assert.Equal(t, 1, vault.ForcePowerUp.Level)
}
// Activation with two cubes.
@@ -98,8 +98,8 @@ func TestVaultForce(t *testing.T) {
vault.UpdateButtons(true, false, false, time.Now())
if assert.NotNil(t, vault.ForcePowerUp) {
assert.Equal(t, RedAlliance, vault.ForcePowerUp.Alliance)
assert.Equal(t, force, vault.ForcePowerUp.effect)
assert.Equal(t, 2, vault.ForcePowerUp.level)
assert.Equal(t, Force, vault.ForcePowerUp.Effect)
assert.Equal(t, 2, vault.ForcePowerUp.Level)
}
// Activation with three cubes.
@@ -110,8 +110,8 @@ func TestVaultForce(t *testing.T) {
assert.NotNil(t, vault.ForcePowerUp)
if assert.NotNil(t, vault.ForcePowerUp) {
assert.Equal(t, BlueAlliance, vault.ForcePowerUp.Alliance)
assert.Equal(t, force, vault.ForcePowerUp.effect)
assert.Equal(t, 3, vault.ForcePowerUp.level)
assert.Equal(t, Force, vault.ForcePowerUp.Effect)
assert.Equal(t, 3, vault.ForcePowerUp.Level)
}
vault.UpdateCubes(3000, 0, 0)
@@ -136,8 +136,8 @@ func TestVaultBoost(t *testing.T) {
vault.UpdateButtons(false, false, true, time.Now())
if assert.NotNil(t, vault.BoostPowerUp) {
assert.Equal(t, BlueAlliance, vault.BoostPowerUp.Alliance)
assert.Equal(t, boost, vault.BoostPowerUp.effect)
assert.Equal(t, 1, vault.BoostPowerUp.level)
assert.Equal(t, Boost, vault.BoostPowerUp.Effect)
assert.Equal(t, 1, vault.BoostPowerUp.Level)
}
// Activation with two cubes.
@@ -147,8 +147,8 @@ func TestVaultBoost(t *testing.T) {
vault.UpdateButtons(false, false, true, time.Now())
if assert.NotNil(t, vault.BoostPowerUp) {
assert.Equal(t, RedAlliance, vault.BoostPowerUp.Alliance)
assert.Equal(t, boost, vault.BoostPowerUp.effect)
assert.Equal(t, 2, vault.BoostPowerUp.level)
assert.Equal(t, Boost, vault.BoostPowerUp.Effect)
assert.Equal(t, 2, vault.BoostPowerUp.Level)
}
// Activation with three cubes.
@@ -159,8 +159,8 @@ func TestVaultBoost(t *testing.T) {
assert.NotNil(t, vault.BoostPowerUp)
if assert.NotNil(t, vault.BoostPowerUp) {
assert.Equal(t, BlueAlliance, vault.BoostPowerUp.Alliance)
assert.Equal(t, boost, vault.BoostPowerUp.effect)
assert.Equal(t, 3, vault.BoostPowerUp.level)
assert.Equal(t, Boost, vault.BoostPowerUp.Effect)
assert.Equal(t, 3, vault.BoostPowerUp.Level)
}
vault.UpdateCubes(0, 0, 3000)

View File

@@ -35,6 +35,6 @@ var colors = map[color][3]byte{
black: {0, 0, 0},
purpleRed: {200, 0, 50},
purpleBlue: {50, 0, 200},
dimRed: {100, 0, 0},
dimBlue: {0, 0, 100},
dimRed: {50, 0, 0},
dimBlue: {0, 0, 50},
}

View File

@@ -45,10 +45,14 @@ 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) {
controller.nearStrip.currentMode = nearMode
controller.nearStrip.counter = 0
controller.farStrip.currentMode = farMode
controller.farStrip.counter = 0
if nearMode != controller.nearStrip.currentMode {
controller.nearStrip.currentMode = nearMode
controller.nearStrip.counter = 0
}
if farMode != controller.farStrip.currentMode {
controller.farStrip.currentMode = farMode
controller.farStrip.counter = 0
}
}
// Returns the current mode if both sides are in the same mode, or off otherwise.

View File

@@ -23,28 +23,30 @@ const (
ForceMode
BoostMode
RandomMode
FadeMode
FadeRedBlueMode
FadeSingleMode
GradientMode
BlinkMode
)
var ModeNames = map[Mode]string{
OffMode: "Off",
RedMode: "Red",
GreenMode: "Green",
BlueMode: "Blue",
WhiteMode: "White",
ChaseMode: "Chase",
WarmupMode: "Warmup",
Warmup2Mode: "Warmup Purple",
Warmup3Mode: "Warmup Sneaky",
Warmup4Mode: "Warmup Gradient",
OwnedMode: "Owned",
NotOwnedMode: "Not Owned",
ForceMode: "Force",
BoostMode: "Boost",
RandomMode: "Random",
FadeMode: "Fade",
GradientMode: "Gradient",
BlinkMode: "Blink",
OffMode: "Off",
RedMode: "Red",
GreenMode: "Green",
BlueMode: "Blue",
WhiteMode: "White",
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",
GradientMode: "Gradient",
BlinkMode: "Blink",
}

View File

@@ -50,8 +50,10 @@ func (strip *strip) updatePixels() {
strip.updateBoostMode()
case RandomMode:
strip.updateRandomMode()
case FadeMode:
strip.updateFadeMode()
case FadeRedBlueMode:
strip.updateFadeRedBlueMode()
case FadeSingleMode:
strip.updateFadeSingleMode()
case GradientMode:
strip.updateGradientMode()
case BlinkMode:
@@ -117,6 +119,14 @@ func (strip *strip) getDimColor() color {
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 {
@@ -231,10 +241,13 @@ func (strip *strip) updateOwnedMode() {
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]
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]
}
}
}
@@ -256,9 +269,9 @@ func (strip *strip) updateForceMode() {
case 2:
fallthrough
case 4:
strip.pixels[i] = colors[strip.getOppositeColor()]
strip.pixels[i] = colors[strip.getColor()]
case 3:
strip.pixels[i] = colors[strip.getDimColor()]
strip.pixels[i] = colors[strip.getDimOppositeColor()]
default:
strip.pixels[i] = colors[black]
}
@@ -289,7 +302,7 @@ func (strip *strip) updateRandomMode() {
}
}
func (strip *strip) updateFadeMode() {
func (strip *strip) updateFadeRedBlueMode() {
fadeCycles := 40
holdCycles := 10
if strip.counter == 4*holdCycles+4*fadeCycles {
@@ -317,6 +330,24 @@ func (strip *strip) updateFadeMode() {
}
}
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)