diff --git a/fsfwgen/events/event_parser.py b/fsfwgen/events/event_parser.py index 74b35cf..47751d7 100644 --- a/fsfwgen/events/event_parser.py +++ b/fsfwgen/events/event_parser.py @@ -166,9 +166,7 @@ class EventParser(FileParser): f"Name: {self.mib_table.get(full_id)[0]}| " f"Description: {self.mib_table.get(full_id)[2]}" ) - self.mib_table.update( - {full_id: (name, severity, description, file_name.as_posix())} - ) + self.mib_table.update({full_id: (name, severity, description, file_name)}) self.count = self.count + 1 @staticmethod @@ -277,7 +275,7 @@ class EventParser(FileParser): def export_to_file( - filename: str, event_list: List[Tuple[str, List]], file_separator: str + filename: Path, event_list: List[Tuple[str, List]], file_separator: str ): file = open(filename, "w") fsep = file_separator @@ -288,59 +286,57 @@ def export_to_file( file.write( f"{event_id}{fsep}{event_id_as_hex}{fsep}{event_value[EVENT_ENTRY_NAME_IDX]}{fsep}" f"{event_value[EVENT_ENTRY_SEVERITY_IDX]}{fsep}{event_value[EVENT_ENTRY_INFO_IDX]}" - f"{fsep}{event_value[EVENT_SOURCE_FILE_IDX]}\n" + f"{fsep}{event_value[EVENT_SOURCE_FILE_IDX].as_posix()}\n" ) file.close() - return def write_translation_source_file( - event_list: list, date_string: str, filename: str = "translateEvents.cpp" + event_list: list, date_string: str, filename: Path = "translateEvents.cpp" ): - outputfile = open(filename, "w") - definitions = "" - # Look up table to avoid duplicate events - lut = dict() - function = ( - "const char *translateEvents(Event event) {\n switch ((event & 0xFFFF)) {\n" - ) - for entry in event_list: - event_id = entry[0] - event_value = entry[1] - if event_value[EVENT_ENTRY_NAME_IDX] not in lut: - definitions += ( - f"const char *{event_value[EVENT_ENTRY_NAME_IDX]}_STRING " - f'= "{event_value[EVENT_ENTRY_NAME_IDX]}";\n' - ) - function += ( - f" case ({event_id}):\n " - f"return {event_value[EVENT_ENTRY_NAME_IDX]}_STRING;\n" - ) - lut.update({event_value[EVENT_ENTRY_NAME_IDX]: event_value}) - function += ' default:\n return "UNKNOWN_EVENT";\n' - outputfile.write( - f"/**\n * @brief Auto-generated event translation file. " - f"Contains {len(event_list)} translations.\n" - f" * @details\n" - f" * Generated on: {date_string}\n */\n" - ) - outputfile.write('#include "translateEvents.h"\n\n') - outputfile.write(definitions + "\n" + function + " }\n return 0;\n}\n") - outputfile.close() + with open(filename, "w") as out: + definitions = "" + # Look up table to avoid duplicate events + lut = dict() + function = ( + "const char *translateEvents(Event event) {\n switch ((event & 0xFFFF)) {\n" + ) + for entry in event_list: + event_id = entry[0] + event_value = entry[1] + if event_value[EVENT_ENTRY_NAME_IDX] not in lut: + definitions += ( + f"const char *{event_value[EVENT_ENTRY_NAME_IDX]}_STRING " + f'= "{event_value[EVENT_ENTRY_NAME_IDX]}";\n' + ) + function += ( + f" case ({event_id}):\n " + f"return {event_value[EVENT_ENTRY_NAME_IDX]}_STRING;\n" + ) + lut.update({event_value[EVENT_ENTRY_NAME_IDX]: event_value}) + function += ' default:\n return "UNKNOWN_EVENT";\n' + out.write( + f"/**\n * @brief Auto-generated event translation file. " + f"Contains {len(event_list)} translations.\n" + f" * @details\n" + f" * Generated on: {date_string}\n */\n" + ) + out.write('#include "translateEvents.h"\n\n') + out.write(definitions + "\n" + function + " }\n return 0;\n}\n") -def write_translation_header_file(filename: str = "translateEvents.h"): - file = open(filename, "w") - file.write( - f"#ifndef FSFWCONFIG_EVENTS_TRANSLATEEVENTS_H_\n" - f"#define FSFWCONFIG_EVENTS_TRANSLATEEVENTS_H_\n\n" - f"{FSFW_EVENT_HEADER_INCLUDE}\n\n" - f"const char *translateEvents(Event event);\n\n" - f"#endif /* FSFWCONFIG_EVENTS_TRANSLATEEVENTS_H_ */\n" - ) +def write_translation_header_file(filename: Path = "translateEvents.h"): + with open(filename, "w") as out: + out.write( + f"#ifndef FSFWCONFIG_EVENTS_TRANSLATEEVENTS_H_\n" + f"#define FSFWCONFIG_EVENTS_TRANSLATEEVENTS_H_\n\n" + f"{FSFW_EVENT_HEADER_INCLUDE}\n\n" + f"const char *translateEvents(Event event);\n\n" + f"#endif /* FSFWCONFIG_EVENTS_TRANSLATEEVENTS_H_ */\n" + ) -def handle_csv_export(file_name: str, event_list: list, file_separator: str): +def handle_csv_export(file_name: Path, event_list: list, file_separator: str): """ Generates the CSV in the same directory as the .py file and copes the CSV to another directory if specified. @@ -353,9 +349,9 @@ def handle_csv_export(file_name: str, event_list: list, file_separator: str): def handle_cpp_export( event_list: list, date_string: str, - file_name: str = "translateEvents.cpp", + file_name: Path = "translateEvents.cpp", generate_header: bool = True, - header_file_name: str = "translateEvents.h", + header_file_name: Path = "translateEvents.h", ): write_translation_source_file( event_list=event_list, date_string=date_string, filename=file_name diff --git a/fsfwgen/objects/objects.py b/fsfwgen/objects/objects.py index 441fd24..faddb78 100644 --- a/fsfwgen/objects/objects.py +++ b/fsfwgen/objects/objects.py @@ -1,4 +1,6 @@ import re +from pathlib import Path +from typing import List from fsfwgen.parserbase.parser import FileParser from fsfwgen.core import get_console_logger @@ -9,10 +11,10 @@ LOGGER = get_console_logger() class ObjectDefinitionParser(FileParser): - def __init__(self, file_list: list): + def __init__(self, file_list: List[Path]): super().__init__(file_list) - def _handle_file_parsing(self, file_name: str, *args, **kwargs): + def _handle_file_parsing(self, file_name: Path, *args, **kwargs): file = open(file_name, "r", encoding="utf-8") for line in file.readlines(): match = re.search(r"([\w]*)[\s]*=[\s]*(0[xX][0-9a-fA-F]+)", line) @@ -21,7 +23,7 @@ class ObjectDefinitionParser(FileParser): def _handle_file_parsing_moving_window( self, - file_name: str, + file_name: Path, current_line: int, moving_window_size: int, moving_window: list, diff --git a/fsfwgen/returnvalues/returnvalues_parser.py b/fsfwgen/returnvalues/returnvalues_parser.py index 3ebbf09..9ce4570 100644 --- a/fsfwgen/returnvalues/returnvalues_parser.py +++ b/fsfwgen/returnvalues/returnvalues_parser.py @@ -1,7 +1,8 @@ import os.path import re import sys -from typing import List, Tuple, Optional +from pathlib import Path +from typing import List, Tuple, Optional, Dict from fsfwgen.parserbase.parser import FileParser, VerbosityLevels from fsfwgen.utility.printer import PrettyPrinter @@ -160,6 +161,31 @@ class InterfaceParser(FileParser): self.mib_table.update(dict_to_build) +class RetvalEntry: + def __init__( + self, + name: str, + description: str, + unique_id: int, + file_name: Path, + subsystem_name: str, + ): + self.name = name + self.description = description + self.unique_id = unique_id + self.file_name = file_name + self.subsystem_name = subsystem_name + + def __repr__(self): + return ( + f"RetvalEntry(name={self.name!r}, description={self.description!r}, unique_id={self.unique_id!r}, " + f"file_name={self.file_name!r}, subsystem_name={self.subsystem_name!r})" + ) + + +RetvalDictT = Dict[int, RetvalEntry] + + class ReturnValueParser(FileParser): """ Generic return value parser. @@ -173,32 +199,32 @@ class ReturnValueParser(FileParser): self.count = 0 # Stores last three lines self.last_lines = ["", "", ""] - self.obsw_root_path: Optional[str] = None + self.obsw_root_path: Optional[Path] = None self.current_interface_id_entries = {"Name": "", "ID": 0, "FullName": ""} self.return_value_dict.update( { - 0: ( - "OK", - "System-wide code for ok.", - "RETURN_OK", - "HasReturnvaluesIF.h", - "HasReturnvaluesIF", + 0: RetvalEntry( + name="OK", + description="System-wide code for ok.", + unique_id=0, + file_name=Path("fsfw/returnvalues/HasReturnvaluesIF.h"), + subsystem_name="HasReturnvaluesIF", ) } ) self.return_value_dict.update( { - 1: ( - "Failed", - "Unspecified system-wide code for failed.", - "RETURN_FAILED", - "HasReturnvaluesIF.h", - "HasReturnvaluesIF", + 1: RetvalEntry( + name="Failed", + description="Unspecified system-wide code for failed.", + unique_id=1, + file_name=Path("fsfw/returnvalues/HasReturnvaluesIF.h"), + subsystem_name="HasReturnvaluesIF", ) } ) - def _handle_file_parsing(self, file_name: str, *args, **kwargs): + def _handle_file_parsing(self, file_name: Path, *args, **kwargs): """Former way to parse returnvalues. Not recommended anymore. :param file_name: :param args: @@ -215,7 +241,7 @@ class ReturnValueParser(FileParser): def _handle_file_parsing_moving_window( self, - file_name: str, + file_name: Path, current_line: int, moving_window_size: int, moving_window: list, @@ -263,9 +289,11 @@ class ReturnValueParser(FileParser): full_returnvalue_string, ) if returnvalue_match: - number_match = returnvalue_match.group(2) + number_match = get_number_from_dec_or_hex_str( + returnvalue_match.group(2) + ) else: - number_match = returnvalue_match.group(3) + number_match = get_number_from_dec_or_hex_str(returnvalue_match.group(3)) if returnvalue_match: description = self.__search_for_descrip_string(moving_window=moving_window) if number_match == INVALID_IF_ID: @@ -315,12 +343,12 @@ class ReturnValueParser(FileParser): name_match=returnvalue_match.group(1), file_name=file_name, description="", - number_match=returnvalue_match.group(2), + number_match=get_number_from_dec_or_hex_str(returnvalue_match.group(2)), ) self.last_lines[1] = self.last_lines[0] self.last_lines[0] = newline - def __handle_interfaceid_match(self, interface_id_match, file_name: str) -> bool: + def __handle_interfaceid_match(self, interface_id_match, file_name: Path) -> bool: """Handle a match of an interface ID definition in the code. Returns whether the interface ID was found successfully in the IF ID header files """ @@ -338,7 +366,7 @@ class ReturnValueParser(FileParser): return False self.current_interface_id_entries["Name"] = self.interfaces[ interface_id_match.group(1) - ][1] + ][1].lstrip() self.current_interface_id_entries["FullName"] = interface_id_match.group(1) if self.get_verbosity() == VerbosityLevels.DEBUG: current_id = self.current_interface_id_entries["ID"] @@ -346,7 +374,7 @@ class ReturnValueParser(FileParser): return True def __handle_returnvalue_match( - self, name_match: str, number_match: str, file_name: str, description: str + self, name_match: str, number_match: int, file_name: Path, description: str ): string_to_add = self.build_checked_string( self.current_interface_id_entries["Name"], @@ -354,23 +382,21 @@ class ReturnValueParser(FileParser): MAX_STRING_LEN, PRINT_TRUNCATED_ENTRIES, ) - full_id = ( - self.current_interface_id_entries["ID"] << 8 - ) + return_number_from_string(number_match) + full_id = (self.current_interface_id_entries["ID"] << 8) | number_match if full_id in self.return_value_dict: # print('Duplicate returncode ' + hex(full_id) + ' from ' + file_name + # ' was already in ' + self.return_value_dict[full_id][3]) pass if self.obsw_root_path is not None: - file_name = os.path.relpath(file_name, self.obsw_root_path) - dict_tuple = ( - string_to_add, - description, - number_match, - file_name, - self.current_interface_id_entries["FullName"], + file_name = file_name.relative_to(self.obsw_root_path) + mib_entry = RetvalEntry( + name=string_to_add, + description=description, + unique_id=number_match, + file_name=file_name, + subsystem_name=self.current_interface_id_entries["FullName"], ) - self.return_value_dict.update({full_id: dict_tuple}) + self.return_value_dict.update({full_id: mib_entry}) self.count = self.count + 1 def _post_parsing_operation(self): @@ -379,22 +405,12 @@ class ReturnValueParser(FileParser): self.mib_table = self.return_value_dict @staticmethod - def export_to_file(filename: str, list_of_entries: dict, file_separator: str): + def export_to_file(filename: str, list_of_entries: RetvalDictT, file_sep: str): file = open(filename, "w") for entry in list_of_entries.items(): file.write( - hex(entry[0]) - + file_separator - + entry[1][0] - + file_separator - + entry[1][1] - + file_separator - + entry[1][2] - + file_separator - + entry[1][3] - + file_separator - + entry[1][4] - + "\n" + f"{entry[0]:#06x}{file_sep}{entry[1].name}{file_sep}{entry[1].description}{file_sep}" + f"{entry[1].unique_id}{file_sep}{entry[1].subsystem_name}{file_sep}{entry[1].file_name.as_posix()}\n" ) file.close() @@ -434,7 +450,7 @@ class ReturnValueParser(FileParser): return description -def return_number_from_string(a_string): +def get_number_from_dec_or_hex_str(a_string): if a_string.startswith("0x"): return int(a_string, 16) if a_string.isdigit(): diff --git a/fsfwgen/utility/file_management.py b/fsfwgen/utility/file_management.py index 9efe981..a24b293 100644 --- a/fsfwgen/utility/file_management.py +++ b/fsfwgen/utility/file_management.py @@ -1,12 +1,14 @@ # -*- coding: utf-8 -*- import shutil import os +from pathlib import Path + from fsfwgen.core import get_console_logger LOGGER = get_console_logger() -def copy_file(filename: str, destination: str = "", delete_existing_file: bool = False): +def copy_file(filename: Path, destination: Path = "", delete_existing_file: bool = False): if not os.path.exists(filename): LOGGER.warning(f"File {filename} does not exist") return @@ -24,7 +26,7 @@ def copy_file(filename: str, destination: str = "", delete_existing_file: bool = LOGGER.exception("Source and destination are the same!") -def move_file(file_name: str, destination: str = ""): +def move_file(file_name: Path, destination: Path = ""): if not os.path.exists(file_name): print(f"move_file: File {file_name} does not exist") return