Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a459595
fix: add resolve to promise
maximka76667 Mar 5, 2026
59b8f09
go back
maximka76667 Mar 5, 2026
b832fc4
feat: remove pacman and rpm distributives
maximka76667 Mar 5, 2026
7100c99
feat: add loading when saving settings and fix backend panic
maximka76667 Mar 7, 2026
2599ade
fix: apply some fixes
maximka76667 Mar 7, 2026
ab6862f
refact: move some variables to config.ts
maximka76667 Mar 7, 2026
65739de
style: change product name
maximka76667 Mar 7, 2026
1262777
feat: implement versioning
maximka76667 Mar 11, 2026
8d4528a
fix: make tests pass
maximka76667 Mar 11, 2026
a2e9d45
fix: some errors
maximka76667 Mar 11, 2026
1884071
bump: icons-master
maximka76667 Mar 12, 2026
9ee2364
bump: bump icons master
maximka76667 Mar 12, 2026
fb8f6d6
docs: icons master does support all systems now
maximka76667 Mar 12, 2026
e08b570
docs: fix comment
maximka76667 Mar 12, 2026
ccf6f54
docs: fix docs
maximka76667 Mar 12, 2026
4ea880e
docs: remove packet-sender mentions
maximka76667 Mar 12, 2026
cfbbd60
feat: replace branch input with combobox
maximka76667 Mar 13, 2026
8bddb4f
feat: add logger commands to key bindings
maximka76667 Mar 13, 2026
bde3849
style: add symbol-based text at the beginning of a script
maximka76667 Mar 14, 2026
db0d325
fix: prevent key bindings if a dialog is open
maximka76667 Mar 14, 2026
2e662c1
fix: fix dialog focus
maximka76667 Mar 14, 2026
85dfbba
feat: refactor logging system and add trace logger
JavierRibaldelRio Mar 14, 2026
02e2e85
feat: validate button
JavierRibaldelRio Mar 14, 2026
193dc48
feat: execute adj validator before running backend and logging it
JavierRibaldelRio Mar 14, 2026
aa7df48
fix: add logging to adj download module
JavierRibaldelRio Mar 14, 2026
8e2f6da
fix(backend): replace fmt logging with zerolog trace logging in logge…
JavierRibaldelRio Mar 14, 2026
706f8c0
fix(backend, adj-validator): apply it without colour
JavierRibaldelRio Mar 14, 2026
3db0116
fic(trace)!: correct extension, change .json to .jsonl
JavierRibaldelRio Mar 15, 2026
03cd625
fix(backend, main): log using trace insetead of panic
JavierRibaldelRio Mar 15, 2026
6e3c2b4
remove(backend, BLCU): remove files related to BLCU connection
JavierRibaldelRio Mar 15, 2026
48e4a86
remove(backend, BLCU): remove BLCU
JavierRibaldelRio Mar 15, 2026
f4cce40
feat(backend, udp): add UDP configuration and enhance UDP server func…
JavierRibaldelRio Mar 15, 2026
7f55760
fix: change to debug
JavierRibaldelRio Mar 15, 2026
d163f1e
Merge pull request #468 from Hyperloop-UPV/control-station/config-ver…
JavierRibaldelRio Mar 15, 2026
597d34a
Merge branch 'develop' into backend/new-fixes
JavierRibaldelRio Mar 15, 2026
8e41763
Merge pull request #469 from Hyperloop-UPV/backend/new-fixes
JavierRibaldelRio Mar 15, 2026
79cf9ff
Merge branch 'production' into develop
JFisica Mar 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ jobs:
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y rpm libarchive-tools

