Skip to content

Commit

Permalink
Refactor to slightly improve memory safety of TeamWifiStatus.
Browse files Browse the repository at this point in the history
  • Loading branch information
patfair committed Oct 14, 2023
1 parent 45bebc4 commit c177997
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 67 deletions.
78 changes: 50 additions & 28 deletions field/arena.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,13 @@ type Arena struct {
}

type AllianceStation struct {
DsConn *DriverStationConnection
Ethernet bool
Astop bool
Estop bool
Bypass bool
Team *model.Team
DsConn *DriverStationConnection
Ethernet bool
Astop bool
Estop bool
Bypass bool
Team *model.Team
WifiStatus network.TeamWifiStatus
}

// Creates the arena and sets it to its initial state.
Expand All @@ -98,16 +99,6 @@ func NewArena(dbPath string) (*Arena, error) {
arena.configureNotifiers()
arena.Plc = new(plc.ModbusPlc)

var err error
arena.Database, err = model.OpenDatabase(dbPath)
if err != nil {
return nil, err
}
err = arena.LoadSettings()
if err != nil {
return nil, err
}

arena.AllianceStations = make(map[string]*AllianceStation)
arena.AllianceStations["R1"] = new(AllianceStation)
arena.AllianceStations["R2"] = new(AllianceStation)
Expand All @@ -118,6 +109,16 @@ func NewArena(dbPath string) (*Arena, error) {

arena.Displays = make(map[string]*Display)

var err error
arena.Database, err = model.OpenDatabase(dbPath)
if err != nil {
return nil, err
}
err = arena.LoadSettings()
if err != nil {
return nil, err
}

arena.ScoringPanelRegistry.initialize()

// Load empty match as current.
Expand All @@ -144,13 +145,43 @@ func (arena *Arena) LoadSettings() error {
arena.EventSettings = settings

// Initialize the components that depend on settings.
var accessPoint1WifiStatuses, accessPoint2WifiStatuses [6]*network.TeamWifiStatus
if arena.EventSettings.Ap2TeamChannel == 0 {
accessPoint1WifiStatuses = [6]*network.TeamWifiStatus{
&arena.AllianceStations["R1"].WifiStatus,
&arena.AllianceStations["R2"].WifiStatus,
&arena.AllianceStations["R3"].WifiStatus,
&arena.AllianceStations["B1"].WifiStatus,
&arena.AllianceStations["B2"].WifiStatus,
&arena.AllianceStations["B3"].WifiStatus,
}
} else {
accessPoint1WifiStatuses = [6]*network.TeamWifiStatus{
&arena.AllianceStations["R1"].WifiStatus,
&arena.AllianceStations["R2"].WifiStatus,
&arena.AllianceStations["R3"].WifiStatus,
nil,
nil,
nil,
}
accessPoint2WifiStatuses = [6]*network.TeamWifiStatus{
nil,
nil,
nil,
&arena.AllianceStations["B1"].WifiStatus,
&arena.AllianceStations["B2"].WifiStatus,
&arena.AllianceStations["B3"].WifiStatus,
}
}

arena.accessPoint.SetSettings(
settings.ApType == "vivid",
settings.ApAddress,
settings.ApUsername,
settings.ApPassword,
settings.ApTeamChannel,
settings.NetworkSecurityEnabled,
accessPoint1WifiStatuses,
)
arena.accessPoint2.SetSettings(
settings.ApType == "vivid",
Expand All @@ -159,6 +190,7 @@ func (arena *Arena) LoadSettings() error {
settings.Ap2Password,
settings.Ap2TeamChannel,
settings.NetworkSecurityEnabled,
accessPoint2WifiStatuses,
)
arena.networkSwitch = network.NewSwitch(settings.SwitchAddress, settings.SwitchPassword)
arena.Plc.SetAddress(settings.PlcAddress)
Expand Down Expand Up @@ -370,20 +402,10 @@ func (arena *Arena) StartMatch() error {
}
arena.updateCycleTime(arena.CurrentMatch.StartedAt)

// Convert AP team wifi network status array to a map by station for ease of client use.
teamWifiStatuses := make(map[string]*network.TeamWifiStatus)
for i, station := range []string{"R1", "R2", "R3", "B1", "B2", "B3"} {
if arena.EventSettings.Ap2TeamChannel == 0 || i < 3 {
teamWifiStatuses[station] = &arena.accessPoint.TeamWifiStatuses[i]
} else {
teamWifiStatuses[station] = &arena.accessPoint2.TeamWifiStatuses[i]
}
}

// Save the missed packet count to subtract it from the running count.
for station, allianceStation := range arena.AllianceStations {
for _, allianceStation := range arena.AllianceStations {
if allianceStation.DsConn != nil {
err = allianceStation.DsConn.signalMatchStart(arena.CurrentMatch, teamWifiStatuses[station])
err = allianceStation.DsConn.signalMatchStart(arena.CurrentMatch, &allianceStation.WifiStatus)
if err != nil {
log.Println(err)
}
Expand Down
24 changes: 9 additions & 15 deletions field/arena_notifiers.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ package field
import (
"github.com/Team254/cheesy-arena/game"
"github.com/Team254/cheesy-arena/model"
"github.com/Team254/cheesy-arena/network"
"github.com/Team254/cheesy-arena/playoff"
"github.com/Team254/cheesy-arena/websocket"
"strconv"
Expand Down Expand Up @@ -73,28 +72,23 @@ func (arena *Arena) generateAllianceStationDisplayModeMessage() any {
}

func (arena *Arena) generateArenaStatusMessage() any {
// Convert AP team wifi network status array to a map by station for ease of client use.
teamWifiStatuses := make(map[string]network.TeamWifiStatus)
for i, station := range []string{"R1", "R2", "R3", "B1", "B2", "B3"} {
if arena.EventSettings.Ap2TeamChannel == 0 || i < 3 {
teamWifiStatuses[station] = arena.accessPoint.TeamWifiStatuses[i]
} else {
teamWifiStatuses[station] = arena.accessPoint2.TeamWifiStatuses[i]
}
}

return &struct {
MatchId int
AllianceStations map[string]*AllianceStation
TeamWifiStatuses map[string]network.TeamWifiStatus
MatchState
CanStartMatch bool
PlcIsHealthy bool
FieldEstop bool
PlcArmorBlockStatuses map[string]bool
}{arena.CurrentMatch.Id, arena.AllianceStations, teamWifiStatuses, arena.MatchState,
arena.checkCanStartMatch() == nil, arena.Plc.IsHealthy(), arena.Plc.GetFieldEstop(),
arena.Plc.GetArmorBlockStatuses()}
}{
arena.CurrentMatch.Id,
arena.AllianceStations,
arena.MatchState,
arena.checkCanStartMatch() == nil,
arena.Plc.IsHealthy(),
arena.Plc.GetFieldEstop(),
arena.Plc.GetArmorBlockStatuses(),
}
}

func (arena *Arena) generateAudienceDisplayModeMessage() any {
Expand Down
21 changes: 14 additions & 7 deletions network/access_point.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type AccessPoint struct {
teamChannel int
networkSecurityEnabled bool
configRequestChan chan [6]*model.Team
TeamWifiStatuses [6]TeamWifiStatus
TeamWifiStatuses [6]*TeamWifiStatus
initialStatusesFetched bool
}

Expand All @@ -57,14 +57,19 @@ type sshOutput struct {
}

func (ap *AccessPoint) SetSettings(
isVividType bool, address, username, password string, teamChannel int, networkSecurityEnabled bool,
isVividType bool,
address, username, password string,
teamChannel int,
networkSecurityEnabled bool,
wifiStatuses [6]*TeamWifiStatus,
) {
ap.isVividType = isVividType
ap.address = address
ap.username = username
ap.password = password
ap.teamChannel = teamChannel
ap.networkSecurityEnabled = networkSecurityEnabled
ap.TeamWifiStatuses = wifiStatuses

// Create config channel the first time this method is called.
if ap.configRequestChan == nil {
Expand Down Expand Up @@ -207,7 +212,7 @@ func (ap *AccessPoint) updateTeamWifiStatuses() error {
output, err := ap.runCommand("iwinfo")
if err == nil {
logWifiInfo(output)
err = decodeWifiInfo(output, ap.TeamWifiStatuses[:])
err = ap.decodeWifiInfo(output)
}

if err != nil {
Expand Down Expand Up @@ -303,7 +308,7 @@ func logWifiInfo(wifiInfo string) {
}

// Parses the given output from the "iwinfo" command on the AP and updates the given status structure with the result.
func decodeWifiInfo(wifiInfo string, statuses []TeamWifiStatus) error {
func (ap *AccessPoint) decodeWifiInfo(wifiInfo string) error {
ssidRe := regexp.MustCompile("ESSID: \"([-\\w ]*)\"")
ssids := ssidRe.FindAllStringSubmatch(wifiInfo, -1)

Expand All @@ -312,9 +317,11 @@ func decodeWifiInfo(wifiInfo string, statuses []TeamWifiStatus) error {
return fmt.Errorf("Could not parse wifi info; expected 6 team networks, got %d.", len(ssids))
}

for i := range statuses {
ssid := ssids[i][1]
statuses[i].TeamId, _ = strconv.Atoi(ssid) // Any non-numeric SSIDs will be represented by a zero.
for i, wifiStatus := range ap.TeamWifiStatuses {
if wifiStatus != nil {
ssid := ssids[i][1]
wifiStatus.TeamId, _ = strconv.Atoi(ssid) // Any non-numeric SSIDs will be represented by a zero.
}
}

return nil
Expand Down
32 changes: 20 additions & 12 deletions network/access_point_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,49 +131,57 @@ func TestGenerateTeamAccessPointConfigForVividHosting(t *testing.T) {
}

func TestDecodeWifiInfo(t *testing.T) {
var statuses [6]TeamWifiStatus
statuses := [6]*TeamWifiStatus{
nil,
&TeamWifiStatus{},
&TeamWifiStatus{},
&TeamWifiStatus{},
nil,
&TeamWifiStatus{},
}
ap := AccessPoint{isVividType: true, TeamWifiStatuses: statuses}

// Test with zero team networks configured.
output, err := ioutil.ReadFile("testdata/iwinfo_0_teams.txt")
if assert.Nil(t, err) {
assert.Nil(t, decodeWifiInfo(string(output), statuses[:]))
assert.Equal(t, 0, statuses[0].TeamId)
assert.Nil(t, ap.decodeWifiInfo(string(output)))
assert.Nil(t, statuses[0])
assert.Equal(t, 0, statuses[1].TeamId)
assert.Equal(t, 0, statuses[2].TeamId)
assert.Equal(t, 0, statuses[3].TeamId)
assert.Equal(t, 0, statuses[4].TeamId)
assert.Nil(t, statuses[4])
assert.Equal(t, 0, statuses[5].TeamId)
}

// Test with two team networks configured.
output, err = ioutil.ReadFile("testdata/iwinfo_2_teams.txt")
if assert.Nil(t, err) {
assert.Nil(t, decodeWifiInfo(string(output), statuses[:]))
assert.Equal(t, 0, statuses[0].TeamId)
assert.Nil(t, ap.decodeWifiInfo(string(output)))
assert.Nil(t, statuses[0])
assert.Equal(t, 2471, statuses[1].TeamId)
assert.Equal(t, 0, statuses[2].TeamId)
assert.Equal(t, 254, statuses[3].TeamId)
assert.Equal(t, 0, statuses[4].TeamId)
assert.Nil(t, statuses[4])
assert.Equal(t, 0, statuses[5].TeamId)
}

// Test with six team networks configured.
output, err = ioutil.ReadFile("testdata/iwinfo_6_teams.txt")
if assert.Nil(t, err) {
assert.Nil(t, decodeWifiInfo(string(output), statuses[:]))
assert.Equal(t, 254, statuses[0].TeamId)
assert.Nil(t, ap.decodeWifiInfo(string(output)))
assert.Nil(t, statuses[0])
assert.Equal(t, 1678, statuses[1].TeamId)
assert.Equal(t, 2910, statuses[2].TeamId)
assert.Equal(t, 604, statuses[3].TeamId)
assert.Equal(t, 8, statuses[4].TeamId)
assert.Nil(t, statuses[4])
assert.Equal(t, 2471, statuses[5].TeamId)
}

// Test with invalid input.
assert.NotNil(t, decodeWifiInfo("", statuses[:]))
assert.NotNil(t, ap.decodeWifiInfo(""))
output, err = ioutil.ReadFile("testdata/iwinfo_invalid.txt")
if assert.Nil(t, err) {
assert.NotNil(t, decodeWifiInfo(string(output), statuses[:]))
assert.NotNil(t, ap.decodeWifiInfo(string(output)))
}
}

Expand Down
8 changes: 4 additions & 4 deletions static/js/field_monitor_display.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var handleArenaStatus = function(data) {
} else if (currentMatchId !== data.MatchId) {
location.reload();
}

$.each(data.AllianceStations, function(station, stationStatus) {
// Select the DOM elements corresponding to the team station.
var teamElementPrefix;
Expand Down Expand Up @@ -75,7 +75,7 @@ var handleArenaStatus = function(data) {
teamEthernetElement.text("ETH");
}

var wifiStatus = data.TeamWifiStatuses[station];
const wifiStatus = stationStatus.WifiStatus;
teamRadioTextElement.text(wifiStatus.TeamId);

if (stationStatus.DsConn) {
Expand Down Expand Up @@ -205,7 +205,7 @@ $(function() {
redSide = "left";
blueSide = "right";
}

//Read if display to be used in a Driver Station, ignore FTA flag if so.
var driverStation = urlParams.get("ds");
if (driverStation === "true") {
Expand All @@ -215,7 +215,7 @@ $(function() {
$(".fta-dependent").attr("data-fta", urlParams.get("fta"));
$(".ds-dependent").attr("data-ds", driverStation);
}

$(".reversible-left").attr("data-reversed", reversed);
$(".reversible-right").attr("data-reversed", reversed);

Expand Down
2 changes: 1 addition & 1 deletion static/js/match_play.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ const getTeamNumber = function(station) {
const handleArenaStatus = function(data) {
// Update the team status view.
$.each(data.AllianceStations, function(station, stationStatus) {
const wifiStatus = data.TeamWifiStatuses[station];
const wifiStatus = stationStatus.WifiStatus;
$("#status" + station + " .radio-status").text(wifiStatus.TeamId);

if (stationStatus.DsConn) {
Expand Down

0 comments on commit c177997

Please sign in to comment.