diff --git a/.gitmodules b/.gitmodules index 0b66075b..bcaf5f3b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,4 +3,4 @@ url = https://github.com/HyperloopUPV-H8/ST-LIB [submodule "Core/Inc/Communications/JSON_ADE"] path = Core/Inc/Code_generation/JSON_ADE - url = https://github.com/HyperloopUPV-H8/JSON_ADE + url = https://github.com/HyperloopUPV-H8/adj diff --git a/CMakeLists.txt b/CMakeLists.txt index c1d122ca..04a60269 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ include(CTest) enable_testing() set(EXECUTABLE ${PROJECT_NAME}.elf) -set(BOARD_NAME "TEST" CACHE STRING "Board key from Core/Inc/Code_generation/JSON_ADE/boards.json") +set(BOARD_NAME "VCU" CACHE STRING "Board key from Core/Inc/Code_generation/JSON_ADE/boards.json" FORCE) if(BOARD_NAME STREQUAL "") message(FATAL_ERROR "BOARD_NAME cannot be empty") endif() diff --git a/Core/Inc/Code_generation/JSON_ADE b/Core/Inc/Code_generation/JSON_ADE index a25030fe..ee857f81 160000 --- a/Core/Inc/Code_generation/JSON_ADE +++ b/Core/Inc/Code_generation/JSON_ADE @@ -1 +1 @@ -Subproject commit a25030fe85f30b7133e4e449847968bdcd856833 +Subproject commit ee857f81e0aef674a19f8fc5db4a2d3c28a75a51 diff --git a/Core/Inc/Code_generation/Packet_generation/Packet_descriptions.py b/Core/Inc/Code_generation/Packet_generation/Packet_descriptions.py index 6399b6a8..2b429415 100644 --- a/Core/Inc/Code_generation/Packet_generation/Packet_descriptions.py +++ b/Core/Inc/Code_generation/Packet_generation/Packet_descriptions.py @@ -6,17 +6,28 @@ def __init__(self,name:str,board:dict,JSONpath:str): self.name = name self.id = board["board_id"] self.ip = board["board_ip"] + + # Load backend IP from general_info.json + backend_ip = "0.0.0.0" + try: + with open(JSONpath + "/general_info.json") as f: + general_info = json.load(f) + if "addresses" in general_info and "backend" in general_info["addresses"]: + backend_ip = general_info["addresses"]["backend"] + except Exception as e: + print(f"Warning: Could not load backend IP from general_info.json: {e}") + #Sockets: try: with open(JSONpath+"/boards/"+name+"/sockets.json") as s: socks = json.load(s) - self.sockets=self.SocketsDescription(socks,self.ip) + self.sockets = self.SocketsDescription(socks, self.ip, backend_ip) except Exception as e: raise Exception(f"Error in file {JSONpath}/boards/{name}/sockets.json: {e}") #Packets: self.sending_packets = [] - self.data_size =0 - self.order_size =0 + self.data_size = 0 + self.order_size = 0 self.measurement_lists = [] self.packets = {} for measurement in board["measurements"]: @@ -60,11 +71,11 @@ def fix_sendind_packets(sending_packets:list): period_type = item.get("period_type") socket = item.get("socket") name = item.get("name") - key = (period,period_type, socket) + key = (period, period_type, socket) lookup.setdefault(key, []).append(name) - for (period,period_type, socket), names in lookup.items(): - entry = {"period": period,"period_type":period_type, "socket": socket} + for (period, period_type, socket), names in lookup.items(): + entry = {"period": period, "period_type": period_type, "socket": socket} if len(names) == 1: entry["name"] = names[0] else: @@ -76,23 +87,30 @@ def fix_sendind_packets(sending_packets:list): class SocketsDescription: - def __init__(self,sockets:list,board_ip:str): - self.allSockets=[] + def __init__(self, sockets: list, board_ip: str, backend_ip: str): + self.allSockets = [] self.ServerSockets = [] self.Sockets = [] self.DatagramSockets = [] self.board_ip = board_ip + self.backend_ip = backend_ip for sock in sockets: name = sock["name"].replace(" ", "_").replace("-", "_") sock_type = sock["type"] - self.allSockets.append({"name": name,"type":sock_type}) + self.allSockets.append({"name": name, "type": sock_type}) if sock_type == "ServerSocket": - self.ServerSockets.append({"name": name,"type":sock_type,"board_ip":self.board_ip, "port": sock["port"]}) + self.ServerSockets.append({"name": name, "type": sock_type, "board_ip": self.board_ip, "port": sock["port"]}) elif sock_type == "Socket": - self.Sockets.append({"name": name,"type":sock_type,"board_ip":self.board_ip, "local_port": sock["local_port"], "remote_ip": sock["remote_ip"], "remote_port": sock["remote_port"]}) + remote_ip = sock["remote_ip"] + if remote_ip == "backend": + remote_ip = self.backend_ip + self.Sockets.append({"name": name, "type": sock_type, "board_ip": self.board_ip, "local_port": sock["local_port"], "remote_ip": remote_ip, "remote_port": sock["remote_port"]}) elif sock_type == "DatagramSocket": - self.DatagramSockets.append({"name": name,"type":sock_type,"board_ip":self.board_ip, "port": sock["port"],"remote_ip":sock["remote_ip"]}) + remote_ip = sock["remote_ip"] + if remote_ip == "backend": + remote_ip = self.backend_ip + self.DatagramSockets.append({"name": name, "type": sock_type, "board_ip": self.board_ip, "port": sock["port"], "remote_ip": remote_ip}) @@ -110,14 +128,11 @@ def __init__(self, packet:dict,measurements:list, filename:str="Unknown"): self.measurements.append(MeasurmentsDescription(measurements,variable, filename)) @staticmethod - def check_for_sending(packet:dict): + def check_for_sending(packet: dict): if "period" in packet and "period_type" in packet and "socket" in packet: name = packet["name"].replace(" ", "_").replace("-", "_") - return {"name": name,"period": packet["period"],"period_type":packet["period_type"],"socket": packet["socket"]} + return {"name": name, "period": packet["period"], "period_type": packet["period_type"], "socket": packet["socket"]} - elif "period_ms" in packet and "socket" in packet: - name = packet["name"].replace(" ", "_").replace("-", "_") - return {"name": name,"period": packet["period_ms"],"period_type":"ms","socket": packet["socket"]} else: return None class MeasurmentsDescription: @@ -166,4 +181,6 @@ def _unsigned_int_correction(type:str): type += "_t" elif type == "float32": type = "float" + elif type == "float64": + type = "double" return type diff --git a/Core/Inc/Code_generation/Packet_generation/Packet_generation.py b/Core/Inc/Code_generation/Packet_generation/Packet_generation.py index d852d367..0bca5338 100644 --- a/Core/Inc/Code_generation/Packet_generation/Packet_generation.py +++ b/Core/Inc/Code_generation/Packet_generation/Packet_generation.py @@ -38,8 +38,8 @@ def GenerateDataEnum(board:BoardDescription): return Enums - def GenerateDataPackets(board:BoardDescription): - Packets =[] + def GenerateDataPackets(board: BoardDescription): + Packets = [] totaldata = [] for packet in board.packets: for packet_instance in board.packets[packet]: @@ -47,8 +47,8 @@ def GenerateDataPackets(board:BoardDescription): tempdata = "" tempdata_but_pointer = "" for variable in packet_instance.variables: - tempdata +=(str(variable) +",") - tempdata_but_pointer +=("&"+str(variable) +",") + tempdata += (str(variable) + ",") + tempdata_but_pointer += ("&" + str(variable) + ",") if tempdata.endswith(","): tempdata = tempdata[:-1] if tempdata_but_pointer.endswith(","): @@ -61,7 +61,7 @@ def GenerateDataPackets(board:BoardDescription): "type": measurement.type }) - aux_packet = {"name": packet_instance.name, "data":tempdata_but_pointer.replace(" ", "_").replace("-", "_") , "id": packet_instance.id, "variables": packet_variables} + aux_packet = {"name": packet_instance.name, "data": tempdata_but_pointer.replace(" ", "_").replace("-", "_"), "id": packet_instance.id, "variables": packet_variables} Packets.append(aux_packet) for measurement in packet_instance.measurements: aux_data = {"type": measurement.type, "name": measurement.id.replace(" ", "_").replace("-", "_")} @@ -135,8 +135,8 @@ def Generate_DataPackets_hpp(board_input:str): #--------------OrderPackets.hpp generation---------------# -def Get_order_context(board:BoardDescription): - def GenerateOrderEnum(board:BoardDescription): +def Get_order_context(board: BoardDescription): + def GenerateOrderEnum(board: BoardDescription): Enums = [] for packet in board.packets: for packet_instance in board.packets[packet]: @@ -146,9 +146,8 @@ def GenerateOrderEnum(board:BoardDescription): Enums.append(measurement.enum) return Enums - - def GenerateOrderPackets(board:BoardDescription): - Packets =[] + def GenerateOrderPackets(board: BoardDescription): + Packets = [] totaldata = [] for packet in board.packets: for packet_instance in board.packets[packet]: @@ -156,8 +155,8 @@ def GenerateOrderPackets(board:BoardDescription): tempdata = "" tempdata_but_pointer = "" for variable in packet_instance.variables: - tempdata +=(str(variable) +",") - tempdata_but_pointer +=("&"+str(variable) +",") + tempdata += (str(variable) + ",") + tempdata_but_pointer += ("&" + str(variable) + ",") if tempdata.endswith(","): tempdata = tempdata[:-1] tempdata_but_pointer = tempdata_but_pointer[:-1] @@ -169,17 +168,16 @@ def GenerateOrderPackets(board:BoardDescription): "type": measurement.type }) - aux_packet = {"name": packet_instance.name, "data":tempdata_but_pointer , "id": packet_instance.id, "variables": packet_variables} + aux_packet = {"name": packet_instance.name, "data": tempdata_but_pointer, "id": packet_instance.id, "variables": packet_variables} Packets.append(aux_packet) for measurement in packet_instance.measurements: - aux_data = {"type": measurement.type, "name": measurement.id} + aux_data = {"type": measurement.type, "name": measurement.name} if not any(x["name"] == aux_data["name"] for x in totaldata): totaldata.append(aux_data) - return Packets,totaldata - + return Packets, totaldata - packets,data = GenerateOrderPackets(board) + packets, data = GenerateOrderPackets(board) context = { "board": board.name, "enums": GenerateOrderEnum(board), @@ -203,6 +201,5 @@ def Generate_OrderPackets_hpp(board_input:str): template = env.get_template("OrderTemplate.hpp") context = Get_order_context(board_instance) - - with open(order_packets_path,"w") as Output: + with open(order_packets_path, "w") as Output: Output.write(template.render(context)) diff --git a/Core/Src/Examples/LinearSensorCharacterization.cpp b/Core/Src/Examples/LinearSensorCharacterization.cpp index df810a81..eb312383 100644 --- a/Core/Src/Examples/LinearSensorCharacterization.cpp +++ b/Core/Src/Examples/LinearSensorCharacterization.cpp @@ -1,13 +1,28 @@ #ifdef EXAMPLE_LINEAR_SENSOR_CHARACTERIZATION +#include "Communications/Packets/DataPackets.hpp" +#include "Communications/Packets/OrderPackets.hpp" #include "ST-LIB.hpp" #include "main.h" using namespace ST_LIB; -constexpr auto led = ST_LIB::DigitalOutputDomain::DigitalOutput(ST_LIB::PB0); +double slope{1.0}; +double offset{0.0}; + +double value{0.0}; +double sensor_value{0.0}; + +double real_value{0.0}; + +constinit float raw_value{0.0f}; +constexpr auto sensor = ADCDomain::ADC( + ST_LIB::PA0, + raw_value, + ADCDomain::Resolution::BITS_16, + ADCDomain::SampleTime::CYCLES_8_5 +); -#ifdef STLIB_ETH #if defined(USE_PHY_LAN8742) constexpr auto eth = EthernetDomain::Ethernet( EthernetDomain::PINSET_H10, @@ -32,26 +47,76 @@ constexpr auto eth = EthernetDomain::Ethernet( #else #error "No PHY selected for Ethernet pinset selection" #endif -using ExampleEthernetBoard = ST_LIB::Board; -#else -using ExampleEthernetBoard = ST_LIB::Board; -#endif +using ExampleEthernetBoard = ST_LIB::Board; + +extern "C" void Error_Handler(void) { + ErrorHandler("HAL error handler triggered"); + while (1) { + } +} + +void characterize(float raw, double read) { + // Incremental OLS accumulators for y = slope * x + offset. + static uint64_t sample_count{0}; + static double sum_x{0.0}; + static double sum_y{0.0}; + static double sum_xx{0.0}; + static double sum_xy{0.0}; + + const double x = static_cast(raw); + const double y = read; + + ++sample_count; + sum_x += x; + sum_y += y; + sum_xx += x * x; + sum_xy += x * y; + + if (sample_count < 2) { + offset = y - (slope * x); + return; + } + + const double n = static_cast(sample_count); + const double denominator = (n * sum_xx) - (sum_x * sum_x); + if (denominator == 0.0) { + return; + } + + slope = ((n * sum_xy) - (sum_x * sum_y)) / denominator; + offset = (sum_y - (slope * sum_x)) / n; +} int main(void) { Hard_fault_check(); - ExampleEthernetBoard::init(); -#ifdef STLIB_ETH + + Scheduler::start(); + // Comms + OrderPackets::characterize_init(real_value); + DataPackets::characterization_init(slope, offset); + DataPackets::Value_init(sensor_value, value); + DataPackets::start(); + + OrderPackets::start(); + + // Instances auto& eth_instance = ExampleEthernetBoard::instance_of(); -#endif - auto& led_instance = ExampleEthernetBoard::instance_of(); + auto& sensor_instance = ExampleEthernetBoard::instance_of(); - led_instance.turn_on(); while (1) { -#ifdef STLIB_ETH eth_instance.update(); -#endif + Scheduler::update(); + + sensor_instance.read(); + sensor_value = static_cast(raw_value); + value = slope * sensor_value + offset; + + if (OrderPackets::characterize_flag) { + OrderPackets::characterize_flag = false; + characterize(raw_value, real_value); + DataPackets::packets_socket->send_packet(*DataPackets::characterization_packet); + } } } - -#endif // EXAMPLE_LINEAR_SENSOR_CHARACTERIZATION +#endif diff --git a/Core/Src/Runes/generated_metadata.cpp b/Core/Src/Runes/generated_metadata.cpp index 6350bc43..ca034a4a 100644 --- a/Core/Src/Runes/generated_metadata.cpp +++ b/Core/Src/Runes/generated_metadata.cpp @@ -5,11 +5,11 @@ extern "C" { const char DESCRIPTION[255] __attribute__((section(".metadata_pool"))) = "****************" // placeholder for beggining - "20260206T223828" // DateTime using ISO-8601 format + "20260218T203535" // DateTime using ISO-8601 format " " // alignment - "dcf817b3" // STLIB commit + "019403b6" // STLIB commit "--------" // ADJ commit - "4b3d0ec4" // Board commit + "9c87b508" // Board commit // the '=' is used for unparsing ; } diff --git a/state_machine.json b/state_machine.json deleted file mode 100644 index 3aabd215..00000000 --- a/state_machine.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "name" : "Example", - - "states" : [ - "name_1", - { - "name" : "Nested", - "nested_to" : "name_1", - "sub-states":[ - "nested_name_1", - "nested_name_2" - ] - }, - "name_2" - ], - - "transitions" : [ - { - "from_state" : "name_1", - "to_state" : "name_2", - "transition_name": "from_1_to_2" - }, - { - "from_state" : "name_1", - "to_state" : "name_2", - "transition_name": "from_1_to_2", - "description" : "Transitioning from 1 to 2" - }, - { - "from_state" : "name_1", - "to_state" : { - "name" : "Nested", - "sub-state" : "nested_name_1" - }, - "transition_name": "from_1_to_nested_1" - } - ], - - "actions" : { - "enter" : [ - { - "state" : "name_1", - "state_actions" : [ - "enter_action_1", - "enter_action_2" - ] - }, - { - "state" : "name_2", - "state_actions" : [ - { - "name" : "enter_action_3", - "description" : "Description of enter_action_3" - }, - "enter_action_4" - ] - } - ], - - "cyclic" : { - "low_precision" : [ - { - "states" : [ - "name_1", - "name_2" - ], - "state_actions" : [ - { - "action_name" : "low_precision_action", - "action_period" : "30ms" - } - ] - } - ], - "mid_precision" : [ - { - "states" : [ - "name_1", - { - "name" : "Nested", - "sub-state" : "nested_name_1" - } - ], - "state_actions" : [ - { - "action_name" : "mid_precision_action_to_nested_state", - "action_period" : "60ms" - } - ] - } - ], - "high_precision" : [ - { - "states" : [ - "name_1", - "name_2" - ], - "state_actions" : [ - { - "action_name" : "high_precision_action_with_description", - "action_period" : "90ms", - "description" : "Cyclic action example with description" - } - ] - } - ] - }, - - "exit" : [ - { - "state" : { - "name" : "Nested", - "sub-state" : "nested_name_2" - }, - "state_actions" : [ - "exit_action_1", - "exit_action_2" - ] - } - ] - } -}