diff --git a/arena.go b/arena.go index 4252461..d2798be 100644 --- a/arena.go +++ b/arena.go @@ -14,7 +14,7 @@ import ( const ( arenaLoopPeriodMs = 10 - dsPacketPeriodMs = 20 + dsPacketPeriodMs = 100 matchEndScoreDwellSec = 3 ) @@ -335,11 +335,11 @@ func (arena *Arena) StartMatch() error { db.SaveMatch(arena.currentMatch) } - // At the beginning of the match, save the missed packet count. + // Save the missed packet count to subtract it from the running count. for _, allianceStation := range arena.AllianceStations { if allianceStation.DsConn != nil { - allianceStation.DsConn.DriverStationStatus.MissedOffset = - allianceStation.DsConn.DriverStationStatus.MissedPacketCount + allianceStation.DsConn.DriverStationStatus.MissedPacketOffset = + allianceStation.DsConn.DriverStationStatus.MissedPacketCount } } diff --git a/displays.go b/displays.go index 5e11b48..5836363 100644 --- a/displays.go +++ b/displays.go @@ -1031,3 +1031,21 @@ func AllianceStationDisplayWebsocketHandler(w http.ResponseWriter, r *http.Reque } } } + +// Renders the FTA diagnostic display. +func FtaDisplayHandler(w http.ResponseWriter, r *http.Request) { + template := template.New("").Funcs(templateHelpers) + _, err := template.ParseFiles("templates/fta_display.html", "templates/base.html") + if err != nil { + handleWebErr(w, err) + return + } + data := struct { + *EventSettings + }{eventSettings} + err = template.ExecuteTemplate(w, "base", data) + if err != nil { + handleWebErr(w, err) + return + } +} diff --git a/driver_station_connection.go b/driver_station_connection.go index afb057a..fc9037a 100644 --- a/driver_station_connection.go +++ b/driver_station_connection.go @@ -20,33 +20,33 @@ const driverStationProtocolVersion = "11191100" const driverStationLinkTimeoutMs = 500 type DriverStationStatus struct { - TeamId int - AllianceStation string - DsLinked bool - RobotLinked bool - Auto bool - Enabled bool - EmergencyStop bool - BatteryVoltage float64 - DsVersion string - PacketCount int - MissedPacketCount int - DsRobotTripTimeMs int - MissedOffset int + TeamId int + AllianceStation string + DsLinked bool + RobotLinked bool + Auto bool + Enabled bool + EmergencyStop bool + BatteryVoltage float64 + DsVersion string + PacketCount int + MissedPacketCount int + MissedPacketOffset int + DsRobotTripTimeMs int } type DriverStationConnection struct { - TeamId int - AllianceStation string - Auto bool - Enabled bool - EmergencyStop bool - DriverStationStatus *DriverStationStatus - LastPacketTime time.Time - LastRobotLinkedTime time.Time - SecondsSinceLastRobotConnection float64 - conn net.Conn - packetCount int + TeamId int + AllianceStation string + Auto bool + Enabled bool + EmergencyStop bool + DriverStationStatus *DriverStationStatus + LastPacketTime time.Time + LastRobotLinkedTime time.Time + SecondsSinceLastRobotLink float64 + conn net.Conn + packetCount int } // Opens a UDP connection for communicating to the driver station. @@ -107,7 +107,7 @@ func ListenForDsPackets(listener *net.UDPConn) { if dsStatus.RobotLinked { dsConn.LastRobotLinkedTime = time.Now() } - dsConn.SecondsSinceLastRobotConnection = time.Since(dsConn.LastRobotLinkedTime).Seconds() + dsConn.SecondsSinceLastRobotLink = time.Since(dsConn.LastRobotLinkedTime).Seconds() } } } diff --git a/match_play.go b/match_play.go index 0aae039..01df344 100644 --- a/match_play.go +++ b/match_play.go @@ -87,58 +87,6 @@ func MatchPlayHandler(w http.ResponseWriter, r *http.Request) { } } - -// Shows the match play control interface. -func MatchFTAHandler(w http.ResponseWriter, r *http.Request) { - practiceMatches, err := buildMatchPlayList("practice") - if err != nil { - handleWebErr(w, err) - return - } - qualificationMatches, err := buildMatchPlayList("qualification") - if err != nil { - handleWebErr(w, err) - return - } - eliminationMatches, err := buildMatchPlayList("elimination") - if err != nil { - handleWebErr(w, err) - return - } - - template := template.New("").Funcs(templateHelpers) - _, err = template.ParseFiles("templates/match_fta.html", "templates/base.html") - if err != nil { - handleWebErr(w, err) - return - } - matchesByType := map[string]MatchPlayList{"practice": practiceMatches, - "qualification": qualificationMatches, "elimination": eliminationMatches} - if currentMatchType == "" { - currentMatchType = "practice" - } - allowSubstitution := mainArena.currentMatch.Type != "qualification" - matchResult, err := db.GetMatchResultForMatch(mainArena.currentMatch.Id) - if err != nil { - handleWebErr(w, err) - return - } - isReplay := matchResult != nil - data := struct { - *EventSettings - MatchesByType map[string]MatchPlayList - CurrentMatchType string - Match *Match - AllowSubstitution bool - IsReplay bool - }{eventSettings, matchesByType, currentMatchType, mainArena.currentMatch, allowSubstitution, isReplay} - err = template.ExecuteTemplate(w, "base", data) - if err != nil { - handleWebErr(w, err) - return - } -} - func MatchPlayLoadHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) matchId, _ := strconv.Atoi(vars["matchId"]) diff --git a/static/css/cheesy-arena.css b/static/css/cheesy-arena.css index 5c54f25..9210c23 100644 --- a/static/css/cheesy-arena.css +++ b/static/css/cheesy-arena.css @@ -41,7 +41,7 @@ .modal-large { width: 60%; } -.ds-status, .robot-status, .battery-status, .bypass-status, .trip-time, .packet-loss { +.ds-status, .robot-status, .battery-status, .bypass-status, .bypass-status-fta, .trip-time, .packet-loss { background-color: #aaa; color: #000; border: 1px solid #999; @@ -54,7 +54,7 @@ margin: 0 auto; } .trip-time, .packet-loss { - width:90px; + width: 90px; } .bypass-status { cursor: pointer; diff --git a/static/js/fta_display.js b/static/js/fta_display.js new file mode 100644 index 0000000..03d39bd --- /dev/null +++ b/static/js/fta_display.js @@ -0,0 +1,62 @@ +// Copyright 2014 Team 254. All Rights Reserved. +// Author: austin.linux@gmail.com (Austin Schuh) +// Author: pat@patfairbank.com (Patrick Fairbank) +// +// Client-side logic for the FTA diagnostic display. + +var websocket; + +var handleStatus = function(data) { + // Update the team status view. + $.each(data.AllianceStations, function(station, stationStatus) { + if (stationStatus.DsConn) { + $("#status" + station + " .team").text(stationStatus.DsConn.TeamId); + var dsStatus = stationStatus.DsConn.DriverStationStatus; + $("#status" + station + " .ds-status").attr("data-status-ok", dsStatus.DsLinked); + $("#status" + station + " .robot-status").attr("data-status-ok", dsStatus.RobotLinked); + if (stationStatus.DsConn.SecondsSinceLastRobotLink > 1 && stationStatus.DsConn.SecondsSinceLastRobotLink < 1000) { + $("#status" + station + " .robot-status").text(stationStatus.DsConn.SecondsSinceLastRobotLink.toFixed()); + } else { + $("#status" + station + " .robot-status").text(""); + } + $("#status" + station + " .battery-status").attr("data-status-ok", + dsStatus.BatteryVoltage > 6 && dsStatus.RobotLinked); + $("#status" + station + " .battery-status").text(dsStatus.BatteryVoltage.toFixed(1) + "V"); + $("#status" + station + " .trip-time").attr("data-status-ok", true); + $("#status" + station + " .trip-time").text(dsStatus.DsRobotTripTimeMs.toFixed(1) + "ms"); + $("#status" + station + " .packet-loss").attr("data-status-ok", true); + $("#status" + station + " .packet-loss").text(dsStatus.MissedPacketCount - dsStatus.MissedPacketOffset); + } else { + $("#status" + station + " .ds-status").attr("data-status-ok", ""); + $("#status" + station + " .robot-status").attr("data-status-ok", ""); + $("#status" + station + " .robot-status").text(""); + $("#status" + station + " .battery-status").attr("data-status-ok", ""); + $("#status" + station + " .battery-status").text(""); + $("#status" + station + " .trip-time").attr("data-status-ok", ""); + $("#status" + station + " .trip-time").text(""); + $("#status" + station + " .packet-loss").attr("data-status-ok", ""); + $("#status" + station + " .packet-loss").text(""); + } + + if (stationStatus.EmergencyStop) { + $("#status" + station + " .bypass-status-fta").attr("data-status-ok", false); + $("#status" + station + " .bypass-status-fta").text("ES"); + } else if (stationStatus.Bypass) { + $("#status" + station + " .bypass-status-fta").attr("data-status-ok", false); + $("#status" + station + " .bypass-status-fta").text("B"); + } else { + $("#status" + station + " .bypass-status-fta").attr("data-status-ok", true); + $("#status" + station + " .bypass-status-fta").text(""); + } + }); +}; + +$(function() { + // Activate tooltips above the status headers. + $("[data-toggle=tooltip]").tooltip({"placement": "top"}); + + // Set up the websocket back to the server. + websocket = new CheesyWebsocket("/match_play/websocket", { + status: function(event) { handleStatus(event.data); } + }); +}); diff --git a/static/js/match_fta.js b/static/js/match_fta.js deleted file mode 100644 index 454acb6..0000000 --- a/static/js/match_fta.js +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2014 Team 254. All Rights Reserved. -// Author: pat@patfairbank.com (Patrick Fairbank) -// -// Client-side logic for the match play page. - -var websocket; -var scoreIsReady; - -var substituteTeam = function(team, position) { - websocket.send("substituteTeam", { team: parseInt(team), position: position }) -}; - -var toggleBypass = function(station) { - websocket.send("toggleBypass", station); -}; - -var startMatch = function() { - websocket.send("startMatch"); -}; - -var abortMatch = function() { - websocket.send("abortMatch"); -}; - -var setAudienceDisplay = function() { - websocket.send("setAudienceDisplay", $("input[name=audienceDisplay]:checked").val()); -}; - -var setAllianceStationDisplay = function() { - websocket.send("setAllianceStationDisplay", $("input[name=allianceStationDisplay]:checked").val()); -}; - -var confirmCommit = function(isReplay) { - if (isReplay || !scoreIsReady) { - // Show the appropriate message(s) in the confirmation dialog. - $("#confirmCommitReplay").css("display", isReplay ? "block" : "none"); - $("#confirmCommitNotReady").css("display", scoreIsReady ? "none" : "block"); - $("#confirmCommitResults").modal("show"); - } else { - commitResults(); - } -}; - -var handleStatus = function(data) { - // Update the team status view. - $.each(data.AllianceStations, function(station, stationStatus) { - if (stationStatus.DsConn) { - var dsStatus = stationStatus.DsConn.DriverStationStatus; - $("#status" + station + " .ds-status").attr("data-status-ok", dsStatus.DsLinked); - $("#status" + station + " .robot-status").attr("data-status-ok", dsStatus.RobotLinked); - if (stationStatus.DsConn.SecondsSinceLastRobotConnection > 1 && stationStatus.DsConn.SecondsSinceLastRobotConnection < 1000) { - $("#status" + station + " .robot-status").text( - stationStatus.DsConn.SecondsSinceLastRobotConnection.toFixed()); - } else { - $("#status" + station + " .robot-status").text(""); - } - $("#status" + station + " .battery-status").attr("data-status-ok", - dsStatus.BatteryVoltage > 6 && dsStatus.RobotLinked); - $("#status" + station + " .battery-status").text(dsStatus.BatteryVoltage.toFixed(1) + "V"); - $("#status" + station + " .trip-time").attr("data-status-ok", true); - $("#status" + station + " .trip-time").text(dsStatus.DsRobotTripTimeMs.toFixed(1) + "ms"); - $("#status" + station + " .packet-loss").attr("data-status-ok", true); - $("#status" + station + " .packet-loss").text((dsStatus.MissedPacketCount - dsStatus.MissedOffset).toFixed() + "p"); - } else { - $("#status" + station + " .ds-status").attr("data-status-ok", ""); - $("#status" + station + " .robot-status").attr("data-status-ok", ""); - $("#status" + station + " .robot-status").text(""); - $("#status" + station + " .battery-status").attr("data-status-ok", ""); - $("#status" + station + " .battery-status").text(""); - $("#status" + station + " .trip-time").attr("data-status-ok", ""); - $("#status" + station + " .trip-time").text(""); - $("#status" + station + " .packet-loss").attr("data-status-ok", ""); - $("#status" + station + " .packet-loss").text(""); - } - - if (stationStatus.EmergencyStop) { - $("#status" + station + " .bypass-status").attr("data-status-ok", false); - $("#status" + station + " .bypass-status").text("ES"); - } else if (stationStatus.Bypass) { - $("#status" + station + " .bypass-status").attr("data-status-ok", false); - $("#status" + station + " .bypass-status").text("B"); - } else { - $("#status" + station + " .bypass-status").attr("data-status-ok", true); - $("#status" + station + " .bypass-status").text(""); - } - }); - - // Enable/disable the buttons based on the current match state. - switch (matchStates[data.MatchState]) { - case "PRE_MATCH": - $("#startMatch").prop("disabled", !data.CanStartMatch); - $("#abortMatch").prop("disabled", true); - $("#commitResults").prop("disabled", true); - $("#discardResults").prop("disabled", true); - break; - case "START_MATCH": - case "AUTO_PERIOD": - case "PAUSE_PERIOD": - case "TELEOP_PERIOD": - case "ENDGAME_PERIOD": - $("#startMatch").prop("disabled", true); - $("#abortMatch").prop("disabled", false); - $("#commitResults").prop("disabled", true); - $("#discardResults").prop("disabled", true); - break; - case "POST_MATCH": - $("#startMatch").prop("disabled", true); - $("#abortMatch").prop("disabled", true); - $("#commitResults").prop("disabled", false); - $("#discardResults").prop("disabled", false); - break; - } -}; - -var handleMatchTime = function(data) { - translateMatchTime(data, function(matchState, matchStateText, countdownSec) { - $("#matchState").text(matchStateText); - $("#matchTime").text(countdownSec); - }); -}; - -var handleSetAudienceDisplay = function(data) { - $("input[name=audienceDisplay]:checked").prop("checked", false); - $("input[name=audienceDisplay][value=" + data + "]").prop("checked", true); -}; - -var handleScoringStatus = function(data) { - scoreIsReady = data.RefereeScoreReady && data.RedScoreReady && data.BlueScoreReady; - $("#refereeScoreStatus").attr("data-ready", data.RefereeScoreReady); - $("#redScoreStatus").attr("data-ready", data.RedScoreReady); - $("#blueScoreStatus").attr("data-ready", data.BlueScoreReady); -}; - -var handleSetAllianceStationDisplay = function(data) { - $("input[name=allianceStationDisplay]:checked").prop("checked", false); - $("input[name=allianceStationDisplay][value=" + data + "]").prop("checked", true); -}; - -$(function() { - // Activate tooltips above the status headers. - $("[data-toggle=tooltip]").tooltip({"placement": "top"}); - - // Set up the websocket back to the server. - websocket = new CheesyWebsocket("/match_play/websocket", { - status: function(event) { handleStatus(event.data); }, - matchTiming: function(event) { handleMatchTiming(event.data); }, - matchTime: function(event) { handleMatchTime(event.data); }, - setAudienceDisplay: function(event) { handleSetAudienceDisplay(event.data); }, - scoringStatus: function(event) { handleScoringStatus(event.data); }, - setAllianceStationDisplay: function(event) { handleSetAllianceStationDisplay(event.data); } - }); -}); diff --git a/templates/base.html b/templates/base.html index 54f84ad..8c4a16a 100644 --- a/templates/base.html +++ b/templates/base.html @@ -32,7 +32,6 @@ Run
@@ -58,13 +57,14 @@