Skip to content

Commit 8e41763

Browse files
Merge pull request #469 from Hyperloop-UPV/backend/new-fixes
Backend/new fixes
2 parents d163f1e + 597d34a commit 8e41763

24 files changed

Lines changed: 312 additions & 403 deletions

backend/cmd/config.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ boards = ["BCU", "BMSL", "HVSCU", "HVSCU-Cabinet", "LCU", "PCU", "VCU", "BLCU"]
1818
# ADJ (Architecture Description JSON) Configuration
1919
[adj]
2020
branch = "main" # Leave blank when using ADJ as a submodule (like this: "")
21+
validate = true # Execute ADJ validator before starting backend
2122

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

37+
# UDP Configuration
38+
# These settings control the UDP server's buffer sizes and performance characteristics
39+
[udp]
40+
ring_buffer_size = 64 # Size of the ring buffer for incoming packets (number of packets, not bytes)
41+
packet_chan_size = 16 # Size of the channel buffer
42+
3643
# TFTP Configuration
3744
[tftp]
3845
block_size = 131072 # TFTP block size in bytes (128kB)

backend/cmd/dev-config.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ boards = ["HVSCU", "HVSCU-Cabinet", "PCU", "LCU", "BCU", "BMSL"]
1919
# ADJ (Architecture Description JSON) Configuration
2020
[adj]
2121
branch = "software" # Leave blank when using ADJ as a submodule (like this: "")
22-
22+
validate = true # Execute ADJ validator before starting backend
2323

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

38+
# UDP Configuration
39+
# These settings control the UDP server's buffer sizes and performance characteristics
40+
[udp]
41+
ring_buffer_size = 64 # Size of the ring buffer for incoming packets (number of packets, not bytes)
42+
packet_chan_size = 16 # Size of the channel buffer
43+
3844
# Server Configuration
3945
[server.ethernet-view]
4046
address = "127.0.0.1:4040"

