From 348f347563b67e34c3e45796146466beedcbf8e3 Mon Sep 17 00:00:00 2001 From: MrPurpleSocks Date: Thu, 17 Oct 2024 14:32:17 -0700 Subject: [PATCH] Convert to warrior-arena and add smc_ws --- LICENSE | 2 +- README.md | 58 +++++--- field/arena.go | 12 +- field/arena_notifiers.go | 9 +- field/arena_test.go | 15 +- field/display.go | 3 +- field/driver_station_connection.go | 6 +- field/driver_station_connection_test.go | 7 +- field/event_status.go | 3 +- field/event_status_test.go | 7 +- field/fake_plc_test.go | 2 +- field/realtime_score.go | 2 +- field/scoring_panel_registry.go | 3 +- field/scoring_panel_registry_test.go | 5 +- field/team_match_log.go | 4 +- field/team_sign.go | 5 +- field/team_sign_test.go | 7 +- field/test_helpers.go | 7 +- go.mod | 2 +- main.go | 4 +- model/database.go | 5 +- model/event_settings.go | 2 +- model/match.go | 3 +- model/match_result.go | 2 +- model/match_result_test.go | 5 +- model/match_test.go | 5 +- model/ranking.go | 3 +- model/ranking_test.go | 5 +- model/test_helpers.go | 5 +- network/access_point.go | 2 +- network/access_point_test.go | 5 +- network/switch.go | 3 +- network/switch_test.go | 5 +- partner/nexus.go | 3 +- partner/nexus_test.go | 5 +- partner/tba.go | 7 +- partner/tba_test.go | 7 +- playoff/double_elimination.go | 3 +- playoff/double_elimination_test.go | 7 +- playoff/match_group.go | 3 +- playoff/match_group_test.go | 5 +- playoff/matchup.go | 3 +- playoff/matchup_test.go | 5 +- playoff/playoff_match_result.go | 2 +- playoff/playoff_tournament.go | 5 +- playoff/playoff_tournament_test.go | 9 +- playoff/single_elimination.go | 3 +- playoff/single_elimination_test.go | 7 +- playoff/test_helpers.go | 5 +- plc/plc.go | 5 +- plc/plc_test.go | 5 +- smc_ws/smc_ws.go | 162 ++++++++++++++++++++++ templates/base.html | 2 +- tournament/awards.go | 3 +- tournament/awards_test.go | 5 +- tournament/qualification_rankings.go | 5 +- tournament/qualification_rankings_test.go | 7 +- tournament/schedule.go | 3 +- tournament/schedule_test.go | 5 +- tournament/test_helpers.go | 3 +- web/alliance_selection.go | 7 +- web/alliance_selection_test.go | 9 +- web/alliance_station_display.go | 5 +- web/alliance_station_display_test.go | 9 +- web/announcer_display.go | 5 +- web/announcer_display_test.go | 7 +- web/api.go | 11 +- web/api_test.go | 13 +- web/audience_display.go | 7 +- web/audience_display_test.go | 5 +- web/bracket_display.go | 5 +- web/bracket_display_test.go | 5 +- web/display_utils.go | 3 +- web/field_monitor_display.go | 7 +- web/field_monitor_display_test.go | 4 +- web/login.go | 5 +- web/logo_display.go | 5 +- web/logo_display_test.go | 5 +- web/match_logs.go | 4 +- web/match_play.go | 10 +- web/match_play_test.go | 17 +-- web/match_review.go | 5 +- web/match_review_test.go | 9 +- web/placeholder_display.go | 5 +- web/placeholder_display_test.go | 7 +- web/queueing_display.go | 7 +- web/queueing_display_test.go | 5 +- web/rankings_display.go | 5 +- web/rankings_display_test.go | 5 +- web/referee_panel.go | 11 +- web/referee_panel_test.go | 11 +- web/reports.go | 8 +- web/reports_test.go | 9 +- web/scoring_panel.go | 11 +- web/scoring_panel_test.go | 11 +- web/setup_awards.go | 5 +- web/setup_awards_test.go | 5 +- web/setup_breaks.go | 3 +- web/setup_breaks_test.go | 5 +- web/setup_displays.go | 9 +- web/setup_displays_test.go | 7 +- web/setup_field_testing.go | 7 +- web/setup_field_testing_test.go | 7 +- web/setup_lower_thirds.go | 7 +- web/setup_lower_thirds_test.go | 9 +- web/setup_schedule.go | 5 +- web/setup_schedule_test.go | 5 +- web/setup_settings.go | 2 +- web/setup_settings_test.go | 9 +- web/setup_sponsor_slides.go | 3 +- web/setup_sponsor_slides_test.go | 5 +- web/setup_teams.go | 5 +- web/setup_teams_test.go | 5 +- web/twitch_display.go | 5 +- web/twitch_display_test.go | 5 +- web/wall_display.go | 7 +- web/wall_display_test.go | 5 +- web/web.go | 7 +- web/web_test.go | 9 +- web/webpage_display.go | 5 +- web/webpage_display_test.go | 5 +- 121 files changed, 592 insertions(+), 313 deletions(-) create mode 100644 smc_ws/smc_ws.go diff --git a/LICENSE b/LICENSE index 7c779a3a..ec1ae9f0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014, Team 254 +Copyright (c) 2014, Team 254, Team 3256 All rights reserved. This software may be used and redistributed subject to the following conditions: diff --git a/README.md b/README.md index 509d683c..b5b991ec 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,7 @@ -Cheesy Arena [![Build Status](https://github.com/Team254/cheesy-arena/actions/workflows/test.yml/badge.svg)](https://github.com/Team254/cheesy-arena/actions) +Warrior Arena [![Build/Test](https://github.com/Team3256/warrior-arena/actions/workflows/test.yml/badge.svg)](https://github.com/Team3256/warrior-arena/actions/workflows/test.yml) ============ A field management system that just works. -For the game-agnostic version, see [Cheesy Arena Lite](https://github.com/Team254/cheesy-arena-lite). - ## Key features **For participants and spectators** @@ -23,14 +21,22 @@ For the game-agnostic version, see [Cheesy Arena Lite](https://github.com/Team25 * Reports, results, and logs can be viewed from any computer * An arbitrary number of auxiliary displays can be set up using any computer with just a web browser, to show rankings, queueing, field status, etc. +**For teams** +* Uses cheaper hardware (no modbus!) +* Allows for less wiring (just additional ethernet cable to alliance stations + one for amps) +* You don't have to program a PLC + +## We didn't make most of this +This was made almost in whole by FRC Team 254. Team 3256 has just modified it to work better for our resources and budgets. + ## License -Teams may use Cheesy Arena freely for practice, scrimmages, and off-season events. See [LICENSE](LICENSE) for more details. +Teams may use Warrior Arena freely for practice, scrimmages, and off-season events. See [LICENSE](LICENSE) for more details. ## Installing **From a pre-built release** -Download the [latest release](https://github.com/Team254/cheesy-arena/releases). Pre-built packages are available for Linux, macOS (x64 and M1), and Windows. +Download the [latest release](https://github.com/Team3256/warrior-arena/releases). Pre-built packages are available for Linux, macOS (x64 and M1), and Windows. On recent versions of macOS, you may be prevented from running an app from an unidentified developer; see [these instructions](https://support.apple.com/guide/mac-help/open-a-mac-app-from-an-unidentified-developer-mh40616/mac) on how to bypass the warning. @@ -40,49 +46,59 @@ On recent versions of macOS, you may be prevented from running an app from an un 1. Clone this GitHub repository to a location of your choice 1. Navigate to the repository's directory in the terminal 1. Compile the code with `go build` -1. Run the `cheesy-arena` or `cheesy-arena.exe` binary +1. Run the `Warrior-arena` or `Warrior-arena.exe` binary 1. Navigate to http://localhost:8080 in your browser (Google Chrome recommended) **IP address configuration** -When running Cheesy Arena on a playing field with robots, set the IP address of the computer running Cheesy Arena to 10.0.100.5. By a convention baked into the FRC Driver Station software, driver stations will broadcast their presence on the network to this hardcoded address so that the FMS does not need to discover them by some other method. +When running Warrior Arena on a playing field with robots, set the IP address of the computer running Warrior Arena to 10.0.100.5. By a convention baked into the FRC Driver Station software, driver stations will broadcast their presence on the network to this hardcoded address so that the FMS does not need to discover them by some other method. + +When running Warrior Arena without robots for testing or development, any IP address can be used. -When running Cheesy Arena without robots for testing or development, any IP address can be used. +When using raspberry pis for alliance station buttons and scoring, the following IPs should be used +| Raspberry Pi Location | IP Address | +|-----------------------------------|------------| +| Red Alliance Driver Station | 10.0.101.0 | +| Blue Alliance Driver Station | 10.0.101.1 | +| Reserved For Auto Scoring | 10.0.101.2 | +| Reserved For Auto Scoring | 10.0.101.3 | +| Reserved For Auto Scoring | 10.0.101.4 | +| Reserved For Auto Scoring | 10.0.101.5 | ## Under the hood -Cheesy Arena is written using [Go](https://golang.org), a language developed by Google and first released in 2009. Go excels in the areas of concurrency, networking, performance, and portability, which makes it ideal for a field management system. +Warrior Arena is written using [Go](https://golang.org), a language developed by Google and first released in 2009. Go excels in the areas of concurrency, networking, performance, and portability, which makes it ideal for a field management system. -Cheesy Arena is implemented as a web server, with all human interaction done via browser. The graphical interfaces are implemented in HTML, JavaScript, and CSS. There are many advantages to this approach – development of new graphical elements is rapid, and no software needs to be installed other than on the server. Client web pages send commands and receive updates using WebSockets. +Warrior Arena is implemented as a web server, with all human interaction done via browser. The graphical interfaces are implemented in HTML, JavaScript, and CSS. There are many advantages to this approach – development of new graphical elements is rapid, and no software needs to be installed other than on the server. Client web pages send commands and receive updates using WebSockets. [Bolt](https://github.com/etcd-io/bbolt) is used as the datastore, and making backups or transferring data from one installation to another is as simple as copying the database file. Schedule generation is fast because pre-generated schedules are included with the code. Each schedule contains a certain number of matches per team for placeholder teams 1 through N, so generating the actual match schedule becomes a simple exercise in permuting the mapping of real teams to placeholder teams. The pre-generated schedules are checked into this repository and can be vetted in advance of any events for deviations from the randomness (and other) requirements. -Cheesy Arena includes support for, but doesn't require, networking hardware similar to that used in official FRC events. Teams are issued their own SSIDs and WPA keys, and when connected to Cheesy Arena are isolated to a VLAN which prevents any communication other than between the driver station, robot, and event server. The network hardware is reconfigured via SSH and Telnet commands for the new set of teams when each mach is loaded. +Warrior Arena includes support for, but doesn't require, networking hardware similar to that used in official FRC events. Teams are issued their own SSIDs and WPA keys, and when connected to Warrior Arena are isolated to a VLAN which prevents any communication other than between the driver station, robot, and event server. The network hardware is reconfigured via SSH and Telnet commands for the new set of teams when each mach is loaded. -## PLC integration -Cheesy Arena has the ability to integrate with an Allen-Bradley PLC setup similar to the one that FIRST uses, to read field sensors and control lights and motors. The PLC hardware travels with the FIRST California fields; contact your FTA for more information. +## PLC substitution +Warrior Arena has the ability to connect to Raspberry Pis (or similar SBCs) instead of using a PLC. Both all driver stations have an E-Stop and an A-Stop, with one RPi per alliance. Additionally, one RPi per major section of the game, that isn't connected to the driver stations (note: certain years, 2025 for example, don't have auto scoring, thus only use the two driver station RPis) -The PLC code can be found [here](https://github.com/ejordan376/Cheesy-PLC). +The RPi code can be found [here](https://github.com/Team3526/warrior-arena/RPi). ## LED hardware -Due to the prohibitive cost of the LEDs and LED controllers used on official fields, for years in which LEDs are mandatory for a proper game experience (such as 2018), Cheesy Arena integrates with [Advatek](https://www.advateklights.com) controllers and LEDs. +Due to the prohibitive cost of the LEDs and LED controllers used on official fields, for years in which LEDs are mandatory for a proper game experience (such as 2018), Warrior Arena integrates with [Advatek](https://www.advateklights.com) controllers and LEDs. ## Advanced networking -See the [Advanced Networking wiki page](https://github.com/Team254/cheesy-arena/wiki/Advanced-Networking-Concepts) for instructions on what equipment to obtain and how to configure it in order to support advanced network security. +See the [Advanced Networking wiki page](https://github.com/Team3256/warrior-arena/wiki/Advanced-Networking-Concepts) for instructions on what equipment to obtain and how to configure it in order to support advanced network security. ## Contributing -Cheesy Arena is far from finished! You can help by: +Warrior Arena is far from finished! You can help by: * Checking out the [TODO list](TODO.md), writing a missing feature, and sending a pull request -* Filing any bugs or feature requests using the [issue tracker](https://github.com/Team254/cheesy-arena/issues) -* Contributing documentation to the [wiki](https://github.com/Team254/cheesy-arena/wiki) +* Filing any bugs or feature requests using the [issue tracker](https://github.com/Team3256/warrior-arena/issues) +* Contributing documentation to the [wiki](https://github.com/Team3256/warrior-arena/wiki) * Sending baked goods to [Pat](https://github.com/patfair) ## Acknowledgements -[Several folks](https://github.com/Team254/cheesy-arena/graphs/contributors) have contributed pull requests. Thanks! +[Several folks](https://github.com/Team3256/warrior-arena/graphs/contributors) have contributed pull requests. Thanks! -In addition, the following individuals have contributed to make Cheesy Arena a reality: +In addition, the following individuals have contributed to make Warrior Arena a reality: * Tom Bottiglieri * James Cerar diff --git a/field/arena.go b/field/arena.go index 10bacea5..6f7678a9 100644 --- a/field/arena.go +++ b/field/arena.go @@ -12,12 +12,12 @@ import ( "reflect" "time" - "github.com/Team254/cheesy-arena/game" - "github.com/Team254/cheesy-arena/model" - "github.com/Team254/cheesy-arena/network" - "github.com/Team254/cheesy-arena/partner" - "github.com/Team254/cheesy-arena/playoff" - "github.com/Team254/cheesy-arena/plc" + "github.com/Team3256/warrior-arena/game" + "github.com/Team3256/warrior-arena/model" + "github.com/Team3256/warrior-arena/network" + "github.com/Team3256/warrior-arena/partner" + "github.com/Team3256/warrior-arena/playoff" + "github.com/Team3256/warrior-arena/plc" ) const ( diff --git a/field/arena_notifiers.go b/field/arena_notifiers.go index 8b4fc739..06c40c8d 100644 --- a/field/arena_notifiers.go +++ b/field/arena_notifiers.go @@ -6,11 +6,12 @@ package field import ( - "github.com/Team254/cheesy-arena/game" - "github.com/Team254/cheesy-arena/model" - "github.com/Team254/cheesy-arena/playoff" - "github.com/Team254/cheesy-arena/websocket" "strconv" + + "github.com/Team3256/warrior-arena/game" + "github.com/Team3256/warrior-arena/model" + "github.com/Team3256/warrior-arena/playoff" + "github.com/Team3256/warrior-arena/websocket" ) type ArenaNotifiers struct { diff --git a/field/arena_test.go b/field/arena_test.go index 964fecec..34951eb1 100644 --- a/field/arena_test.go +++ b/field/arena_test.go @@ -4,18 +4,19 @@ package field import ( - "github.com/Team254/cheesy-arena/game" - "github.com/Team254/cheesy-arena/model" - "github.com/Team254/cheesy-arena/partner" - "github.com/Team254/cheesy-arena/playoff" - "github.com/Team254/cheesy-arena/tournament" - "github.com/Team254/cheesy-arena/websocket" - "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" "strings" "testing" "time" + + "github.com/Team3256/warrior-arena/game" + "github.com/Team3256/warrior-arena/model" + "github.com/Team3256/warrior-arena/partner" + "github.com/Team3256/warrior-arena/playoff" + "github.com/Team3256/warrior-arena/tournament" + "github.com/Team3256/warrior-arena/websocket" + "github.com/stretchr/testify/assert" ) func TestAssignTeam(t *testing.T) { diff --git a/field/display.go b/field/display.go index 909a07cd..acb9ed24 100644 --- a/field/display.go +++ b/field/display.go @@ -7,7 +7,6 @@ package field import ( "fmt" - "github.com/Team254/cheesy-arena/websocket" "net/url" "reflect" "sort" @@ -15,6 +14,8 @@ import ( "strings" "sync" "time" + + "github.com/Team3256/warrior-arena/websocket" ) const ( diff --git a/field/driver_station_connection.go b/field/driver_station_connection.go index 1e57594b..8086695a 100644 --- a/field/driver_station_connection.go +++ b/field/driver_station_connection.go @@ -13,9 +13,9 @@ import ( "strconv" "time" - "github.com/Team254/cheesy-arena/game" - "github.com/Team254/cheesy-arena/model" - "github.com/Team254/cheesy-arena/network" + "github.com/Team3256/warrior-arena/game" + "github.com/Team3256/warrior-arena/model" + "github.com/Team3256/warrior-arena/network" ) // FMS uses 1121 for sending UDP packets, and FMS Lite uses 1120. Using 1121 diff --git a/field/driver_station_connection_test.go b/field/driver_station_connection_test.go index 6a961f4d..04cd940b 100644 --- a/field/driver_station_connection_test.go +++ b/field/driver_station_connection_test.go @@ -4,12 +4,13 @@ package field import ( - "github.com/Team254/cheesy-arena/model" - "github.com/Team254/cheesy-arena/network" - "github.com/stretchr/testify/assert" "net" "testing" "time" + + "github.com/Team3256/warrior-arena/model" + "github.com/Team3256/warrior-arena/network" + "github.com/stretchr/testify/assert" ) func TestEncodeControlPacket(t *testing.T) { diff --git a/field/event_status.go b/field/event_status.go index 4799b0ea..3fa63a1d 100644 --- a/field/event_status.go +++ b/field/event_status.go @@ -7,9 +7,10 @@ package field import ( "fmt" - "github.com/Team254/cheesy-arena/model" "math" "time" + + "github.com/Team3256/warrior-arena/model" ) const maxExpectedCycleTimeSec = 900 diff --git a/field/event_status_test.go b/field/event_status_test.go index 5f7c323e..eacdab28 100644 --- a/field/event_status_test.go +++ b/field/event_status_test.go @@ -4,11 +4,12 @@ package field import ( - "github.com/Team254/cheesy-arena/game" - "github.com/Team254/cheesy-arena/model" - "github.com/stretchr/testify/assert" "testing" "time" + + "github.com/Team3256/warrior-arena/game" + "github.com/Team3256/warrior-arena/model" + "github.com/stretchr/testify/assert" ) func TestCycleTime(t *testing.T) { diff --git a/field/fake_plc_test.go b/field/fake_plc_test.go index 925f5def..e1b24c58 100644 --- a/field/fake_plc_test.go +++ b/field/fake_plc_test.go @@ -6,7 +6,7 @@ package field import ( - "github.com/Team254/cheesy-arena/websocket" + "github.com/Team3256/warrior-arena/websocket" ) type FakePlc struct { diff --git a/field/realtime_score.go b/field/realtime_score.go index b1043c7f..096e3c21 100644 --- a/field/realtime_score.go +++ b/field/realtime_score.go @@ -5,7 +5,7 @@ package field -import "github.com/Team254/cheesy-arena/game" +import "github.com/Team3256/warrior-arena/game" type RealtimeScore struct { CurrentScore game.Score diff --git a/field/scoring_panel_registry.go b/field/scoring_panel_registry.go index 7ae563e7..6bdc25fc 100644 --- a/field/scoring_panel_registry.go +++ b/field/scoring_panel_registry.go @@ -6,8 +6,9 @@ package field import ( - "github.com/Team254/cheesy-arena/websocket" "sync" + + "github.com/Team3256/warrior-arena/websocket" ) type ScoringPanelRegistry struct { diff --git a/field/scoring_panel_registry_test.go b/field/scoring_panel_registry_test.go index bbc37cbc..5ddc11ad 100644 --- a/field/scoring_panel_registry_test.go +++ b/field/scoring_panel_registry_test.go @@ -4,9 +4,10 @@ package field import ( - "github.com/Team254/cheesy-arena/websocket" - "github.com/stretchr/testify/assert" "testing" + + "github.com/Team3256/warrior-arena/websocket" + "github.com/stretchr/testify/assert" ) func TestScoringPanelRegistry(t *testing.T) { diff --git a/field/team_match_log.go b/field/team_match_log.go index c6a8885d..7f7b295f 100644 --- a/field/team_match_log.go +++ b/field/team_match_log.go @@ -12,8 +12,8 @@ import ( "path/filepath" "time" - "github.com/Team254/cheesy-arena/model" - "github.com/Team254/cheesy-arena/network" + "github.com/Team3256/warrior-arena/model" + "github.com/Team3256/warrior-arena/network" ) const logsDir = "static/logs" diff --git a/field/team_sign.go b/field/team_sign.go index 147d8ac1..9a197482 100644 --- a/field/team_sign.go +++ b/field/team_sign.go @@ -7,14 +7,15 @@ package field import ( "fmt" - "github.com/Team254/cheesy-arena/game" - "github.com/Team254/cheesy-arena/model" "image/color" "log" "net" "strconv" "strings" "time" + + "github.com/Team3256/warrior-arena/game" + "github.com/Team3256/warrior-arena/model" ) // Represents a collection of team number and timer signs. diff --git a/field/team_sign_test.go b/field/team_sign_test.go index 68624c1d..a4eb261e 100644 --- a/field/team_sign_test.go +++ b/field/team_sign_test.go @@ -4,11 +4,12 @@ package field import ( - "github.com/Team254/cheesy-arena/game" - "github.com/Team254/cheesy-arena/model" - "github.com/stretchr/testify/assert" "image/color" "testing" + + "github.com/Team3256/warrior-arena/game" + "github.com/Team3256/warrior-arena/model" + "github.com/stretchr/testify/assert" ) func TestTeamSign_GenerateInMatchRearText(t *testing.T) { diff --git a/field/test_helpers.go b/field/test_helpers.go index d26b7f03..e8dd5f83 100644 --- a/field/test_helpers.go +++ b/field/test_helpers.go @@ -7,13 +7,14 @@ package field import ( "fmt" - "github.com/Team254/cheesy-arena/game" - "github.com/Team254/cheesy-arena/model" - "github.com/stretchr/testify/assert" "math/rand" "os" "path/filepath" "testing" + + "github.com/Team3256/warrior-arena/game" + "github.com/Team3256/warrior-arena/model" + "github.com/stretchr/testify/assert" ) func SetupTestArena(t *testing.T, uniqueName string) *Arena { diff --git a/go.mod b/go.mod index 72c27084..d281b96c 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/Team254/cheesy-arena +module github.com/Team3256/warrior-arena go 1.22 diff --git a/main.go b/main.go index 6b422592..bf455801 100644 --- a/main.go +++ b/main.go @@ -7,8 +7,8 @@ package main import ( - "github.com/Team254/cheesy-arena/field" - "github.com/Team254/cheesy-arena/web" + "github.com/Team3256/warrior-arena/field" + "github.com/Team3256/warrior-arena/web" "log" ) diff --git a/model/database.go b/model/database.go index cdb7bb87..b11ea4e9 100644 --- a/model/database.go +++ b/model/database.go @@ -7,13 +7,14 @@ package model import ( "fmt" - "github.com/Team254/cheesy-arena/game" - "go.etcd.io/bbolt" "io" "os" "path/filepath" "strings" "time" + + "github.com/Team3256/warrior-arena/game" + "go.etcd.io/bbolt" ) const backupsDir = "db/backups" diff --git a/model/event_settings.go b/model/event_settings.go index 5e53459a..8e28eabd 100644 --- a/model/event_settings.go +++ b/model/event_settings.go @@ -5,7 +5,7 @@ package model -import "github.com/Team254/cheesy-arena/game" +import "github.com/Team3256/warrior-arena/game" type PlayoffType int diff --git a/model/match.go b/model/match.go index fcb5d075..36cb300a 100644 --- a/model/match.go +++ b/model/match.go @@ -7,10 +7,11 @@ package model import ( "fmt" - "github.com/Team254/cheesy-arena/game" "sort" "strings" "time" + + "github.com/Team3256/warrior-arena/game" ) //go:generate stringer -type=MatchType diff --git a/model/match_result.go b/model/match_result.go index a4efb45d..fb639d91 100644 --- a/model/match_result.go +++ b/model/match_result.go @@ -6,7 +6,7 @@ package model import ( - "github.com/Team254/cheesy-arena/game" + "github.com/Team3256/warrior-arena/game" ) type MatchResult struct { diff --git a/model/match_result_test.go b/model/match_result_test.go index 8fcc6d5f..29a223af 100644 --- a/model/match_result_test.go +++ b/model/match_result_test.go @@ -4,9 +4,10 @@ package model import ( - "github.com/Team254/cheesy-arena/game" - "github.com/stretchr/testify/assert" "testing" + + "github.com/Team3256/warrior-arena/game" + "github.com/stretchr/testify/assert" ) func TestGetNonexistentMatchResult(t *testing.T) { diff --git a/model/match_test.go b/model/match_test.go index 0efb243e..ce952c23 100644 --- a/model/match_test.go +++ b/model/match_test.go @@ -4,10 +4,11 @@ package model import ( - "github.com/Team254/cheesy-arena/game" - "github.com/stretchr/testify/assert" "testing" "time" + + "github.com/Team3256/warrior-arena/game" + "github.com/stretchr/testify/assert" ) func TestGetNonexistentMatch(t *testing.T) { diff --git a/model/ranking.go b/model/ranking.go index 96b9ae8c..147e50e5 100644 --- a/model/ranking.go +++ b/model/ranking.go @@ -6,8 +6,9 @@ package model import ( - "github.com/Team254/cheesy-arena/game" "sort" + + "github.com/Team3256/warrior-arena/game" ) func (database *Database) CreateRanking(ranking *game.Ranking) error { diff --git a/model/ranking_test.go b/model/ranking_test.go index 7a022e8c..47d8cb5b 100644 --- a/model/ranking_test.go +++ b/model/ranking_test.go @@ -4,9 +4,10 @@ package model import ( - "github.com/Team254/cheesy-arena/game" - "github.com/stretchr/testify/assert" "testing" + + "github.com/Team3256/warrior-arena/game" + "github.com/stretchr/testify/assert" ) func TestGetNonexistentRanking(t *testing.T) { diff --git a/model/test_helpers.go b/model/test_helpers.go index 36a8c0d2..3282cbd0 100644 --- a/model/test_helpers.go +++ b/model/test_helpers.go @@ -7,11 +7,12 @@ package model import ( "fmt" - "github.com/Team254/cheesy-arena/game" - "github.com/stretchr/testify/assert" "os" "path/filepath" "testing" + + "github.com/Team3256/warrior-arena/game" + "github.com/stretchr/testify/assert" ) func SetupTestDb(t *testing.T, uniqueName string) *Database { diff --git a/network/access_point.go b/network/access_point.go index 58d2416e..4ede2e65 100644 --- a/network/access_point.go +++ b/network/access_point.go @@ -18,7 +18,7 @@ import ( "syscall" "time" - "github.com/Team254/cheesy-arena/model" + "github.com/Team3256/warrior-arena/model" ) const ( diff --git a/network/access_point_test.go b/network/access_point_test.go index e7f358ef..f5fa79fd 100644 --- a/network/access_point_test.go +++ b/network/access_point_test.go @@ -5,11 +5,12 @@ package network import ( "encoding/json" - "github.com/Team254/cheesy-arena/model" - "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" "testing" + + "github.com/Team3256/warrior-arena/model" + "github.com/stretchr/testify/assert" ) func TestAccessPoint_ConfigureTeamWifi(t *testing.T) { diff --git a/network/switch.go b/network/switch.go index 4f6dc4a5..2757316d 100644 --- a/network/switch.go +++ b/network/switch.go @@ -9,10 +9,11 @@ import ( "bufio" "bytes" "fmt" - "github.com/Team254/cheesy-arena/model" "net" "sync" "time" + + "github.com/Team3256/warrior-arena/model" ) const ( diff --git a/network/switch_test.go b/network/switch_test.go index a6527a34..ce011e39 100644 --- a/network/switch_test.go +++ b/network/switch_test.go @@ -6,11 +6,12 @@ package network import ( "bytes" "fmt" - "github.com/Team254/cheesy-arena/model" - "github.com/stretchr/testify/assert" "net" "testing" "time" + + "github.com/Team3256/warrior-arena/model" + "github.com/stretchr/testify/assert" ) func TestConfigureSwitch(t *testing.T) { diff --git a/partner/nexus.go b/partner/nexus.go index d5202658..9045ea5e 100644 --- a/partner/nexus.go +++ b/partner/nexus.go @@ -8,10 +8,11 @@ package partner import ( "encoding/json" "fmt" - "github.com/Team254/cheesy-arena/model" "io" "net/http" "strconv" + + "github.com/Team3256/warrior-arena/model" ) const nexusBaseUrl = "https://frc.nexus" diff --git a/partner/nexus_test.go b/partner/nexus_test.go index ef6cda74..c5797b79 100644 --- a/partner/nexus_test.go +++ b/partner/nexus_test.go @@ -4,12 +4,13 @@ package partner import ( - "github.com/Team254/cheesy-arena/model" - "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" "strings" "testing" + + "github.com/Team3256/warrior-arena/model" + "github.com/stretchr/testify/assert" ) func TestGetLineup(t *testing.T) { diff --git a/partner/tba.go b/partner/tba.go index be0da145..034d3e84 100644 --- a/partner/tba.go +++ b/partner/tba.go @@ -11,13 +11,14 @@ import ( "encoding/base64" "encoding/json" "fmt" - "github.com/Team254/cheesy-arena/game" - "github.com/Team254/cheesy-arena/model" - "github.com/mitchellh/mapstructure" "io" "io/ioutil" "net/http" "strconv" + + "github.com/Team3256/warrior-arena/game" + "github.com/Team3256/warrior-arena/model" + "github.com/mitchellh/mapstructure" ) const ( diff --git a/partner/tba_test.go b/partner/tba_test.go index 407b2537..8d0b530a 100644 --- a/partner/tba_test.go +++ b/partner/tba_test.go @@ -6,15 +6,16 @@ package partner import ( "bytes" "encoding/json" - "github.com/Team254/cheesy-arena/game" - "github.com/Team254/cheesy-arena/model" - "github.com/stretchr/testify/assert" "io" "net/http" "net/http/httptest" "strings" "testing" "time" + + "github.com/Team3256/warrior-arena/game" + "github.com/Team3256/warrior-arena/model" + "github.com/stretchr/testify/assert" ) func TestPublishTeams(t *testing.T) { diff --git a/playoff/double_elimination.go b/playoff/double_elimination.go index 344cebf0..50c8b703 100644 --- a/playoff/double_elimination.go +++ b/playoff/double_elimination.go @@ -7,7 +7,8 @@ package playoff import ( "fmt" - "github.com/Team254/cheesy-arena/model" + + "github.com/Team3256/warrior-arena/model" ) // Creates a double-elimination bracket and returns the root matchup comprising the tournament finals along with diff --git a/playoff/double_elimination_test.go b/playoff/double_elimination_test.go index 82e3f05b..e0f1d0c2 100644 --- a/playoff/double_elimination_test.go +++ b/playoff/double_elimination_test.go @@ -4,10 +4,11 @@ package playoff import ( - "github.com/Team254/cheesy-arena/game" - "github.com/Team254/cheesy-arena/model" - "github.com/stretchr/testify/assert" "testing" + + "github.com/Team3256/warrior-arena/game" + "github.com/Team3256/warrior-arena/model" + "github.com/stretchr/testify/assert" ) func TestDoubleEliminationInitial(t *testing.T) { diff --git a/playoff/match_group.go b/playoff/match_group.go index a27b2115..bc621b74 100644 --- a/playoff/match_group.go +++ b/playoff/match_group.go @@ -7,8 +7,9 @@ package playoff import ( "fmt" - "github.com/Team254/cheesy-arena/model" "sort" + + "github.com/Team3256/warrior-arena/model" ) type MatchGroup interface { diff --git a/playoff/match_group_test.go b/playoff/match_group_test.go index f122ff75..055aaaea 100644 --- a/playoff/match_group_test.go +++ b/playoff/match_group_test.go @@ -4,9 +4,10 @@ package playoff import ( - "github.com/Team254/cheesy-arena/model" - "github.com/stretchr/testify/assert" "testing" + + "github.com/Team3256/warrior-arena/model" + "github.com/stretchr/testify/assert" ) func TestCollectMatchGroupsErrors(t *testing.T) { diff --git a/playoff/matchup.go b/playoff/matchup.go index 989e5027..865376b1 100644 --- a/playoff/matchup.go +++ b/playoff/matchup.go @@ -8,8 +8,9 @@ package playoff import ( "fmt" - "github.com/Team254/cheesy-arena/game" "math" + + "github.com/Team3256/warrior-arena/game" ) type Matchup struct { diff --git a/playoff/matchup_test.go b/playoff/matchup_test.go index 8c3252d8..3ce172e7 100644 --- a/playoff/matchup_test.go +++ b/playoff/matchup_test.go @@ -4,9 +4,10 @@ package playoff import ( - "github.com/Team254/cheesy-arena/game" - "github.com/stretchr/testify/assert" "testing" + + "github.com/Team3256/warrior-arena/game" + "github.com/stretchr/testify/assert" ) func TestMatchupAllianceSourceDisplayNames(t *testing.T) { diff --git a/playoff/playoff_match_result.go b/playoff/playoff_match_result.go index f3dd79f7..955c0cc9 100644 --- a/playoff/playoff_match_result.go +++ b/playoff/playoff_match_result.go @@ -5,7 +5,7 @@ package playoff -import "github.com/Team254/cheesy-arena/game" +import "github.com/Team3256/warrior-arena/game" type playoffMatchResult struct { status game.MatchStatus diff --git a/playoff/playoff_tournament.go b/playoff/playoff_tournament.go index 62215434..8444a469 100644 --- a/playoff/playoff_tournament.go +++ b/playoff/playoff_tournament.go @@ -7,9 +7,10 @@ package playoff import ( "fmt" - "github.com/Team254/cheesy-arena/game" - "github.com/Team254/cheesy-arena/model" "time" + + "github.com/Team3256/warrior-arena/game" + "github.com/Team3256/warrior-arena/model" ) type PlayoffTournament struct { diff --git a/playoff/playoff_tournament_test.go b/playoff/playoff_tournament_test.go index 7623a9ff..2150acd1 100644 --- a/playoff/playoff_tournament_test.go +++ b/playoff/playoff_tournament_test.go @@ -4,12 +4,13 @@ package playoff import ( - "github.com/Team254/cheesy-arena/game" - "github.com/Team254/cheesy-arena/model" - "github.com/Team254/cheesy-arena/tournament" - "github.com/stretchr/testify/assert" "testing" "time" + + "github.com/Team3256/warrior-arena/game" + "github.com/Team3256/warrior-arena/model" + "github.com/Team3256/warrior-arena/tournament" + "github.com/stretchr/testify/assert" ) func TestNewPlayoffTournamentErrors(t *testing.T) { diff --git a/playoff/single_elimination.go b/playoff/single_elimination.go index f5057767..ee14c49d 100644 --- a/playoff/single_elimination.go +++ b/playoff/single_elimination.go @@ -7,8 +7,9 @@ package playoff import ( "fmt" - "github.com/Team254/cheesy-arena/model" "strings" + + "github.com/Team3256/warrior-arena/model" ) // Creates a single-elimination bracket containing only the required matchups for the given number of alliances, and diff --git a/playoff/single_elimination_test.go b/playoff/single_elimination_test.go index 209608ce..b6e64404 100644 --- a/playoff/single_elimination_test.go +++ b/playoff/single_elimination_test.go @@ -4,10 +4,11 @@ package playoff import ( - "github.com/Team254/cheesy-arena/game" - "github.com/Team254/cheesy-arena/model" - "github.com/stretchr/testify/assert" "testing" + + "github.com/Team3256/warrior-arena/game" + "github.com/Team3256/warrior-arena/model" + "github.com/stretchr/testify/assert" ) func TestSingleEliminationInitialWith2Alliances(t *testing.T) { diff --git a/playoff/test_helpers.go b/playoff/test_helpers.go index 8bad1634..d407c335 100644 --- a/playoff/test_helpers.go +++ b/playoff/test_helpers.go @@ -6,9 +6,10 @@ package playoff import ( - "github.com/Team254/cheesy-arena/model" - "github.com/stretchr/testify/assert" "testing" + + "github.com/Team3256/warrior-arena/model" + "github.com/stretchr/testify/assert" ) func setupTestDb(t *testing.T) *model.Database { diff --git a/plc/plc.go b/plc/plc.go index 30aaf80b..18615f6e 100644 --- a/plc/plc.go +++ b/plc/plc.go @@ -7,11 +7,12 @@ package plc import ( "fmt" - "github.com/Team254/cheesy-arena/websocket" - "github.com/goburrow/modbus" "log" "strings" "time" + + "github.com/Team3256/warrior-arena/websocket" + "github.com/goburrow/modbus" ) type Plc interface { diff --git a/plc/plc_test.go b/plc/plc_test.go index 914be180..7323f6d3 100644 --- a/plc/plc_test.go +++ b/plc/plc_test.go @@ -4,10 +4,11 @@ package plc import ( - "github.com/Team254/cheesy-arena/websocket" + "testing" + + "github.com/Team3256/warrior-arena/websocket" "github.com/goburrow/modbus" "github.com/stretchr/testify/assert" - "testing" ) func TestPlcInitialization(t *testing.T) { diff --git a/smc_ws/smc_ws.go b/smc_ws/smc_ws.go new file mode 100644 index 00000000..e33e6ec4 --- /dev/null +++ b/smc_ws/smc_ws.go @@ -0,0 +1,162 @@ +// Copyright 2024 Team 3256. All Rights Reserved. +// Author: patrick@warriorb.org (Patrick Woollvin) +// +// Methods for interfacing with the field SMCs (Scoring and Management Computers) over websocket. +// +// Heavy "inspiration" from the cheesy-arena plc package + +package smc_ws + +import ( + "github.com/Team3256/warrior-arena/websocket" + "time" +) + +type Smc interface { + SetAddress(address string) + Connect() + GetConnectionStatus() bool + GetIsEnabled() bool + IsHealthy() bool + lastHeartbeat() time.Time + Run() + GetFieldEStop() bool + GetTeamEStops() [3]bool + GetTeamAStops() [3]bool + GetButtonsConnected() [3]bool + ResetMatch() + SetStackLights(red, blue, orange, green bool) + SetStackBuzzer(state bool) + SetFieldResetLight(state bool) + GetCycleState(max, index, duration int) bool + GetInputNames() []string + GetInputIds() []string + GetAmpButtons() (bool, bool) + GetAmpNoteCounts() int + GetSpeakerNoteCounts() int + SetSpeakerMotors(state bool) + SetSpeakerLights(redState, blueState bool) + SetSubwooferCountdown(redState, blueState bool) + SetAmpLights(low, high, coop bool) + SetPostMatchSubwooferLights(state bool) +} + +type SmcWS struct { + address string + RedDSWebsocket websocket.Websocket + BlueDSWebsocket websocket.Websocket + Aux1Websocket websocket.Websocket // For 2024: Aux1 is the Red Amp + Aux2Websocket websocket.Websocket // For 2024: Aux1 is the Blue Amp + Aux3Websocket websocket.Websocket // General use + Aux4Websocket websocket.Websocket // General use + Aux3Enabled bool + Aux4Enabled bool + isHealthy bool + inputs [inputCount]bool + registers [registerCount]uint16 + oldInputs [inputCount]bool + oldRegisters [registerCount]uint16 + oldCoils [coilCount]bool + cycleCounter int + matchResetCycles int + scoringEquipment bool +} + +// Discrete inputs +// +//go:generate stringer -type=input +type input int + +const ( + fieldEStop input = iota + red1EStop + red1AStop + red2EStop + red2AStop + red3EStop + red3AStop + blue1EStop + blue1AStop + blue2EStop + blue2AStop + blue3EStop + blue3AStop + redConnected1 + redConnected2 + redConnected3 + blueConnected1 + blueConnected2 + blueConnected3 + redAmplify + redCoop + blueAmplify + blueCoop + inputCount +) + +// 16-bit registers +// +//go:generate stringer -type=register +type register int + +const ( + fieldIoConnection register = iota + redSpeaker + blueSpeaker + redAmp + blueAmp + miscounts + registerCount +) + +// Coils +// +//go:generate stringer -type=coil +type coil int + +const ( + heartbeat coil = iota + matchReset + stackLightGreen + stackLightOrange + stackLightRed + stackLightBlue + stackLightBuzzer + fieldResetLight + speakerMotors + redSpeakerLight + blueSpeakerLight + redSubwooferCountdown + blueSubwooferCountdown + redAmpLightLow + redAmpLightHigh + redAmpLightCoop + blueAmpLightLow + blueAmpLightHigh + blueAmpLightCoop + postMatchSubwooferLights + coilCount +) + +func (ws *SmcWS) Run() { + for { + if plc.handler == nil { + if !plc.IsEnabled() { + // No PLC is configured; just allow the loop to continue to simulate inputs and outputs. + plc.isHealthy = false + } else { + err := plc.connect() + if err != nil { + log.Printf("PLC error: %v", err) + time.Sleep(time.Second * plcRetryIntevalSec) + plc.isHealthy = false + continue + } + } + } + + startTime := time.Now() + plc.update() + time.Sleep(time.Until(startTime.Add(time.Millisecond * plcLoopPeriodMs))) + } +} diff --git a/templates/base.html b/templates/base.html index 85d37f4c..e2a9b6cc 100644 --- a/templates/base.html +++ b/templates/base.html @@ -130,7 +130,7 @@