Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a80e953
Send a confirmation message to the frontend
JFisica Jun 21, 2025
e36c93e
Changed Push to use board name instead of board id
JFisica Jun 21, 2025
0816d2a
Show confirmation message after actually sending the order
JFisica Jun 21, 2025
cef55f0
Remove boardIdToBoard
JFisica Jun 21, 2025
aa5bde7
Merge pull request #333 from HyperloopUPV-H8/backend/confirmation-mes…
msanlli Jun 22, 2025
e2cc097
filterMessage to test
ariadnatp Jun 24, 2025
253d5b7
Merge branch 'develop' into ethernet-view/charts-view
msanlli Jun 25, 2025
6f8df5f
Implement plot memory on a higher level so it isn't destroyed when cl…
JFisica Jun 25, 2025
0f4e5e9
remove unnecessary variable
JFisica Jun 25, 2025
0f756c9
Change buttons to english
JFisica Jun 25, 2025
0806e6c
Implement the necessary buttons
JFisica Jun 25, 2025
d9ebd4d
Log enabled by default on all variables
JFisica Jun 25, 2025
e24740b
Fixed for non-numeric values, and moved the checkbox to the left
JFisica Jun 25, 2025
7d1e5a3
Fixed logic for sending variables to the backend
JFisica Jun 25, 2025
5f86032
Remove temp console.log
JFisica Jun 25, 2025
70f436a
Add allowed variables to data logger
JFisica Jun 26, 2025
b572970
Merge pull request #338 from HyperloopUPV-H8/ethernet-view/plot-disap…
msanlli Jun 26, 2025
bcfa1b3
Merge branch 'develop' into ethernet-view/charts-view
msanlli Jun 26, 2025
b5ae134
Connect the logger/variables to correctly change the data_logger par…
JFisica Jun 26, 2025
25bc89b
Update log-all and log-none for collapsed boards
JFisica Jun 26, 2025
2f599bc
Added board prefix to measurements
JFisica Jun 27, 2025
d611648
Use bcu master nested state
JFisica Jun 27, 2025
3e8e7b5
Merge pull request #341 from HyperloopUPV-H8/control-station/booster-…
msanlli Jun 27, 2025
1e94ea0
Merge branch 'develop' into ethernet-view/log-variables-custom
msanlli Jun 27, 2025
d73c401
Merge pull request #340 from HyperloopUPV-H8/ethernet-view/log-variab…
msanlli Jun 27, 2025
30bc8f8
Merge branch 'develop' into backend/log-variables-custom
msanlli Jun 27, 2025
170da9f
Merge pull request #339 from HyperloopUPV-H8/backend/log-variables-cu…
msanlli Jun 27, 2025
9c8d7dc
Merge branch 'develop' into ethernet-view/charts-view
msanlli Jul 1, 2025
824978b
Merge pull request #336 from HyperloopUPV-H8/ethernet-view/charts-view
msanlli Jul 1, 2025
5b9932e
Merge branch 'main' into develop
msanlli Jul 7, 2025
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
9 changes: 4 additions & 5 deletions backend/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,9 @@ func main() {
connectionTopic := connection_topic.NewUpdateTopic()
orderTopic := order_topic.NewSendTopic()
loggerTopic := logger_topic.NewEnableTopic()
boardIdToBoard := make(map[abstraction.BoardId]string)
for name, id := range adj.Info.BoardIds {
boardIdToBoard[abstraction.BoardId(id)] = name
}
messageTopic := message_topic.NewUpdateTopic(boardIdToBoard)
loggerTopic.SetDataLogger(subloggers[data_logger.Name].(*data_logger.Logger))

messageTopic := message_topic.NewUpdateTopic()
stateOrderTopic := order_topic.NewState(idToBoard, trace.Logger)

broker.AddTopic(data_topic.UpdateName, dataTopic)
Expand All @@ -194,6 +192,7 @@ func main() {
broker.AddTopic(order_topic.StateName, stateOrderTopic)
broker.AddTopic(logger_topic.EnableName, loggerTopic)
broker.AddTopic(logger_topic.ResponseName, loggerTopic)
broker.AddTopic(logger_topic.VariablesName, loggerTopic)
broker.AddTopic(message_topic.UpdateName, messageTopic)

connections := make(chan *websocket.Client)
Expand Down
23 changes: 23 additions & 0 deletions backend/pkg/broker/topics/logger/enable.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,23 @@ import (
"sync/atomic"

"github.com/HyperloopUPV-H8/h9-backend/pkg/abstraction"
data_logger "github.com/HyperloopUPV-H8/h9-backend/pkg/logger/data"
"github.com/HyperloopUPV-H8/h9-backend/pkg/websocket"
"github.com/google/uuid"
ws "github.com/gorilla/websocket"
)

const EnableName abstraction.BrokerTopic = "logger/enable"
const ResponseName abstraction.BrokerTopic = "logger/response"
const VariablesName abstraction.BrokerTopic = "logger/variables"

type Enable struct {
isRunning *atomic.Bool
pool *websocket.Pool
connectionMx *sync.Mutex
subscribers map[websocket.ClientId]struct{}
api abstraction.BrokerAPI
data_logger *data_logger.Logger
}

func NewEnableTopic() *Enable {
Expand Down Expand Up @@ -58,6 +61,12 @@ func (enable *Enable) ClientMessage(id websocket.ClientId, message *websocket.Me

fmt.Printf("logger/response subscribed %s\n", uuid.UUID(id).String())
enable.subscribers[id] = struct{}{}

case VariablesName:
err := enable.handleVariables(id, message)
if err != nil {
fmt.Printf("error handling logger/variables: %v\n", err)
}
default:
enable.connectionMx.Lock()
defer enable.connectionMx.Unlock()
Expand Down Expand Up @@ -85,6 +94,16 @@ func (enable *Enable) handleToggle(_ websocket.ClientId, message *websocket.Mess
return nil
}

func (enable *Enable) handleVariables(_ websocket.ClientId, message *websocket.Message) error {
var allowedVars []string
err := json.Unmarshal(message.Payload, &allowedVars)
if err != nil {
return err
}
enable.data_logger.SetAllowedVars(allowedVars)
return nil
}

func (enable *Enable) broadcastState() error {
payload, err := json.Marshal(enable.isRunning.Load())
if err != nil {
Expand Down Expand Up @@ -123,6 +142,10 @@ func (enable *Enable) SetAPI(api abstraction.BrokerAPI) {
enable.api = api
}

func (enable *Enable) SetDataLogger(logger *data_logger.Logger) {
enable.data_logger = logger
}

type Status struct {
request bool
response chan bool
Expand Down
8 changes: 4 additions & 4 deletions backend/pkg/broker/topics/message/message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ func TestMessageTopic_Push(t *testing.T) {
client := websocket.NewClient(c)
clientChan <- client

messageTopic := data.NewUpdateTopic(map[abstraction.BoardId]string{})
messageTopic := data.NewUpdateTopic()
messageTopic.SetAPI(api)
messageTopic.SetPool(pool)

// Simulate sending a download request
request := data.Push("test", 0)
request := data.Push("test", "test_board")
err = messageTopic.Push(request)
if err != nil {
t.Fatal("Error pushing download request:", err)
Expand Down Expand Up @@ -80,11 +80,11 @@ func TestMessageTopic_ClientMessage(t *testing.T) {
logger := zerolog.New(os.Stdout).With().Timestamp().Logger()
api := broker.New(logger)

messageTopic := data.NewUpdateTopic(map[abstraction.BoardId]string{})
messageTopic := data.NewUpdateTopic()
messageTopic.SetAPI(api)

packet := protection.NewPacket(0, protection.OkSeverity)
payload := data.Push(packet, 0)
payload := data.Push(packet, "test_board")
payloadBytes, _ := json.Marshal(payload)
messageTopic.ClientMessage(websocket.ClientId{0}, &websocket.Message{
Topic: data.SubscribeName,
Expand Down
30 changes: 20 additions & 10 deletions backend/pkg/broker/topics/message/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,29 @@ import (

"github.com/HyperloopUPV-H8/h9-backend/pkg/abstraction"
"github.com/HyperloopUPV-H8/h9-backend/pkg/broker/topics"
"github.com/HyperloopUPV-H8/h9-backend/pkg/transport/packet/data"
"github.com/HyperloopUPV-H8/h9-backend/pkg/transport/packet/protection"
"github.com/HyperloopUPV-H8/h9-backend/pkg/websocket"
"github.com/google/uuid"
ws "github.com/gorilla/websocket"
)

var _ = data.Packet{}

const UpdateName abstraction.BrokerTopic = "message/update"
const SubscribeName abstraction.BrokerTopic = "message/update"

type Update struct {
subscribersMx *sync.Mutex
subscribers map[websocket.ClientId]struct{}
idToBoard map[abstraction.BoardId]string
pool *websocket.Pool
api abstraction.BrokerAPI
}

func NewUpdateTopic(idToBoard map[abstraction.BoardId]string) *Update {
func NewUpdateTopic() *Update {
return &Update{
subscribersMx: &sync.Mutex{},
subscribers: make(map[websocket.ClientId]struct{}),
idToBoard: idToBoard,
}
}

Expand All @@ -42,7 +43,7 @@ func (update *Update) Push(p abstraction.BrokerPush) error {
return topics.ErrUnexpectedPush{Push: p}
}

raw, err := json.Marshal(push.Data(push.boardId, update.idToBoard))
raw, err := json.Marshal(push.Data(push.boardName))
if err != nil {
return err
}
Expand Down Expand Up @@ -100,19 +101,19 @@ func (update *Update) SetAPI(api abstraction.BrokerAPI) {
}

type pushStruct struct {
data any
boardId abstraction.BoardId
data any
boardName string
}

func Push(data any, boardId abstraction.BoardId) *pushStruct {
return &pushStruct{data: data, boardId: boardId}
func Push(data any, boardName string) *pushStruct {
return &pushStruct{data: data, boardName: boardName}
}

func (push *pushStruct) Topic() abstraction.BrokerTopic {
return UpdateName
}

func (push *pushStruct) Data(boardID abstraction.BoardId, idToBoard map[abstraction.BoardId]string) wrapper {
func (push *pushStruct) Data(boardName string) wrapper {
switch data := push.data.(type) {
case *protection.Packet:
return wrapper{
Expand All @@ -124,12 +125,21 @@ func (push *pushStruct) Data(boardID abstraction.BoardId, idToBoard map[abstract
Kind: string(data.Data.Name()),
Data: data.Data,
},
Board: string(idToBoard[boardID]),
Board: boardName,
Name: string(data.Name),
Timestamp: data.Timestamp,
}
case *data.Packet:
return wrapper{
Kind: "info",
Payload: "Order Sent",
Board: boardName,
Name: string(data.Id()),
Timestamp: protection.NowTimestamp(),
}
}
return wrapper{}

}

type wrapper struct {
Expand Down
28 changes: 23 additions & 5 deletions backend/pkg/logger/data/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type Logger struct {
fileLock *sync.RWMutex
// saveFiles is a map that contains the file of each value
saveFiles map[data.ValueName]*file.CSV
// allowedVars contains the full names (board/valueName) to be logged
allowedVars map[string]struct{}
}

// Record is a struct that implements the abstraction.LoggerRecord interface
Expand All @@ -41,15 +43,25 @@ func (*Record) Name() abstraction.LoggerName { return Name }

func NewLogger() *Logger {
logger := &Logger{
saveFiles: make(map[data.ValueName]*file.CSV),
running: &atomic.Bool{},
fileLock: &sync.RWMutex{},
saveFiles: make(map[data.ValueName]*file.CSV),
running: &atomic.Bool{},
fileLock: &sync.RWMutex{},
allowedVars: nil, // no filter by default
}

logger.running.Store(false)
return logger
}

// SetAllowedVars allows updating the list of allowed variables at runtime
func (sublogger *Logger) SetAllowedVars(allowed []string) {
allowedMap := make(map[string]struct{}, len(allowed))
for _, v := range allowed {
allowedMap[v] = struct{}{}
}
sublogger.allowedVars = allowedMap
}

func (sublogger *Logger) Start() error {
if !sublogger.running.CompareAndSwap(false, true) {
fmt.Println("Logger already running")
Expand Down Expand Up @@ -85,7 +97,13 @@ func (sublogger *Logger) PushRecord(record abstraction.LoggerRecord) error {

writeErr := error(nil)
for valueName, value := range dataRecord.Packet.GetValues() {

// Filter: only log allowed variables
if sublogger.allowedVars != nil {
key := dataRecord.From + "/" + string(valueName)
if _, ok := sublogger.allowedVars[key]; !ok {
continue
}
}
var valueRepresentation string
switch value := value.(type) {
case numeric:
Expand All @@ -102,7 +120,7 @@ func (sublogger *Logger) PushRecord(record abstraction.LoggerRecord) error {
}

err = saveFile.Write([]string{
fmt.Sprint(dataRecord.Packet.Timestamp().UnixMilli()),
fmt.Sprint(dataRecord.Packet.Timestamp().Format(time.StampMicro)),
dataRecord.From,
dataRecord.To,
valueRepresentation,
Expand Down
2 changes: 1 addition & 1 deletion backend/pkg/vehicle/notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func (vehicle *Vehicle) handlePacketNotification(notification transport.PacketNo

case *protection.Packet:
boardId := vehicle.ipToBoardId[strings.Split(notification.From, ":")[0]]
err := vehicle.broker.Push(message_topic.Push(p, boardId))
err := vehicle.broker.Push(message_topic.Push(p, vehicle.idToBoardName[uint16(p.Id())]))
if err != nil {
vehicle.trace.Error().Stack().Err(err).Msg("broker push")
return errors.Join(fmt.Errorf("update protection to frontend (%s protection with id %d and kind %d from %s to %s)", p.Severity(), p.Id(), p.Kind, notification.From, notification.To), err)
Expand Down
9 changes: 7 additions & 2 deletions backend/pkg/vehicle/vehicle.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,18 @@ func (vehicle *Vehicle) UserPush(push abstraction.BrokerPush) error {
return err
}

err = vehicle.broker.Push(message_topic.Push(packet, vehicle.idToBoardName[uint16(packet.Id())]))
if err != nil {
fmt.Fprintf(os.Stderr, "error sending info packet to the frontend: %v\n", err)
return err
}

err = vehicle.logger.PushRecord(&order_logger.Record{
Packet: packet,
From: "backend",
To: vehicle.idToBoardName[uint16(packet.Id())],
Timestamp: packet.Timestamp(),
})

if err != nil && !errors.Is(err, logger.ErrLoggerNotRunning{}) {
fmt.Fprintln(os.Stderr, "Error pushing record to logger: ", err)
}
Expand Down Expand Up @@ -178,5 +183,5 @@ func (vehicle *Vehicle) notifyError(name string, err error) {
packet.Data = &protection.ErrorHandler{
Error: err.Error(),
}
vehicle.broker.Push(message_topic.Push(packet, 255))
vehicle.broker.Push(message_topic.Push(packet, "Error"))
}
1 change: 1 addition & 0 deletions common-front/lib/broker/BrokerStructure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type BrokerStructure = {
};
"message/update": { request: never; response: MessageAdapter };
"logger/enable": { request: boolean; response: boolean };
"logger/variables": { request: string[]; response: boolean };
"blcu/upload": {
request: BootloaderUploadRequest;
response: BootloaderUploadResponse;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//Implementa un filtro para que si un mensaje es igual
// a uno anterior, no se muestre.

//Existen dos tipos de mensajes:
//Boundaries: envían un nombre de variable, un valor límite y el valor actual.
// Si el valor actual es diferente del último enviado, debe mostrarse siempre.

//ErrorHandler & InfoWarning: estos mensajes son básicamente un string.
// Se deben filtrar si el mensaje es igual al último o si es igual dentro de un marco temporal
// (cómo implementar este filtro queda a tu criterio).

//debo:
//1ro: identificar el tipo de mensaje, si es BOUNDARY o ERRORHANDLER
//si es el 1ro => comparar el valor actual de este tipo con el ultimo valor de este tipo => diferente = se muestra SIEMPRE
//si es el 2do => comparar el string con el ultimo recibido: igual y dentro de un t<10s = no se muestra, else = mostrarlo

import { Message, Protection } from "../../../../models/Message";

export function filterMessages (messages: Message[]): Message[]{
const filtered: Message[] = []; //array de msg filtrados
const lastMessageName = new Map <string, Message>();
for (const msg of messages){
const last = lastMessageName.get(msg.name); //obtengo el ultimo msg
//2do caso
//comprobamos si el msg actual NO es boundaries => vemos si el msg es de alguno de estos tipos que contienen texto (ProtectionMessage)
if (msg.kind == "warning" || msg.kind == "fault" || msg.kind == "ok"){
if (!last || last.payload !== msg.payload){ //evalua si el payload (contenido) es igual al ultimo recibido
filtered.push(msg); //se añade al array
lastMessageName.set(msg.name, msg); //actualiza last con el nuevo valor
}
}else{
//1er caso => es boundary
if (!last || JSON.stringify((last.payload as unknown as Protection)) !== JSON.stringify((msg.payload as unknown as Protection).data)){ //como payload es del tipo boundary hay que tratarlo con Protection, antes le pongo 'unknown' xq si no lanza error sl hacer la conversion antes
filtered.push(msg); //se añade al array
lastMessageName.set(msg.name, msg); //actualiza con el ultimomensaje
}
}
}
return filtered;
}
3 changes: 2 additions & 1 deletion common-front/lib/models/PodData/Measurement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type Measurement =
type AbstractMeasurement = {
id: string;
name: string;
log?: boolean;
};

export type NumericMeasurement = AbstractMeasurement & {
Expand All @@ -23,7 +24,7 @@ export type NumericValue = {
last: number;
average: number;
showLatest: boolean;
};
}

export type BooleanMeasurement = AbstractMeasurement & {
type: 'bool';
Expand Down
Loading
Loading