backend/cmd/main.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"github.com/HyperloopUPV-H8/h9-backend/internal/flags"
1010
"github.com/HyperloopUPV-H8/h9-backend/internal/pod_data"
1111
"github.com/HyperloopUPV-H8/h9-backend/internal/update_factory"
12+
tracelogger "github.com/HyperloopUPV-H8/h9-backend/pkg/logger/trace"
13+
1214
vehicle_models "github.com/HyperloopUPV-H8/h9-backend/internal/vehicle/models"
1315
adj_module "github.com/HyperloopUPV-H8/h9-backend/pkg/adj"
1416
"github.com/HyperloopUPV-H8/h9-backend/pkg/transport"
@@ -33,7 +35,7 @@ func main() {
3335
handleVersionFlag()
3436

3537
// Configure trace
36-
traceFile := initTrace(flags.TraceLevel, flags.TraceFile)
38+
traceFile := tracelogger.InitTrace(flags.TraceLevel)
3739
if traceFile != nil {
3840
defer traceFile.Close()
3941
}
@@ -49,7 +51,7 @@ func main() {
4951
}
5052

5153
// <--- ADJ --->
52-
adj, err := adj_module.NewADJ(config.Adj.Branch)
54+
adj, err := adj_module.NewADJ(config.Adj)
5355
if err != nil {
5456
trace.Fatal().Err(err).Msg("setting up ADJ")
5557
}

backend/cmd/setup_transport.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func configureTransport(
5050
configureTCPServerTransport(adj, transp)
5151

5252
// Start handling network packets using UDP server
53-
configureUDPServerTransport(adj, transp)
53+
configureUDPServerTransport(adj, transp, config)
5454

5555
}
5656

@@ -133,12 +133,14 @@ func configureTCPServerTransport(
133133
func configureUDPServerTransport(
134134
adj adj_module.ADJ,
135135
transp *transport.Transport,
136+
config config.Config,
137+
136138
) {
137139
trace.Info().Msg("Starting UDP server")
138-
udpServer := udp.NewServer(adj.Info.Addresses[BACKEND], adj.Info.Ports[UDP], &trace.Logger)
140+
udpServer := udp.NewServer(adj.Info.Addresses[BACKEND], adj.Info.Ports[UDP], &trace.Logger, config.UDP.RingBufferSize, config.UDP.PacketChanSize)
139141
err := udpServer.Start()
140142
if err != nil {
141-
panic("failed to start UDP server: " + err.Error())
143+
trace.Fatal().Err(err).Msg("failed to start UDP server: " + err.Error())
142144
}
143145
go transp.HandleUDPServer(udpServer)
144146
}

backend/internal/config/config_types.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ type App struct {
1111
}
1212

1313
type Adj struct {
14-
Branch string `toml:"branch"`
14+
Branch string `toml:"branch"`
15+
Validate bool `toml:"validate"`
1516
}
1617

1718
type Transport struct {
@@ -35,6 +36,11 @@ type TCP struct {
3536
KeepAlive int `toml:"keep_alive_ms"`
3637
}
3738

39+
type UDP struct {
40+
RingBufferSize int `toml:"ring_buffer_size"`
41+
PacketChanSize int `toml:"packet_chan_size"`
42+
}
43+
3844
type Logging struct {
3945
TimeUnit logger.TimeUnit `toml:"time_unit"`
4046
LoggingPath string `toml:"logging_path"`
@@ -48,5 +54,6 @@ type Config struct {
4854
Transport Transport
4955
TFTP TFTP
5056
TCP TCP
57+
UDP UDP
5158
Logging Logging
5259
}

backend/internal/flags/flags.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ func Init() {
3232
flag.StringVar(&ConfigFile, "config", "config.toml", "path to configuration file")
3333
flag.BoolVar(&ConfigAllowUnknown, "config-allow-unknown", false, "allow unknown fields in configuration file")
3434
flag.StringVar(&TraceLevel, "trace", "info", "set the trace level (\"fatal\", \"error\", \"warn\", \"info\", \"debug\", \"trace\")")
35-
flag.StringVar(&TraceFile, "log", "", "set the trace log file")
3635
flag.StringVar(&CPUProfile, "cpuprofile", "", "write cpu profile to file")
3736
flag.BoolVar(&EnableSNTP, "sntp", false, "enables a simple SNTP server on port 123")
3837
flag.IntVar(&BlockProfile, "blockprofile", 0, "number of block profiles to include")

backend/pkg/adj/adj.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import (
66
"os"
77
"path/filepath"
88

9+
"github.com/HyperloopUPV-H8/h9-backend/internal/config"
910
"github.com/HyperloopUPV-H8/h9-backend/internal/utils"
1011
)
1112

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

1618
var RepoPath = getRepoPath()
@@ -32,8 +34,8 @@ func getRepoPath() string {
3234
return absPath + string(filepath.Separator)
3335
}
3436

35-
func NewADJ(AdjBranch string) (ADJ, error) {
36-
infoRaw, boardsRaw, err := downloadADJ(AdjBranch)
37+
func NewADJ(AdjSettings config.Adj) (ADJ, error) {
38+
infoRaw, boardsRaw, err := downloadADJ(AdjSettings)
3739
if err != nil {
3840
return ADJ{}, err
3941
}
@@ -87,8 +89,16 @@ func NewADJ(AdjBranch string) (ADJ, error) {
8789
return adj, nil
8890
}
8991

90-
func downloadADJ(AdjBranch string) (json.RawMessage, json.RawMessage, error) {
91-
updateRepo(AdjBranch)
92+
func downloadADJ(AdjSettings config.Adj) (json.RawMessage, json.RawMessage, error) {
93+
updateRepo(AdjSettings.Branch)
94+
95+
// After downloading adj apply adj validator
96+
97+
if AdjSettings.Validate {
98+
99+
Validate()
100+
101+
}
92102

93103
info, err := os.ReadFile(RepoPath + "general_info.json")
94104
if err != nil {

backend/pkg/adj/git.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package adj
22

33
import (
4-
"log"
54
"os"
65
"path/filepath"
76

7+
trace "github.com/rs/zerolog/log"
8+
89
"github.com/go-git/go-git/v5"
910
"github.com/go-git/go-git/v5/plumbing"
1011
)
@@ -20,8 +21,10 @@ func updateRepo(AdjBranch string) error {
2021

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

backend/pkg/adj/validator.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package adj
2+
3+
import (
4+
"os/exec"
5+
"path"
6+
"strings"
7+
8+
trace "github.com/rs/zerolog/log"
9+
10+
"github.com/HyperloopUPV-H8/h9-backend/pkg/logger/validator"
11+
)
12+
13+
func Validate() {
14+
15+
trace.Info().Msg("Starting ADJ-Validator")
16+
17+
// Check for Python interpreter is installed and accessible
18+
pyCmd := pythonCommand()
19+
if pyCmd == "" {
20+
trace.Fatal().Msg("No Python interpreter found in PATH. Please install Python 3 and ensure it's accessible via 'python3', 'python', or 'py' command.")
21+
}
22+
23+
// Construct the full path to the ADJ validator script
24+
validatorPath := path.Join(RepoPath, ADJValidatorScript)
25+
26+
trace.Debug().Msgf("Running ADJ Validator using command: %s %s --no-color", pyCmd, validatorPath)
27+
28+
// Execute the ADJ validator script and capture its output
29+
cmd := exec.Command(pyCmd, validatorPath, "--no-color")
30+
output, err := cmd.CombinedOutput()
31+
32+
// Log the output of the validator for debugging purposes
33+
validator.LogADJValidatorOutput(output)
34+
35+
// If the command returns a non-zero exit code, it indicates a validation failure or an error during execution
36+
if err != nil {
37+
38+
if strings.Contains(string(output), "JSON Validation Script") {
39+
40+
trace.Fatal().Msg("ADJ Validator failed with error, check the output for details.")
41+
42+
}
43+
44+
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)
45+
46+
}
47+
48+
}
49+
50+
// pythonCommand returns the name of a Python interpreter executable
51+
// available in the current system PATH.
52+
//
53+
// It checks a list of common Python command names in order of preference:
54+
// - "python3" (typical on Linux/macOS)
55+
// - "python" (may point to Python 3 on many systems)
56+
// - "py" (Python launcher commonly available on Windows)
57+
//
58+
// For each candidate, exec.LookPath is used to determine whether the
59+
// executable can be found in the PATH. The function returns the first
60+
// command that exists.
61+
//
62+
// If none of the candidates are found, an empty string is returned,
63+
// indicating that no Python interpreter is available.
64+
func pythonCommand() string {
65+
candidates := []string{"python3", "python", "py"}
66+
67+
for _, c := range candidates {
68+
_, err := exec.LookPath(c)
69+
if err == nil {
70+
return c
71+
}
72+
}
73+
74+
return ""
75+
}

backend/pkg/logger/base/logger.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package loggerbase
22

33
import (
4-
"fmt"
54
"os"
65
"path"
76
"sync/atomic"
87
"time"
98

9+
trace "github.com/rs/zerolog/log"
10+
1011
"github.com/HyperloopUPV-H8/h9-backend/pkg/abstraction"
1112
loggerHandler "github.com/HyperloopUPV-H8/h9-backend/pkg/logger"
1213
"github.com/HyperloopUPV-H8/h9-backend/pkg/transport/packet/data"
@@ -42,33 +43,37 @@ type BaseLogger struct {
4243
// Function to start the base logger
4344
func (sublogger *BaseLogger) Start() error {
4445
if !sublogger.Running.CompareAndSwap(false, true) {
45-
fmt.Println("Logger already running")
46+
trace.Warn().Msg("Logger already running")
4647
return nil
4748
}
4849

4950
sublogger.StartTime = loggerHandler.FormatTimestamp(time.Now()) // Update the start time
5051

51-
fmt.Println("Logger started " + string(sublogger.Name) + ".")
52+
trace.Info().Msg("Logger " + string(sublogger.Name) + " started.")
5253
return nil
5354
}
5455

5556
// Function to create the base file path
5657

5758
func (sublogger *BaseLogger) CreateFile(filename string) (*os.File, error) {
59+
return CreateFile(loggerHandler.BasePath, sublogger.Name, filename)
60+
}
61+
62+
// Create File given a path name of loggerand file name
63+
func CreateFile(basePath string, name abstraction.LoggerName, filename string) (*os.File, error) {
5864

59-
// Includes the direcory specified by the user
60-
baseFilename := path.Join(loggerHandler.BasePath, filename)
65+
baseFilename := path.Join(basePath, filename)
6166

6267
err := os.MkdirAll(path.Dir(baseFilename), os.ModePerm)
6368
if err != nil {
6469
return nil, loggerHandler.ErrCreatingAllDir{
65-
Name: sublogger.Name,
70+
Name: name,
6671
Timestamp: time.Now(),
6772
Path: baseFilename,
6873
}
6974
}
7075

71-
return os.Create(path.Join(baseFilename))
76+
return os.Create(baseFilename)
7277
}
7378

7479
// Create a base Logger with default values
@@ -88,12 +93,12 @@ func (sublogger *BaseLogger) PullRecord(abstraction.LoggerRequest) (abstraction.
8893
// Param templateStop is a function that contains the specific stop actions of each logger
8994
func (sublogger *BaseLogger) Stop(templateStop func() error) error {
9095
if !sublogger.Running.CompareAndSwap(true, false) {
91-
fmt.Println("Logger already stopped" + string(sublogger.Name) + ".")
96+
trace.Warn().Msg("Logger already stopped" + string(sublogger.Name) + ".")
9297
return nil
9398
}
9499

95100
output := templateStop()
96101

97-
fmt.Println("Logger stopped " + string(sublogger.Name) + ".")
102+
trace.Info().Msg("Logger " + string(sublogger.Name) + " stopped.")
98103
return output
99104
}

0 commit comments

Comments
 (0)