# Download ONLY the appropriate backend for this platform
- name: Download Linux backend
Expand Down Expand Up @@ -188,8 +187,6 @@ jobs:
electron-app/dist/*.exe
electron-app/dist/*.AppImage
electron-app/dist/*.deb
electron-app/dist/*.rpm
electron-app/dist/*.pacman
electron-app/dist/*.dmg
electron-app/dist/*.zip
electron-app/dist/*.yml
Expand Down
25 changes: 13 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Hyperloop Control Station H11
![Testing View](https://raw.githubusercontent.com/Hyperloop-UPV/webpage/5c1c827d82d380689856ee61af43da30da22e0fc/src/assets/backgrounds/testing-view.png)

![Testing View](https://raw.githubusercontent.com/Hyperloop-UPV/webpage/5c1c827d82d380689856ee61af43da30da22e0fc/src/assets/backgrounds/testing-view.png)

## Monorepo usage

Expand All @@ -20,17 +21,17 @@ Before starting, ensure you have the following installed:

Our `pnpm-workspace.yaml` defines the following workspaces:

| Workspace | Language | Description |
| :----------------------------- | :------- | :--------------------------------------------- |
| `testing-view` | TS/React | Web interface for telemetry testing |
| `competition-view` | TS/React | UI for the competition |
| `backend` | Go | Data ingestion and pod communication server |
| `packet-sender` | Rust | Utility for simulating vehicle packets |
| `electron-app` | JS | The main Control Station desktop application |
| `@workspace/ui` | TS/React | Shared UI component library (frontend-kit) |
| `@workspace/core` | TS | Shared business logic and types (frontend-kit) |
| `@workspace/eslint-config` | ESLint | Common ESLint configuration (frontend-kit) |
| `@workspace/typescript-config` | TS | Common TypeScript configuration (frontend-kit) |
| Workspace | Language | Description |
| :----------------------------- | :------- | :---------------------------------------------------- |
| `testing-view` | TS/React | Web interface for telemetry testing |
| `competition-view` | TS/React | UI for the competition |
| `backend` | Go | Data ingestion and pod communication server |
| `packet-sender` | Rust | Utility for simulating vehicle packets |
| `hyperloop-control-station` | JS | The main Control Station electron desktop application |
| `@workspace/ui` | TS/React | Shared UI component library (frontend-kit) |
| `@workspace/core` | TS | Shared business logic and types (frontend-kit) |
| `@workspace/eslint-config` | ESLint | Common ESLint configuration (frontend-kit) |
| `@workspace/typescript-config` | TS | Common TypeScript configuration (frontend-kit) |

---

Expand Down
7 changes: 7 additions & 0 deletions backend/cmd/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ boards = ["BCU", "BMSL", "HVSCU", "HVSCU-Cabinet", "LCU", "PCU", "VCU", "BLCU"]
# ADJ (Architecture Description JSON) Configuration
[adj]
branch = "main" # Leave blank when using ADJ as a submodule (like this: "")
validate = true # Execute ADJ validator before starting backend

# Transport Configuration
[transport]
Expand All @@ -33,6 +34,12 @@ max_retries = 0 # Maximum retries before cycling (0 = infinite retr
connection_timeout_ms = 1000 # Connection timeout in milliseconds
keep_alive_ms = 1000 # Keep-alive interval in milliseconds

# UDP Configuration
# These settings control the UDP server's buffer sizes and performance characteristics
[udp]
ring_buffer_size = 64 # Size of the ring buffer for incoming packets (number of packets, not bytes)
packet_chan_size = 16 # Size of the channel buffer

# TFTP Configuration
[tftp]
block_size = 131072 # TFTP block size in bytes (128kB)
Expand Down
8 changes: 7 additions & 1 deletion backend/cmd/dev-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ boards = ["HVSCU", "HVSCU-Cabinet", "PCU", "LCU", "BCU", "BMSL"]
# ADJ (Architecture Description JSON) Configuration
[adj]
branch = "software" # Leave blank when using ADJ as a submodule (like this: "")

validate = true # Execute ADJ validator before starting backend

# Transport Configuration
[transport]
Expand All @@ -35,6 +35,12 @@ max_retries = 0 # Maximum retries before cycling (0 = infinite re
connection_timeout_ms = 999999 # Timeout for the initial connection attempt
keep_alive_ms = 0 # Keep-alive interval in milliseconds (0 to disable)

# UDP Configuration
# These settings control the UDP server's buffer sizes and performance characteristics
[udp]
ring_buffer_size = 64 # Size of the ring buffer for incoming packets (number of packets, not bytes)
packet_chan_size = 16 # Size of the channel buffer

# Server Configuration
[server.ethernet-view]
address = "127.0.0.1:4040"
Expand Down
6 changes: 4 additions & 2 deletions backend/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"github.com/HyperloopUPV-H8/h9-backend/internal/flags"
"github.com/HyperloopUPV-H8/h9-backend/internal/pod_data"
"github.com/HyperloopUPV-H8/h9-backend/internal/update_factory"
tracelogger "github.com/HyperloopUPV-H8/h9-backend/pkg/logger/trace"

vehicle_models "github.com/HyperloopUPV-H8/h9-backend/internal/vehicle/models"
adj_module "github.com/HyperloopUPV-H8/h9-backend/pkg/adj"
"github.com/HyperloopUPV-H8/h9-backend/pkg/transport"
Expand All @@ -33,7 +35,7 @@ func main() {
handleVersionFlag()

// Configure trace
traceFile := initTrace(flags.TraceLevel, flags.TraceFile)
traceFile := tracelogger.InitTrace(flags.TraceLevel)
if traceFile != nil {
defer traceFile.Close()
}
Expand All @@ -49,7 +51,7 @@ func main() {
}

// <--- ADJ --->
adj, err := adj_module.NewADJ(config.Adj.Branch)
adj, err := adj_module.NewADJ(config.Adj)
if err != nil {
trace.Fatal().Err(err).Msg("setting up ADJ")
}
Expand Down
8 changes: 5 additions & 3 deletions backend/cmd/setup_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func configureTransport(
configureTCPServerTransport(adj, transp)

// Start handling network packets using UDP server
configureUDPServerTransport(adj, transp)
configureUDPServerTransport(adj, transp, config)

}

Expand Down Expand Up @@ -133,12 +133,14 @@ func configureTCPServerTransport(
func configureUDPServerTransport(
adj adj_module.ADJ,
transp *transport.Transport,
config config.Config,

) {
trace.Info().Msg("Starting UDP server")
udpServer := udp.NewServer(adj.Info.Addresses[BACKEND], adj.Info.Ports[UDP], &trace.Logger)
udpServer := udp.NewServer(adj.Info.Addresses[BACKEND], adj.Info.Ports[UDP], &trace.Logger, config.UDP.RingBufferSize, config.UDP.PacketChanSize)
err := udpServer.Start()
if err != nil {
panic("failed to start UDP server: " + err.Error())
trace.Fatal().Err(err).Msg("failed to start UDP server: " + err.Error())
}
go transp.HandleUDPServer(udpServer)
}
Expand Down
9 changes: 8 additions & 1 deletion backend/internal/config/config_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ type App struct {
}

type Adj struct {
Branch string `toml:"branch"`
Branch string `toml:"branch"`
Validate bool `toml:"validate"`
}

type Transport struct {
Expand All @@ -35,6 +36,11 @@ type TCP struct {
KeepAlive int `toml:"keep_alive_ms"`
}

type UDP struct {
RingBufferSize int `toml:"ring_buffer_size"`
PacketChanSize int `toml:"packet_chan_size"`
}

type Logging struct {
TimeUnit logger.TimeUnit `toml:"time_unit"`
LoggingPath string `toml:"logging_path"`
Expand All @@ -48,5 +54,6 @@ type Config struct {
Transport Transport
TFTP TFTP
TCP TCP
UDP UDP
Logging Logging
}
1 change: 0 additions & 1 deletion backend/internal/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ func Init() {
flag.StringVar(&ConfigFile, "config", "config.toml", "path to configuration file")
flag.BoolVar(&ConfigAllowUnknown, "config-allow-unknown", false, "allow unknown fields in configuration file")
flag.StringVar(&TraceLevel, "trace", "info", "set the trace level (\"fatal\", \"error\", \"warn\", \"info\", \"debug\", \"trace\")")
flag.StringVar(&TraceFile, "log", "", "set the trace log file")
flag.StringVar(&CPUProfile, "cpuprofile", "", "write cpu profile to file")
flag.BoolVar(&EnableSNTP, "sntp", false, "enables a simple SNTP server on port 123")
flag.IntVar(&BlockProfile, "blockprofile", 0, "number of block profiles to include")
Expand Down
20 changes: 15 additions & 5 deletions backend/pkg/adj/adj.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import (
"os"
"path/filepath"

"github.com/HyperloopUPV-H8/h9-backend/internal/config"
"github.com/HyperloopUPV-H8/h9-backend/internal/utils"
)

const (
RepoURL = "https://github.com/Hyperloop-UPV/adj.git" // URL of the ADJ repository
RepoURL = "https://github.com/Hyperloop-UPV/adj.git" // URL of the ADJ repository
ADJValidatorScript = ".github/workflows/scripts/adj-tester/main.py" // Path of ADJ valdiator
)

var RepoPath = getRepoPath()
Expand All @@ -32,8 +34,8 @@ func getRepoPath() string {
return absPath + string(filepath.Separator)
}

func NewADJ(AdjBranch string) (ADJ, error) {
infoRaw, boardsRaw, err := downloadADJ(AdjBranch)
func NewADJ(AdjSettings config.Adj) (ADJ, error) {
infoRaw, boardsRaw, err := downloadADJ(AdjSettings)
if err != nil {
return ADJ{}, err
}
Expand Down Expand Up @@ -87,8 +89,16 @@ func NewADJ(AdjBranch string) (ADJ, error) {
return adj, nil
}

func downloadADJ(AdjBranch string) (json.RawMessage, json.RawMessage, error) {
updateRepo(AdjBranch)
func downloadADJ(AdjSettings config.Adj) (json.RawMessage, json.RawMessage, error) {
updateRepo(AdjSettings.Branch)

// After downloading adj apply adj validator

if AdjSettings.Validate {

Validate()

}

info, err := os.ReadFile(RepoPath + "general_info.json")
if err != nil {
Expand Down
7 changes: 5 additions & 2 deletions backend/pkg/adj/git.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package adj

import (
"log"
"os"
"path/filepath"

trace "github.com/rs/zerolog/log"

"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
)
Expand All @@ -20,8 +21,10 @@ func updateRepo(AdjBranch string) error {

if AdjBranch == "" {
// Makes use of user's custom ADJ
trace.Info().Msg("No ADJ branch specified. Using local ADJ.")
return nil
} else {
trace.Info().Msgf("Updating local ADJ repository to match remote branch '%s'", AdjBranch)
cloneOptions := &git.CloneOptions{
URL: RepoURL,
ReferenceName: plumbing.NewBranchReferenceName(AdjBranch),
Expand All @@ -41,7 +44,7 @@ func updateRepo(AdjBranch string) error {
_, err = git.PlainClone(tempPath, false, cloneOptions)
if err != nil {
// If the clone fails, work with the local ADJ
log.Printf("Warning: Could not clone ADJ branch '%s' from remote. Working with local ADJ. Error: %v", AdjBranch, err)
trace.Info().Msgf("Warning: Could not clone ADJ branch '%s' from remote. Working with local ADJ. Error: %v", AdjBranch, err)
return nil
}

Expand Down
75 changes: 75 additions & 0 deletions backend/pkg/adj/validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package adj

import (
"os/exec"
"path"
"strings"

trace "github.com/rs/zerolog/log"

"github.com/HyperloopUPV-H8/h9-backend/pkg/logger/validator"
)

func Validate() {

trace.Info().Msg("Starting ADJ-Validator")

// Check for Python interpreter is installed and accessible
pyCmd := pythonCommand()
if pyCmd == "" {
trace.Fatal().Msg("No Python interpreter found in PATH. Please install Python 3 and ensure it's accessible via 'python3', 'python', or 'py' command.")
}

// Construct the full path to the ADJ validator script
validatorPath := path.Join(RepoPath, ADJValidatorScript)

trace.Debug().Msgf("Running ADJ Validator using command: %s %s --no-color", pyCmd, validatorPath)

// Execute the ADJ validator script and capture its output
cmd := exec.Command(pyCmd, validatorPath, "--no-color")
output, err := cmd.CombinedOutput()

// Log the output of the validator for debugging purposes
validator.LogADJValidatorOutput(output)

// If the command returns a non-zero exit code, it indicates a validation failure or an error during execution
if err != nil {

if strings.Contains(string(output), "JSON Validation Script") {

trace.Fatal().Msg("ADJ Validator failed with error, check the output for details.")

}

trace.Fatal().Msgf("Error executing ADJ Validator with command '%s %s'. Ensure that you have installed jsonschema with 'pip install jsonschema==4.25.0' and is accessible in your PATH.", pyCmd, validatorPath)

}

}

// pythonCommand returns the name of a Python interpreter executable
// available in the current system PATH.
//
// It checks a list of common Python command names in order of preference:
// - "python3" (typical on Linux/macOS)
// - "python" (may point to Python 3 on many systems)
// - "py" (Python launcher commonly available on Windows)
//
// For each candidate, exec.LookPath is used to determine whether the
// executable can be found in the PATH. The function returns the first
// command that exists.
//
// If none of the candidates are found, an empty string is returned,
// indicating that no Python interpreter is available.
func pythonCommand() string {
candidates := []string{"python3", "python", "py"}

for _, c := range candidates {
_, err := exec.LookPath(c)
if err == nil {
return c
}
}

return ""
}
Loading
Loading