Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
66 changes: 42 additions & 24 deletions backend/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ import (

const (
BACKEND = "backend"
BLCU = "blcu"
BLCU = "BLCU"
TcpClient = "TCP_CLIENT"
TcpServer = "TCP_SERVER"
UDP = "UDP"
Expand All @@ -88,7 +88,7 @@ var currentVersion string

func main() {
// update() // FIXME: Updater disabled due to cross-platform and reliability issues

traceFile := initTrace(*traceLevel, *traceFile)
defer traceFile.Close()

Expand Down Expand Up @@ -223,16 +223,34 @@ func main() {
// <--- BLCU Board --->
// Register BLCU board for handling bootloader operations
if blcuIP, exists := adj.Info.Addresses[BLCU]; exists {
tftpConfig := boards.TFTPConfig{
BlockSize: config.TFTP.BlockSize,
Retries: config.TFTP.Retries,
TimeoutMs: config.TFTP.TimeoutMs,
BackoffFactor: config.TFTP.BackoffFactor,
EnableProgress: config.TFTP.EnableProgress,
blcuId, idExists := adj.Info.BoardIds["BLCU"]
if !idExists {
trace.Error().Msg("BLCU IP found in ADJ but board ID missing")
} else {
// Get configurable order IDs or use defaults
downloadOrderId := config.Blcu.DownloadOrderId
uploadOrderId := config.Blcu.UploadOrderId
if downloadOrderId == 0 {
downloadOrderId = boards.DefaultBlcuDownloadOrderId
}
if uploadOrderId == 0 {
uploadOrderId = boards.DefaultBlcuUploadOrderId
}

tftpConfig := boards.TFTPConfig{
BlockSize: config.TFTP.BlockSize,
Retries: config.TFTP.Retries,
TimeoutMs: config.TFTP.TimeoutMs,
BackoffFactor: config.TFTP.BackoffFactor,
EnableProgress: config.TFTP.EnableProgress,
}
blcuBoard := boards.NewWithConfig(blcuIP, tftpConfig, abstraction.BoardId(blcuId), downloadOrderId, uploadOrderId)
vehicle.AddBoard(blcuBoard)
vehicle.SetBlcuId(abstraction.BoardId(blcuId))
trace.Info().Str("ip", blcuIP).Int("id", int(blcuId)).Uint16("download_order_id", downloadOrderId).Uint16("upload_order_id", uploadOrderId).Msg("BLCU board registered")
}
blcuBoard := boards.NewWithTFTPConfig(blcuIP, tftpConfig)
vehicle.AddBoard(blcuBoard)
trace.Info().Str("ip", blcuIP).Msg("BLCU board registered")
} else {
trace.Warn().Msg("BLCU not found in ADJ configuration - bootloader operations unavailable")
}

// <--- transport --->
Expand All @@ -254,15 +272,15 @@ func main() {
downloadOrderId := config.Blcu.DownloadOrderId
uploadOrderId := config.Blcu.UploadOrderId
if downloadOrderId == 0 {
downloadOrderId = boards.BlcuDownloadOrderId
downloadOrderId = boards.DefaultBlcuDownloadOrderId
}
if uploadOrderId == 0 {
uploadOrderId = boards.BlcuUploadOrderId
uploadOrderId = boards.DefaultBlcuUploadOrderId
}

transp.SetIdTarget(abstraction.PacketId(downloadOrderId), abstraction.TransportTarget("BLCU"))
transp.SetIdTarget(abstraction.PacketId(uploadOrderId), abstraction.TransportTarget("BLCU"))

// Use BLCU address from config, ADJ, or default
blcuIP := config.Blcu.IP
if blcuIP == "" {
Expand All @@ -289,23 +307,23 @@ func main() {
}
// Create TCP client config with custom parameters from config
clientConfig := tcp.NewClientConfig(backendTcpClientAddr)

// Apply custom timeout if specified
if config.TCP.ConnectionTimeout > 0 {
clientConfig.Timeout = time.Duration(config.TCP.ConnectionTimeout) * time.Millisecond
}

// Apply custom keep-alive if specified
if config.TCP.KeepAlive > 0 {
clientConfig.KeepAlive = time.Duration(config.TCP.KeepAlive) * time.Millisecond
}

// Apply custom backoff parameters
if config.TCP.BackoffMinMs > 0 || config.TCP.BackoffMaxMs > 0 || config.TCP.BackoffMultiplier > 0 {
minBackoff := 100 * time.Millisecond // default
maxBackoff := 5 * time.Second // default
multiplier := 1.5 // default
maxBackoff := 5 * time.Second // default
multiplier := 1.5 // default

if config.TCP.BackoffMinMs > 0 {
minBackoff = time.Duration(config.TCP.BackoffMinMs) * time.Millisecond
}
Expand All @@ -315,13 +333,13 @@ func main() {
if config.TCP.BackoffMultiplier > 0 {
multiplier = config.TCP.BackoffMultiplier
}

clientConfig.ConnectionBackoffFunction = tcp.NewExponentialBackoff(minBackoff, multiplier, maxBackoff)
}

// Apply max retries (0 or negative means infinite)
clientConfig.MaxConnectionRetries = config.TCP.MaxRetries

go transp.HandleClient(clientConfig, fmt.Sprintf("%s:%d", adj.Info.Addresses[board.Name], adj.Info.Ports[TcpServer]))
i++
}
Expand Down
52 changes: 35 additions & 17 deletions backend/pkg/boards/blcu.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,16 @@ import (
dataPacket "github.com/HyperloopUPV-H8/h9-backend/pkg/transport/packet/data"
)

// TODO! Get from ADE
const (
BlcuName = "BLCU"
BlcuId = abstraction.BoardId(1)

AckId = abstraction.BoardEvent("ACK")
DownloadEventId = abstraction.BoardEvent("DOWNLOAD")
UploadEventId = abstraction.BoardEvent("UPLOAD")

BlcuDownloadOrderId = 701
BlcuUploadOrderId = 700
// Default order IDs - can be overridden via config.toml
DefaultBlcuDownloadOrderId = 701
DefaultBlcuUploadOrderId = 700
)

type TFTPConfig struct {
Expand All @@ -33,31 +32,50 @@ type TFTPConfig struct {
}

type BLCU struct {
api abstraction.BoardAPI
ackChan chan struct{}
ip string
tftpConfig TFTPConfig
api abstraction.BoardAPI
ackChan chan struct{}
ip string
tftpConfig TFTPConfig
id abstraction.BoardId
downloadOrderId uint16
uploadOrderId uint16
}

// Deprecated: Use NewWithConfig with proper board ID and order IDs from configuration
func New(ip string) *BLCU {
return NewWithTFTPConfig(ip, TFTPConfig{
BlockSize: 131072, // 128kB
Retries: 3,
TimeoutMs: 5000,
BackoffFactor: 2,
EnableProgress: true,
})
}, 0) // Board ID 0 indicates missing configuration
}

func NewWithTFTPConfig(ip string, tftpConfig TFTPConfig) *BLCU {
// Deprecated: Use NewWithConfig for proper order ID configuration
func NewWithTFTPConfig(ip string, tftpConfig TFTPConfig, id abstraction.BoardId) *BLCU {
return &BLCU{
ackChan: make(chan struct{}),
ip: ip,
tftpConfig: tftpConfig,
ackChan: make(chan struct{}),
ip: ip,
tftpConfig: tftpConfig,
id: id,
downloadOrderId: DefaultBlcuDownloadOrderId,
uploadOrderId: DefaultBlcuUploadOrderId,
}
}
func (boards *BLCU) Id() abstraction.BoardId {
return BlcuId

func NewWithConfig(ip string, tftpConfig TFTPConfig, id abstraction.BoardId, downloadOrderId, uploadOrderId uint16) *BLCU {
return &BLCU{
ackChan: make(chan struct{}),
ip: ip,
tftpConfig: tftpConfig,
id: id,
downloadOrderId: downloadOrderId,
uploadOrderId: uploadOrderId,
}
}
func (board *BLCU) Id() abstraction.BoardId {
return board.id
}

func (boards *BLCU) Notify(boardNotification abstraction.BoardNotification) {
Expand Down Expand Up @@ -96,7 +114,7 @@ func (boards *BLCU) SetAPI(api abstraction.BoardAPI) {
func (boards *BLCU) download(notification DownloadEvent) error {
// Notify the BLCU
ping := dataPacket.NewPacketWithValues(
abstraction.PacketId(BlcuDownloadOrderId),
abstraction.PacketId(boards.downloadOrderId),
map[dataPacket.ValueName]dataPacket.Value{
BlcuName: dataPacket.NewEnumValue(dataPacket.EnumVariant(notification.Board)),
},
Expand Down Expand Up @@ -169,7 +187,7 @@ func (boards *BLCU) download(notification DownloadEvent) error {
}

func (boards *BLCU) upload(notification UploadEvent) error {
ping := dataPacket.NewPacketWithValues(abstraction.PacketId(BlcuUploadOrderId),
ping := dataPacket.NewPacketWithValues(abstraction.PacketId(boards.uploadOrderId),
map[dataPacket.ValueName]dataPacket.Value{
BlcuName: dataPacket.NewEnumValue(dataPacket.EnumVariant(notification.Board)),
},
Expand Down
60 changes: 56 additions & 4 deletions backend/pkg/boards/blcu_simple_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,76 @@ package boards_test
import (
"testing"

"github.com/HyperloopUPV-H8/h9-backend/pkg/abstraction"
"github.com/HyperloopUPV-H8/h9-backend/pkg/boards"
blcu_topic "github.com/HyperloopUPV-H8/h9-backend/pkg/broker/topics/blcu"
"github.com/HyperloopUPV-H8/h9-backend/pkg/vehicle"
"github.com/rs/zerolog"
)

// TestBLCUBoardRegistration tests that BLCU board can be registered
// TestBLCUBoardRegistration tests that BLCU board can be registered with different configurations
func TestBLCUBoardRegistration(t *testing.T) {
logger := zerolog.New(nil).Level(zerolog.Disabled)
v := vehicle.New(logger)

// Create and register BLCU board
// Test deprecated constructor (should use board ID 0)
blcuBoard := boards.New("192.168.0.10")
v.AddBoard(blcuBoard)

// Verify board is registered with ID 0 (missing configuration)
if blcuBoard.Id() != 0 {
t.Errorf("Expected board ID 0 for deprecated constructor, got %d", blcuBoard.Id())
}
}

// TestBLCUWithCustomConfiguration tests BLCU with custom board ID and order IDs
func TestBLCUWithCustomConfiguration(t *testing.T) {
logger := zerolog.New(nil).Level(zerolog.Disabled)
v := vehicle.New(logger)

// Test new constructor with custom configuration
tftpConfig := boards.TFTPConfig{
BlockSize: 131072,
Retries: 3,
TimeoutMs: 5000,
BackoffFactor: 2,
EnableProgress: true,
}

customBoardId := abstraction.BoardId(7)
customDownloadOrderId := uint16(801)
customUploadOrderId := uint16(802)

blcuBoard := boards.NewWithConfig("192.168.0.10", tftpConfig, customBoardId, customDownloadOrderId, customUploadOrderId)
v.AddBoard(blcuBoard)

// Verify board is registered with custom ID
if blcuBoard.Id() != customBoardId {
t.Errorf("Expected board ID %d, got %d", customBoardId, blcuBoard.Id())
}
}

// TestBLCUWithDefaultConfiguration tests BLCU with default order IDs
func TestBLCUWithDefaultConfiguration(t *testing.T) {
logger := zerolog.New(nil).Level(zerolog.Disabled)
v := vehicle.New(logger)

// Test deprecated constructor (should use default order IDs)
tftpConfig := boards.TFTPConfig{
BlockSize: 131072,
Retries: 3,
TimeoutMs: 5000,
BackoffFactor: 2,
EnableProgress: true,
}

boardId := abstraction.BoardId(7)
blcuBoard := boards.NewWithTFTPConfig("192.168.0.10", tftpConfig, boardId)
v.AddBoard(blcuBoard)

// Verify board is registered
if blcuBoard.Id() != boards.BlcuId {
t.Errorf("Expected board ID %d, got %d", boards.BlcuId, blcuBoard.Id())
if blcuBoard.Id() != boardId {
t.Errorf("Expected board ID %d, got %d", boardId, blcuBoard.Id())
}
}

Expand Down
5 changes: 5 additions & 0 deletions backend/pkg/vehicle/constructor.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,8 @@ func (vehicle *Vehicle) SetIpToBoardId(ipToBoardId map[string]abstraction.BoardI
vehicle.ipToBoardId = ipToBoardId
vehicle.trace.Info().Msg("set ip to board id")
}

func (vehicle *Vehicle) SetBlcuId(id abstraction.BoardId) {
vehicle.BlcuId = id
vehicle.trace.Info().Uint16("blcu_id", uint16(id)).Msg("set blcu id")
}
2 changes: 1 addition & 1 deletion backend/pkg/vehicle/notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func (vehicle *Vehicle) handlePacketNotification(notification transport.PacketNo
return errors.Join(fmt.Errorf("remove state orders (state orders from %s to %s)", notification.From, notification.To), err)
}
case *blcu_packet.Ack:
vehicle.boards[boards.BlcuId].Notify(abstraction.BoardNotification(
vehicle.boards[vehicle.BlcuId].Notify(abstraction.BoardNotification(
&boards.AckNotification{
ID: boards.AckId,
},
Expand Down
7 changes: 4 additions & 3 deletions backend/pkg/vehicle/vehicle.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type Vehicle struct {
updateFactory *update_factory.UpdateFactory
idToBoardName map[uint16]string
ipToBoardId map[string]abstraction.BoardId
BlcuId abstraction.BoardId

trace zerolog.Logger
}
Expand Down Expand Up @@ -92,11 +93,11 @@ func (vehicle *Vehicle) UserPush(push abstraction.BrokerPush) error {
case "blcu/downloadRequest":
download := push.(*blcu_topic.DownloadRequest)

if board, exists := vehicle.boards[boards.BlcuId]; exists {
if board, exists := vehicle.boards[vehicle.BlcuId]; exists {
board.Notify(abstraction.BoardNotification(
&boards.DownloadEvent{
BoardEvent: boards.DownloadEventId,
BoardID: boards.BlcuId,
BoardID: vehicle.BlcuId,
Board: download.Board,
},
))
Expand Down Expand Up @@ -124,7 +125,7 @@ func (vehicle *Vehicle) UserPush(push abstraction.BrokerPush) error {
return nil
}

if board, exists := vehicle.boards[boards.BlcuId]; exists {
if board, exists := vehicle.boards[vehicle.BlcuId]; exists {
board.Notify(abstraction.BoardNotification(uploadEvent))
} else {
fmt.Fprintf(os.Stderr, "BLCU board not registered\n")
Expand Down
Loading