Update assumptions about PLC interface.

This commit is contained in:
Patrick Fairbank
2018-04-15 10:45:03 -07:00
parent 19f1681477
commit 8b8468f4c8
5 changed files with 97 additions and 138 deletions

View File

@@ -207,7 +207,6 @@ func (arena *Arena) LoadMatch(match *model.Match) error {
// Reset the realtime scores.
arena.RedRealtimeScore = NewRealtimeScore()
arena.BlueRealtimeScore = NewRealtimeScore()
arena.Plc.ResetCounts()
arena.FieldReset = false
arena.scale = new(game.Seesaw)
arena.redSwitch = new(game.Seesaw)
@@ -376,7 +375,6 @@ func (arena *Arena) Update() {
arena.AudienceDisplayScreen = "match"
arena.AudienceDisplayNotifier.Notify(nil)
arena.FieldTestMode = ""
arena.Plc.ResetCounts()
arena.sendGameSpecificDataPacket()
if !arena.MuteMatchSounds {
arena.PlaySoundNotifier.Notify("match-warmup")
@@ -677,10 +675,10 @@ func (arena *Arena) handlePlcInput() {
}
// Handle vaults.
redForceCubes, redLevitateCubes, redBoostCubes, blueForceCubes, blueLevitateCubes, blueBoostCubes :=
redForceDistance, redLevitateDistance, redBoostDistance, blueForceDistance, blueLevitateDistance, blueBoostDistance :=
arena.Plc.GetVaults()
arena.redVault.UpdateCubes(redForceCubes, redLevitateCubes, redBoostCubes)
arena.blueVault.UpdateCubes(blueForceCubes, blueLevitateCubes, blueBoostCubes)
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)

View File

@@ -13,15 +13,14 @@ import (
)
type Plc struct {
IsHealthy bool
address string
handler *modbus.TCPClientHandler
client modbus.Client
Inputs [37]bool
Counters [0]uint16
Coils [8]bool
cycleCounter int
resetCountCycles int
IsHealthy bool
address string
handler *modbus.TCPClientHandler
client modbus.Client
Inputs [inputCount]bool
Registers [registerCount]uint16
Coils [coilCount]bool
cycleCounter int
}
const (
@@ -34,57 +33,58 @@ const (
// Discrete inputs
const (
fieldEstop = iota
scaleNear
scaleFar
redEstop1
redEstop2
redEstop3
redSwitchNear
redSwitchFar
redForceCube1
redForceCube2
redForceCube3
redForceButton
redLevitateCube1
redLevitateCube2
redLevitateCube3
redLevitateButton
redBoostCube1
redBoostCube2
redBoostCube3
redBoostButton
blueEstop1
blueEstop2
blueEstop3
redConnected1
redConnected2
redConnected3
blueConnected1
blueConnected2
blueConnected3
scaleNear
scaleFar
redSwitchNear
redSwitchFar
blueSwitchNear
blueSwitchFar
blueForceCube1
blueForceCube2
blueForceCube3
blueForceButton
blueLevitate1
blueLevitate2
blueLevitate3
blueLevitateButton
blueBoostCube1
blueBoostCube2
blueBoostCube3
blueBoostButton
redForceActivate
redLevitateActivate
redBoostActivate
blueForceActivate
blueLevitateActivate
blueBoostActivate
inputCount
)
// 16-bit registers
const ()
const (
red1Bandwidth = iota
red2Bandwidth
red3Bandwidth
blue1Bandwidth
blue2Bandwidth
blue3Bandwidth
redForceDistance
redLevitateDistance
redBoostDistance
blueForceDistance
blueLevitateDistance
blueBoostDistance
registerCount
)
// Coils
const (
redForceLight = iota
redLevitateLight
redBoostLight
blueForceLight
blueLevitateLight
blueBoostLight
resetCounts
heartbeat
heartbeat = iota
stackLightGreen
stackLightOrange
stackLightRed
stackLightBlue
coilCount
)
func (plc *Plc) SetAddress(address string) {
@@ -163,51 +163,15 @@ func (plc *Plc) GetScaleAndSwitches() ([2]bool, [2]bool, [2]bool) {
}
// Returns the state of the red and blue vault power cube sensors.
func (plc *Plc) GetVaults() ([3]bool, [3]bool, [3]bool, [3]bool, [3]bool, [3]bool) {
var redForce, redLevitate, redBoost, blueForce, blueLevitate, blueBoost [3]bool
redForce[0] = plc.Inputs[redForceCube1]
redForce[1] = plc.Inputs[redForceCube2]
redForce[2] = plc.Inputs[redForceCube3]
redLevitate[0] = plc.Inputs[redLevitateCube1]
redLevitate[1] = plc.Inputs[redLevitateCube2]
redLevitate[2] = plc.Inputs[redLevitateCube3]
redBoost[0] = plc.Inputs[redBoostCube1]
redBoost[1] = plc.Inputs[redBoostCube2]
redBoost[2] = plc.Inputs[redBoostCube3]
blueForce[0] = plc.Inputs[blueForceCube1]
blueForce[1] = plc.Inputs[blueForceCube2]
blueForce[2] = plc.Inputs[blueForceCube3]
blueLevitate[0] = plc.Inputs[blueLevitate1]
blueLevitate[1] = plc.Inputs[blueLevitate2]
blueLevitate[2] = plc.Inputs[blueLevitate3]
blueBoost[0] = plc.Inputs[blueBoostCube1]
blueBoost[1] = plc.Inputs[blueBoostCube2]
blueBoost[2] = plc.Inputs[blueBoostCube3]
return redForce, redLevitate, redBoost, blueForce, blueLevitate, blueBoost
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[redForceButton], plc.Inputs[redLevitateButton], plc.Inputs[redBoostButton],
plc.Inputs[blueForceButton], plc.Inputs[blueLevitateButton], plc.Inputs[blueBoostButton]
}
// Resets the counter counts to zero.
func (plc *Plc) ResetCounts() {
plc.Coils[resetCounts] = true
plc.resetCountCycles = 0
}
// Sets the state of the lights inside the power up buttons on the vaults.
func (plc *Plc) SetPowerUpLights(redForce, redLevitate, redBoost, blueForce, blueLevitate, blueBoost bool) {
plc.Coils[redForceLight] = redForce
plc.Coils[redLevitateLight] = redLevitate
plc.Coils[redBoostLight] = redBoost
plc.Coils[blueForceLight] = blueForce
plc.Coils[blueLevitateLight] = blueLevitate
plc.Coils[blueBoostLight] = blueBoost
return plc.Inputs[redForceActivate], plc.Inputs[redLevitateActivate], plc.Inputs[redBoostActivate],
plc.Inputs[blueForceActivate], plc.Inputs[blueLevitateActivate], plc.Inputs[blueBoostActivate]
}
func (plc *Plc) GetCycleState(max, index, duration int) bool {
@@ -258,22 +222,22 @@ func (plc *Plc) readInputs() bool {
}
func (plc *Plc) readCounters() bool {
if len(plc.Counters) == 0 {
if len(plc.Registers) == 0 {
return true
}
registers, err := plc.client.ReadHoldingRegisters(0, uint16(len(plc.Counters)))
registers, err := plc.client.ReadHoldingRegisters(0, uint16(len(plc.Registers)))
if err != nil {
log.Printf("PLC error reading registers: %v", err)
return false
}
if len(registers)/2 < len(plc.Counters) {
if len(registers)/2 < len(plc.Registers) {
log.Printf("Insufficient length of PLC counters: got %d bytes, expected %d words.", len(registers),
len(plc.Counters))
len(plc.Registers))
return false
}
copy(plc.Counters[:], byteToUint(registers, len(plc.Counters)))
copy(plc.Registers[:], byteToUint(registers, len(plc.Registers)))
return true
}
@@ -288,11 +252,6 @@ func (plc *Plc) writeCoils() bool {
return false
}
if plc.resetCountCycles > 5 {
plc.Coils[resetCounts] = false // Need to send a short pulse to reset the counters.
} else {
plc.resetCountCycles++
}
return true
}

View File

@@ -20,10 +20,10 @@ type Vault struct {
}
// Updates the state of the vault given the state of the individual power cube sensors.
func (vault *Vault) UpdateCubes(forceCubes, levitateCubes, boostCubes [3]bool) {
vault.numForceCubes = countCubes(forceCubes)
vault.numLevitateCubes = countCubes(levitateCubes)
vault.numBoostCubes = countCubes(boostCubes)
func (vault *Vault) UpdateCubes(forceDistance, levitateDistance, boostDistance uint16) {
vault.numForceCubes = countCubes(forceDistance)
vault.numLevitateCubes = countCubes(levitateDistance)
vault.numBoostCubes = countCubes(boostDistance)
}
// Updates the state of the vault given the state of the power up buttons.
@@ -48,14 +48,15 @@ func (vault *Vault) GetNumCubes() int {
return vault.numForceCubes + vault.numLevitateCubes + vault.numBoostCubes
}
func countCubes(cubes [3]bool) int {
if cubes[0] {
if cubes[1] {
if cubes[2] {
return 3
}
return 2
}
func countCubes(distance uint16) int {
// TODO(patrick): Update with real values once there is a physical setup to test with.
if distance >= 3000 {
return 3
}
if distance >= 2000 {
return 2
}
if distance >= 1000 {
return 1
}
return 0

View File

@@ -10,49 +10,50 @@ import (
)
func TestVaultNumCubes(t *testing.T) {
// TODO(patrick): Update with real values once there is a physical setup to test with.
vault := Vault{}
assert.Equal(t, 0, vault.GetNumCubes())
vault.UpdateCubes([3]bool{true, false, false}, [3]bool{false, false, false}, [3]bool{false, false, false})
vault.UpdateCubes(1000, 0, 0)
assert.Equal(t, 1, vault.GetNumCubes())
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{true, false, true}, [3]bool{true, false, false})
vault.UpdateCubes(0, 1000, 1000)
assert.Equal(t, 2, vault.GetNumCubes())
vault.UpdateCubes([3]bool{false, true, true}, [3]bool{false, false, true}, [3]bool{true, true, false})
vault.UpdateCubes(0, 0, 2000)
assert.Equal(t, 2, vault.GetNumCubes())
vault.UpdateCubes([3]bool{true, true, false}, [3]bool{true, true, false}, [3]bool{true, true, true})
vault.UpdateCubes(2000, 2000, 3000)
assert.Equal(t, 7, vault.GetNumCubes())
vault.UpdateCubes([3]bool{true, true, true}, [3]bool{true, true, true}, [3]bool{true, true, true})
vault.UpdateCubes(3000, 3000, 3000)
assert.Equal(t, 9, vault.GetNumCubes())
}
func TestVaultLevitate(t *testing.T) {
vault := Vault{}
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{false, false, false})
vault.UpdateCubes(0, 0, 0)
vault.UpdateButtons(false, true, false, time.Now())
assert.False(t, vault.LevitatePlayed)
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{true, false, false}, [3]bool{false, false, false})
vault.UpdateCubes(0, 1000, 0)
vault.UpdateButtons(false, true, false, time.Now())
assert.False(t, vault.LevitatePlayed)
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{true, true, false}, [3]bool{false, false, false})
vault.UpdateCubes(0, 2000, 0)
vault.UpdateButtons(false, true, false, time.Now())
assert.False(t, vault.LevitatePlayed)
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{true, true, true}, [3]bool{false, false, false})
vault.UpdateCubes(0, 3000, 0)
vault.UpdateButtons(true, false, true, time.Now())
assert.False(t, vault.LevitatePlayed)
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{true, true, true}, [3]bool{false, false, false})
vault.UpdateCubes(0, 3000, 0)
vault.UpdateButtons(false, true, false, time.Now())
assert.True(t, vault.LevitatePlayed)
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{true, true, true}, [3]bool{false, false, false})
vault.UpdateCubes(0, 3000, 0)
vault.UpdateButtons(false, false, false, time.Now())
assert.True(t, vault.LevitatePlayed)
}
@@ -61,16 +62,16 @@ func TestVaultForce(t *testing.T) {
vault := Vault{alliance: blueAlliance}
ResetPowerUps()
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{false, false, false})
vault.UpdateCubes(0, 0, 0)
vault.UpdateButtons(true, false, false, time.Now())
assert.Nil(t, vault.ForcePowerUp)
vault.UpdateCubes([3]bool{true, true, true}, [3]bool{false, false, false}, [3]bool{false, false, false})
vault.UpdateCubes(3000, 0, 0)
vault.UpdateButtons(false, true, true, time.Now())
assert.Nil(t, vault.ForcePowerUp)
// Activation with one cube.
vault.UpdateCubes([3]bool{true, false, false}, [3]bool{false, false, false}, [3]bool{false, false, false})
vault.UpdateCubes(1000, 0, 0)
vault.UpdateButtons(true, false, false, time.Now())
if assert.NotNil(t, vault.ForcePowerUp) {
assert.Equal(t, blueAlliance, vault.ForcePowerUp.alliance)
@@ -81,7 +82,7 @@ func TestVaultForce(t *testing.T) {
// Activation with two cubes.
vault = Vault{alliance: redAlliance}
ResetPowerUps()
vault.UpdateCubes([3]bool{true, true, false}, [3]bool{false, false, false}, [3]bool{false, false, false})
vault.UpdateCubes(2000, 0, 0)
vault.UpdateButtons(true, false, false, time.Now())
if assert.NotNil(t, vault.ForcePowerUp) {
assert.Equal(t, redAlliance, vault.ForcePowerUp.alliance)
@@ -92,7 +93,7 @@ func TestVaultForce(t *testing.T) {
// Activation with three cubes.
vault = Vault{alliance: blueAlliance}
ResetPowerUps()
vault.UpdateCubes([3]bool{true, true, true}, [3]bool{false, false, false}, [3]bool{false, false, false})
vault.UpdateCubes(3000, 0, 0)
vault.UpdateButtons(true, false, false, time.Now())
assert.NotNil(t, vault.ForcePowerUp)
if assert.NotNil(t, vault.ForcePowerUp) {
@@ -101,7 +102,7 @@ func TestVaultForce(t *testing.T) {
assert.Equal(t, 3, vault.ForcePowerUp.level)
}
vault.UpdateCubes([3]bool{true, true, true}, [3]bool{false, false, false}, [3]bool{false, false, false})
vault.UpdateCubes(3000, 0, 0)
vault.UpdateButtons(false, false, false, time.Now())
assert.NotNil(t, vault.ForcePowerUp)
}
@@ -110,16 +111,16 @@ func TestVaultBoost(t *testing.T) {
vault := Vault{alliance: blueAlliance}
ResetPowerUps()
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{false, false, false})
vault.UpdateCubes(0, 0, 0)
vault.UpdateButtons(false, false, true, time.Now())
assert.Nil(t, vault.BoostPowerUp)
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{true, true, true})
vault.UpdateCubes(0, 0, 3000)
vault.UpdateButtons(true, true, false, time.Now())
assert.Nil(t, vault.BoostPowerUp)
// Activation with one cube.
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{true, false, false})
vault.UpdateCubes(0, 0, 1000)
vault.UpdateButtons(false, false, true, time.Now())
if assert.NotNil(t, vault.BoostPowerUp) {
assert.Equal(t, blueAlliance, vault.BoostPowerUp.alliance)
@@ -130,7 +131,7 @@ func TestVaultBoost(t *testing.T) {
// Activation with two cubes.
vault = Vault{alliance: redAlliance}
ResetPowerUps()
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{true, true, false})
vault.UpdateCubes(0, 0, 2000)
vault.UpdateButtons(false, false, true, time.Now())
if assert.NotNil(t, vault.BoostPowerUp) {
assert.Equal(t, redAlliance, vault.BoostPowerUp.alliance)
@@ -141,7 +142,7 @@ func TestVaultBoost(t *testing.T) {
// Activation with three cubes.
vault = Vault{alliance: blueAlliance}
ResetPowerUps()
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{true, true, true})
vault.UpdateCubes(0, 0, 3000)
vault.UpdateButtons(false, false, true, time.Now())
assert.NotNil(t, vault.BoostPowerUp)
if assert.NotNil(t, vault.BoostPowerUp) {
@@ -150,7 +151,7 @@ func TestVaultBoost(t *testing.T) {
assert.Equal(t, 3, vault.BoostPowerUp.level)
}
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{true, true, true})
vault.UpdateCubes(0, 0, 3000)
vault.UpdateButtons(false, false, false, time.Now())
assert.NotNil(t, vault.BoostPowerUp)
}

View File

@@ -30,7 +30,7 @@ func (web *Web) fieldGetHandler(w http.ResponseWriter, r *http.Request) {
Counters []uint16
Coils []bool
}{web.arena.EventSettings, web.arena.AllianceStationDisplays, web.arena.FieldTestMode, web.arena.Plc.Inputs[:],
web.arena.Plc.Counters[:], web.arena.Plc.Coils[:]}
web.arena.Plc.Registers[:], web.arena.Plc.Coils[:]}
err = template.ExecuteTemplate(w, "base", data)
if err != nil {
handleWebErr(w, err)