added generator files
This commit is contained in:
parent
cda061255a
commit
9229c4d98b
18
generators/definitions.py
Normal file
18
generators/definitions.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import enum
|
||||||
|
|
||||||
|
DATABASE_NAME = "fsfw_mod.db"
|
||||||
|
|
||||||
|
|
||||||
|
class BspSelect(enum.Enum):
|
||||||
|
BSP_HOSTED = enum.auto()
|
||||||
|
BSP_LINUX = enum.auto()
|
||||||
|
BSP_STM32_FREERTOS = enum.auto()
|
||||||
|
BSP_STM32_RTEMS = enum.auto()
|
||||||
|
|
||||||
|
|
||||||
|
BspFolderDict = {
|
||||||
|
BspSelect.BSP_HOSTED.value: "bsp_hosted",
|
||||||
|
BspSelect.BSP_LINUX.value: "bsp_linux",
|
||||||
|
BspSelect.BSP_STM32_FREERTOS.value: "bsp_stm32_freertos",
|
||||||
|
BspSelect.BSP_STM32_RTEMS.value: "bsp_stm32_rtems",
|
||||||
|
}
|
0
generators/devicecommands/__init__.py
Normal file
0
generators/devicecommands/__init__.py
Normal file
385
generators/devicecommands/device_command_parser.py
Normal file
385
generators/devicecommands/device_command_parser.py
Normal file
@ -0,0 +1,385 @@
|
|||||||
|
#!/usr/bin/python3.7
|
||||||
|
"""
|
||||||
|
@file device_command_parser.py
|
||||||
|
@brief Parses the device commands which are used for the PUS Service 8 as the primary means
|
||||||
|
of satellite commanding.
|
||||||
|
@details Used by the MIB Exporter, inherits generic File Parser.
|
||||||
|
Also has information parser which parses the possible device handler command values
|
||||||
|
from the actual device handlers.
|
||||||
|
@author R. Mueller
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
from fsfwgen.parserbase.file_list_parser import FileListParser
|
||||||
|
from fsfwgen.parserbase.parser import FileParser
|
||||||
|
from fsfwgen.utility.csv_writer import CsvWriter
|
||||||
|
from fsfwgen.utility.printer import Printer
|
||||||
|
|
||||||
|
|
||||||
|
DH_COMMAND_PACKET_DEFINITION_DESTINATION = "../../mission/devices/devicepackets/"
|
||||||
|
DH_DEFINITION_DESTINATION = "../../mission/devices/"
|
||||||
|
DH_COMMANDS_CSV_NAME = "mib_device_commands.csv"
|
||||||
|
DH_COMMAND_HEADER_COLUMNS = [
|
||||||
|
"Device Handler", "Command Name", "Action ID", "Command Field Name", "Command Field Position",
|
||||||
|
"Command Field Type", "Command Field Option Name", "Command Field Option Value", "Comment"]
|
||||||
|
|
||||||
|
SQL_DELETE_CMDTABLE_CMD = """
|
||||||
|
DROP TABLE IF EXISTS DeviceHandlerCommand;
|
||||||
|
"""
|
||||||
|
|
||||||
|
SQL_CREATE_CMDTABLE_CMD = """
|
||||||
|
CREATE TABLE IF NOT EXISTS DeviceHandlerCommand(
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
deviceHandler TEXT,
|
||||||
|
commandName TEXT,
|
||||||
|
actionID INTEGER,
|
||||||
|
cmdFieldName TEXT,
|
||||||
|
cmdFieldPos INTEGER,
|
||||||
|
cmdFieldType TEXT,
|
||||||
|
cmdFieldOptName TEXT,
|
||||||
|
cmdFieldOptVal INTEGER,
|
||||||
|
comment COMMENT
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
SQL_INSERT_INTO_CMDTABLE_CMD = """
|
||||||
|
INSERT INTO DeviceHandlerCommand(deviceHandler,commandName,actionID,cmdFieldName,cmdFieldPos,
|
||||||
|
cmdFieldType,cmdFieldOptName,cmdFieldOptVal,comment)
|
||||||
|
VALUES(?,?,?,?,?,?,?,?,?)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceCommandColumns(Enum):
|
||||||
|
"""
|
||||||
|
Specifies order of MIB columns
|
||||||
|
"""
|
||||||
|
DH_NAME = 0
|
||||||
|
NAME = 1
|
||||||
|
ACTION_ID = 2
|
||||||
|
COMMAND_FIELD_NAME = 3
|
||||||
|
COMMAND_INDEX = 4
|
||||||
|
TYPE = 5
|
||||||
|
COMMAND_FIELD_OPTION_NAME = 6
|
||||||
|
COMMAND_FIELD_OPTION_VALUE = 7
|
||||||
|
COMMAND_FIELD_COMMENT = 8
|
||||||
|
|
||||||
|
|
||||||
|
Clmns = DeviceCommandColumns
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
The main routine is run if the device command parser is run separately.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
info_header_file_parser = FileListParser(DH_DEFINITION_DESTINATION)
|
||||||
|
info_header_file_list = info_header_file_parser.\
|
||||||
|
parse_header_files(False, "Parsing device handler informations:")
|
||||||
|
dh_information_parser = DeviceHandlerInformationParser(info_header_file_list)
|
||||||
|
dh_information_table = dh_information_parser.parse_files()
|
||||||
|
Printer.print_content(dh_information_table, "Priting device handler command information table: ")
|
||||||
|
|
||||||
|
header_file_parser = FileListParser(DH_COMMAND_PACKET_DEFINITION_DESTINATION)
|
||||||
|
header_file_list = \
|
||||||
|
header_file_parser.parse_header_files(False, "Parsing device handler command files:")
|
||||||
|
packet_subservice_parser = DeviceHandlerCommandParser(header_file_list, dh_information_table)
|
||||||
|
dh_command_table = packet_subservice_parser.parse_files()
|
||||||
|
Printer.print_content(dh_command_table, "Printing device handler command table:")
|
||||||
|
dh_command_writer = CsvWriter(DH_COMMANDS_CSV_NAME, dh_command_table, DH_COMMAND_HEADER_COLUMNS)
|
||||||
|
dh_command_writer.write_to_csv()
|
||||||
|
dh_command_writer.copy_csv()
|
||||||
|
dh_command_writer.move_csv("..")
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
class DeviceHandlerInformationParser(FileParser):
|
||||||
|
"""
|
||||||
|
This helper class parses device handler informations based on the device handler
|
||||||
|
header files. These can be used to map commands to the device handler packets later.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, fileList):
|
||||||
|
super().__init__(fileList)
|
||||||
|
self.command_dict = dict()
|
||||||
|
self.command_enum_dict = dict()
|
||||||
|
self.command_enum_name = ""
|
||||||
|
self.command_value_name_list = []
|
||||||
|
self.command_value_list = []
|
||||||
|
self.command_comment_list = []
|
||||||
|
|
||||||
|
# this table includes the current new table entry, which will be updated
|
||||||
|
# for target parameter
|
||||||
|
self.command_scanning_pending = False
|
||||||
|
|
||||||
|
# This is called for every file. Fill out info table in this routine
|
||||||
|
def _handle_file_parsing(self, file_name, *args):
|
||||||
|
self_print_parsing_info = False
|
||||||
|
if len(args) == 1 and isinstance(args[0], bool):
|
||||||
|
self_print_parsing_info = args[0]
|
||||||
|
|
||||||
|
# Read device name from file name
|
||||||
|
handler_match = re.search(r'([\w]*).h', file_name)
|
||||||
|
if not handler_match:
|
||||||
|
print("Device Command Parser: Configuration error, no handler name match !")
|
||||||
|
handler_name = handler_match.group(1)
|
||||||
|
file = open(file_name, "r")
|
||||||
|
if self_print_parsing_info:
|
||||||
|
print("Parsing " + file_name + " ...")
|
||||||
|
# Scans each line for possible device handler command enums
|
||||||
|
for line in file.readlines():
|
||||||
|
self.__handle_line_reading(line)
|
||||||
|
handler_tuple = (self.command_dict, self.command_enum_dict)
|
||||||
|
handler_dict = dict()
|
||||||
|
handler_dict.update({handler_name: handler_tuple})
|
||||||
|
self.mib_table.update(handler_dict)
|
||||||
|
|
||||||
|
self.command_dict = dict()
|
||||||
|
self.command_enum_dict = dict()
|
||||||
|
|
||||||
|
def __handle_line_reading(self, line):
|
||||||
|
"""
|
||||||
|
Searches for enum command definitions or device command definitions.
|
||||||
|
:param line:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# Case insensitive matching of device command enums
|
||||||
|
enum_match = re.search(r'[\s]*enum[\s]*([\w]*)[\s]*{[\s][/!<>]*[\s]*'
|
||||||
|
r'\[EXPORT[\w]*\][\s]*:[\s]*\[ENUM\]([^\n]*)', line, re.IGNORECASE)
|
||||||
|
if enum_match:
|
||||||
|
self.command_enum_name = enum_match.group(1)
|
||||||
|
self.command_scanning_pending = True
|
||||||
|
else:
|
||||||
|
self.__handle_command_definition_scanning(line)
|
||||||
|
|
||||||
|
# while command scanning is pending, each line in enum needs to be parsed
|
||||||
|
if self.command_scanning_pending:
|
||||||
|
self.__handle_command_enum_scanning(line)
|
||||||
|
|
||||||
|
def __handle_command_definition_scanning(self, line):
|
||||||
|
command_match = \
|
||||||
|
re.search(r'[\s]*static[\s]*const[\s]*DeviceCommandId_t[\s]*([\w]*)[\s]*=[\s]*'
|
||||||
|
r'([\w]*)[\s]*;[\s]*[/!<>]*[\s]*\[EXPORT\][\s]*:[\s]*\[COMMAND\]', line)
|
||||||
|
if command_match:
|
||||||
|
command_name = command_match.group(1)
|
||||||
|
command_id = command_match.group(2)
|
||||||
|
self.command_dict.update({command_name: command_id})
|
||||||
|
|
||||||
|
def __handle_command_enum_scanning(self, line):
|
||||||
|
self.__scan_command_entries(line)
|
||||||
|
if not self.command_scanning_pending:
|
||||||
|
# scanning enum finished
|
||||||
|
# stores current command into command dictionary with command name as unique key
|
||||||
|
command_tuple = self.command_value_name_list, self.command_value_list, \
|
||||||
|
self.command_comment_list
|
||||||
|
self.command_enum_dict.update({self.command_enum_name: command_tuple})
|
||||||
|
self.command_enum_name = ""
|
||||||
|
self.command_value_name_list = []
|
||||||
|
self.command_value_list = []
|
||||||
|
self.command_comment_list = []
|
||||||
|
|
||||||
|
def __scan_command_entries(self, line):
|
||||||
|
command_match = \
|
||||||
|
re.search(r'[\s]*([\w]*)[\s]*=[\s]*([0-9]{1,3})[^/][\s]*[/!<>]*[\s]*([^\n]*)', line)
|
||||||
|
if command_match:
|
||||||
|
self.command_value_name_list.append(command_match.group(1))
|
||||||
|
self.command_value_list.append(command_match.group(2))
|
||||||
|
self.command_comment_list.append(command_match.group(3))
|
||||||
|
elif re.search(r'}[\s]*;', line):
|
||||||
|
self.command_scanning_pending = False
|
||||||
|
|
||||||
|
def _post_parsing_operation(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PendingScanType(Enum):
|
||||||
|
"""
|
||||||
|
Specifies which scan type is performed in the device command parser.
|
||||||
|
"""
|
||||||
|
NO_SCANNING = 0
|
||||||
|
STRUCT_SCAN = 1
|
||||||
|
CLASS_SCAN = 2
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=too-many-instance-attributes
|
||||||
|
class DeviceHandlerCommandParser(FileParser):
|
||||||
|
"""
|
||||||
|
This is the actual device handler command parser. It will parse the device handler
|
||||||
|
packet definitions. A device handler info table must be passed which can be acquired
|
||||||
|
by running the DH information parser.
|
||||||
|
"""
|
||||||
|
def __init__(self, file_list, dh_information_table):
|
||||||
|
super().__init__(file_list)
|
||||||
|
# this table includes the current new table entry,
|
||||||
|
# which will be updated for target parameter
|
||||||
|
self.dict_entry_list = list(range(Clmns.__len__()))
|
||||||
|
|
||||||
|
# This table containts information about respective device handler command options
|
||||||
|
self.dh_information_table = dh_information_table
|
||||||
|
self.enum_dict = dict()
|
||||||
|
|
||||||
|
self.current_enum_name = ""
|
||||||
|
self.comment = ""
|
||||||
|
self.command_comment = ""
|
||||||
|
self.command_index = 0
|
||||||
|
|
||||||
|
self.scanning_pending = PendingScanType.NO_SCANNING.value
|
||||||
|
|
||||||
|
# This is called for every file, fill out mib_table
|
||||||
|
def _handle_file_parsing(self, file_name, *args):
|
||||||
|
self_print_parsing_info = False
|
||||||
|
if len(args) == 1 and isinstance(args[0], bool):
|
||||||
|
self_print_parsing_info = args[0]
|
||||||
|
file = open(file_name, "r")
|
||||||
|
|
||||||
|
if self_print_parsing_info:
|
||||||
|
print("Parsing " + file_name + " ...")
|
||||||
|
|
||||||
|
# Scans each line for possible device handler command enums
|
||||||
|
for line in file.readlines():
|
||||||
|
self.__handle_line_reading(line)
|
||||||
|
|
||||||
|
def __handle_line_reading(self, line: str):
|
||||||
|
"""
|
||||||
|
Search for struct command definition
|
||||||
|
:param line:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.__scan_for_commands(line)
|
||||||
|
# if self.struct_scanning_pending:
|
||||||
|
|
||||||
|
def __scan_for_commands(self, line):
|
||||||
|
# Search for struct command definition
|
||||||
|
struct_found = self.__scan_for_structs(line)
|
||||||
|
if not struct_found:
|
||||||
|
self.__scan_for_class(line)
|
||||||
|
if self.scanning_pending is not PendingScanType.NO_SCANNING.value:
|
||||||
|
self.__scan_command(line)
|
||||||
|
|
||||||
|
def __scan_for_structs(self, line):
|
||||||
|
struct_match = re.search(r'[\s]*struct[\s]*([\w]*)[\s]*{[\s]*[/!<>]*[\s]*'
|
||||||
|
r'\[EXPORT\][ :]*\[COMMAND\]'
|
||||||
|
r'[\s]*([\w]*)[ :]*([\w]*)', line)
|
||||||
|
if struct_match:
|
||||||
|
# Scan a found command struct
|
||||||
|
self.__start_class_or_struct_scanning(struct_match)
|
||||||
|
self.scanning_pending = PendingScanType.STRUCT_SCAN.value
|
||||||
|
return struct_match
|
||||||
|
|
||||||
|
def __scan_for_class(self, line):
|
||||||
|
# search for class command definition
|
||||||
|
class_match = re.search(r'[\s]*class[\s]*([\w]*)[\s]*[^{]*{[ /!<>]*\[EXPORT\][ :]*'
|
||||||
|
r'\[COMMAND\][\s]*([\w]*)[ :]*([\w]*)', line)
|
||||||
|
if class_match:
|
||||||
|
self.__start_class_or_struct_scanning(class_match)
|
||||||
|
self.scanning_pending = PendingScanType.CLASS_SCAN.value
|
||||||
|
|
||||||
|
def __start_class_or_struct_scanning(self, command_match):
|
||||||
|
"""
|
||||||
|
Stores and assigns values that are the same for each command field option
|
||||||
|
:param command_match:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
handler_name = command_match.group(2)
|
||||||
|
self.dict_entry_list[Clmns.DH_NAME.value] = handler_name
|
||||||
|
self.dict_entry_list[Clmns.NAME.value] = command_match.group(1)
|
||||||
|
command_name = command_match.group(3)
|
||||||
|
if handler_name in self.dh_information_table:
|
||||||
|
(command_id_dict, self.enum_dict) = self.dh_information_table[handler_name]
|
||||||
|
if command_name in command_id_dict:
|
||||||
|
self.dict_entry_list[Clmns.ACTION_ID.value] = command_id_dict[command_name]
|
||||||
|
|
||||||
|
def __scan_command(self, line):
|
||||||
|
datatype_match = False
|
||||||
|
if self.scanning_pending is PendingScanType.STRUCT_SCAN.value:
|
||||||
|
datatype_match = \
|
||||||
|
re.search(r'[\s]*(uint[0-9]{1,2}_t|float|double|bool|int|char)[\s]*([\w]*);'
|
||||||
|
r'(?:[\s]*[/!<>]*[\s]*\[EXPORT\][: ]*(.*))?', line)
|
||||||
|
elif self.scanning_pending is PendingScanType.CLASS_SCAN.value:
|
||||||
|
datatype_match = re.search(
|
||||||
|
r'[\s]*SerializeElement[\s]*<(uint[0-9]{1,2}_t|float|double|bool|int|char)[ >]*'
|
||||||
|
r'([\w]*);(?:[ /!<>]*\[EXPORT\][: ]*(.*))?', line)
|
||||||
|
if datatype_match:
|
||||||
|
self.__handle_datatype_match(datatype_match)
|
||||||
|
elif re.search(r'}[\s]*;', line):
|
||||||
|
self.scanning_pending = PendingScanType.NO_SCANNING.value
|
||||||
|
self.command_index = 0
|
||||||
|
|
||||||
|
def __handle_datatype_match(self, datatype_match):
|
||||||
|
self.dict_entry_list[Clmns.TYPE.value] = datatype_match.group(1)
|
||||||
|
self.dict_entry_list[Clmns.COMMAND_FIELD_NAME.value] = datatype_match.group(2)
|
||||||
|
size_of_enum = 0
|
||||||
|
if datatype_match.group(3) is not None:
|
||||||
|
self.__analyse_exporter_sequence(datatype_match.group(3))
|
||||||
|
if self.current_enum_name != "":
|
||||||
|
size_of_enum = self.__get_enum_size()
|
||||||
|
self.__update_device_command_dict(size_of_enum)
|
||||||
|
|
||||||
|
def __analyse_exporter_sequence(self, exporter_sequence):
|
||||||
|
# This matches the exporter sequence pairs e.g. [ENUM] BLA [COMMENT] BLABLA [...] ...
|
||||||
|
export_string_matches = re.search(r'(?:\[([\w]*)\][\s]*([^\[]*))?', exporter_sequence)
|
||||||
|
if export_string_matches:
|
||||||
|
if len(export_string_matches.groups()) % 2 != 0:
|
||||||
|
print("Device Command Parser: Error when analysing exporter sequence,"
|
||||||
|
" check exporter string format")
|
||||||
|
else:
|
||||||
|
count = 0
|
||||||
|
while count < len(export_string_matches.groups()):
|
||||||
|
sequence_type = export_string_matches.group(count + 1)
|
||||||
|
sequence_entry = export_string_matches.group(count + 2)
|
||||||
|
count = count + 2
|
||||||
|
self.__handle_sequence_pair(sequence_type, sequence_entry)
|
||||||
|
|
||||||
|
def __handle_sequence_pair(self, sequence_type, sequence_entry):
|
||||||
|
if sequence_type.casefold() == "enum":
|
||||||
|
self.current_enum_name = sequence_entry
|
||||||
|
elif sequence_type.casefold() == "comment":
|
||||||
|
self.command_comment = sequence_entry
|
||||||
|
|
||||||
|
def __get_enum_size(self) -> int:
|
||||||
|
if self.current_enum_name in self.enum_dict:
|
||||||
|
size_of_enum = len(self.enum_dict[self.current_enum_name][1])
|
||||||
|
return size_of_enum
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def __update_device_command_dict(self, size_of_enum: int = 0):
|
||||||
|
if size_of_enum > 0:
|
||||||
|
enum_tuple = self.enum_dict[self.current_enum_name]
|
||||||
|
for count in range(0, size_of_enum):
|
||||||
|
self.__update_table_with_command_options(count, enum_tuple)
|
||||||
|
self.command_index = \
|
||||||
|
self.command_index + 1
|
||||||
|
else:
|
||||||
|
self.__update_table_with_no_command_options()
|
||||||
|
self.index = self.index + 1
|
||||||
|
self.current_enum_name = ""
|
||||||
|
|
||||||
|
def __update_table_with_command_options(self, count, enum_tuple):
|
||||||
|
enum_value_name_list, enum_value_list, enum_comment_list = enum_tuple
|
||||||
|
self.dict_entry_list[Clmns.COMMAND_FIELD_OPTION_NAME.value] = \
|
||||||
|
enum_value_name_list[count]
|
||||||
|
self.dict_entry_list[Clmns.COMMAND_FIELD_OPTION_VALUE.value] = enum_value_list[count]
|
||||||
|
self.dict_entry_list[Clmns.COMMAND_FIELD_COMMENT.value] = enum_comment_list[count]
|
||||||
|
self.dict_entry_list[Clmns.COMMAND_INDEX.value] = \
|
||||||
|
self.command_index
|
||||||
|
dh_command_tuple = tuple(self.dict_entry_list)
|
||||||
|
self.index += 1
|
||||||
|
self.mib_table.update({self.index: dh_command_tuple})
|
||||||
|
|
||||||
|
def __update_table_with_no_command_options(self):
|
||||||
|
self.dict_entry_list[Clmns.COMMAND_FIELD_OPTION_NAME.value] = ""
|
||||||
|
self.dict_entry_list[Clmns.COMMAND_FIELD_OPTION_VALUE.value] = ""
|
||||||
|
self.dict_entry_list[Clmns.COMMAND_FIELD_COMMENT.value] = self.command_comment
|
||||||
|
self.dict_entry_list[Clmns.COMMAND_INDEX.value] = \
|
||||||
|
self.command_index
|
||||||
|
dh_command_tuple = tuple(self.dict_entry_list)
|
||||||
|
self.mib_table.update({self.index: dh_command_tuple})
|
||||||
|
self.command_index += 1
|
||||||
|
|
||||||
|
def _post_parsing_operation(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
0
generators/events/__init__.py
Normal file
0
generators/events/__init__.py
Normal file
94
generators/events/event_parser.py
Normal file
94
generators/events/event_parser.py
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#! /usr/bin/python3
|
||||||
|
"""
|
||||||
|
@file event_parser.py
|
||||||
|
@brief Part of the Mission Information Base Exporter for the SOURCE project by KSat.
|
||||||
|
@details
|
||||||
|
Event exporter.
|
||||||
|
|
||||||
|
To use MySQLdb, run pip install mysqlclient or install in IDE.
|
||||||
|
On Windows, Build Tools installation might be necessary
|
||||||
|
@data 21.11.2019
|
||||||
|
"""
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from fsfwgen.events.event_parser import handle_csv_export, handle_cpp_export, SubsystemDefinitionParser, EventParser
|
||||||
|
from fsfwgen.parserbase.file_list_parser import FileListParser
|
||||||
|
from fsfwgen.utility.printer import PrettyPrinter
|
||||||
|
from fsfwgen.utility.file_management import copy_file, move_file
|
||||||
|
|
||||||
|
from definitions import BspSelect, BspFolderDict
|
||||||
|
|
||||||
|
# TODO: Ask from user or store in json file?
|
||||||
|
BSP_SELECT = BspSelect.BSP_LINUX.value
|
||||||
|
BSP_FOLDER = BspFolderDict[BSP_SELECT]
|
||||||
|
DATE_TODAY = datetime.datetime.now()
|
||||||
|
DATE_STRING_FULL = DATE_TODAY.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
|
GENERATE_CPP = True
|
||||||
|
GENERATE_CPP_H = True
|
||||||
|
GENERATE_CSV = True
|
||||||
|
COPY_CPP_FILE = True
|
||||||
|
COPY_CPP_H_FILE = True
|
||||||
|
MOVE_CSV_FILE = True
|
||||||
|
|
||||||
|
PARSE_HOST_BSP = True
|
||||||
|
|
||||||
|
CSV_FILENAME = f"{BSP_FOLDER}_events.csv"
|
||||||
|
CSV_MOVE_DESTINATION = "../"
|
||||||
|
|
||||||
|
CPP_FILENAME = "translateEvents.cpp"
|
||||||
|
CPP_H_FILENAME = "translateEvents.h"
|
||||||
|
|
||||||
|
CPP_COPY_DESTINATION = f"../../{BSP_FOLDER}/fsfwconfig/events/"
|
||||||
|
|
||||||
|
FILE_SEPARATOR = ";"
|
||||||
|
SUBSYSTEM_DEFINITION_DESTINATIONS = [
|
||||||
|
f"../../{BSP_FOLDER}/fsfwconfig/events/subsystemIdRanges.h",
|
||||||
|
"../../fsfw/events/fwSubsystemIdRanges.h",
|
||||||
|
"../../common/config/commonSubsystemIds.h"
|
||||||
|
]
|
||||||
|
|
||||||
|
HEADER_DEFINITION_DESTINATIONS = ["../../mission/", "../../fsfw/", f"../../{BSP_FOLDER}", "../../test/"]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("EventParser: Parsing events: ")
|
||||||
|
event_list = parse_events()
|
||||||
|
if GENERATE_CSV:
|
||||||
|
handle_csv_export(file_name=CSV_FILENAME, event_list=event_list, file_separator=FILE_SEPARATOR)
|
||||||
|
if MOVE_CSV_FILE:
|
||||||
|
move_file(file_name=CSV_FILENAME, destination=CSV_MOVE_DESTINATION)
|
||||||
|
if GENERATE_CPP:
|
||||||
|
handle_cpp_export(
|
||||||
|
event_list=event_list, date_string=DATE_STRING_FULL, file_name=CPP_FILENAME,
|
||||||
|
generate_header=GENERATE_CPP_H, header_file_name=CPP_H_FILENAME
|
||||||
|
)
|
||||||
|
if COPY_CPP_FILE:
|
||||||
|
print(f"EventParser: Copying file to {CPP_COPY_DESTINATION}")
|
||||||
|
copy_file(CPP_FILENAME, CPP_COPY_DESTINATION)
|
||||||
|
copy_file(CPP_H_FILENAME, CPP_COPY_DESTINATION)
|
||||||
|
print("")
|
||||||
|
|
||||||
|
|
||||||
|
def parse_events():
|
||||||
|
subsystem_parser = SubsystemDefinitionParser(SUBSYSTEM_DEFINITION_DESTINATIONS)
|
||||||
|
subsystem_table = subsystem_parser.parse_files()
|
||||||
|
print(f"Found {len(subsystem_table)} subsystem definitions.")
|
||||||
|
PrettyPrinter.pprint(subsystem_table)
|
||||||
|
event_header_parser = FileListParser(HEADER_DEFINITION_DESTINATIONS)
|
||||||
|
event_headers = event_header_parser.parse_header_files(
|
||||||
|
True, "Parsing event header file list:\n", True
|
||||||
|
)
|
||||||
|
# PrettyPrinter.pprint(event_headers)
|
||||||
|
# myEventList = parseHeaderFiles(subsystem_table, event_headers)
|
||||||
|
event_parser = EventParser(event_headers, subsystem_table)
|
||||||
|
event_parser.set_moving_window_mode(moving_window_size=7)
|
||||||
|
event_table = event_parser.parse_files()
|
||||||
|
list_items = sorted(event_table.items())
|
||||||
|
print(f"Found {len(list_items)} entries:")
|
||||||
|
PrettyPrinter.pprint(list_items)
|
||||||
|
return list_items
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
249
generators/events/translateEvents.cpp
Normal file
249
generators/events/translateEvents.cpp
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
/**
|
||||||
|
* @brief Auto-generated event translation file. Contains 78 translations.
|
||||||
|
* @details
|
||||||
|
* Generated on: 2021-05-28 18:21:48
|
||||||
|
*/
|
||||||
|
#include "translateEvents.h"
|
||||||
|
|
||||||
|
const char *STORE_SEND_WRITE_FAILED_STRING = "STORE_SEND_WRITE_FAILED";
|
||||||
|
const char *STORE_WRITE_FAILED_STRING = "STORE_WRITE_FAILED";
|
||||||
|
const char *STORE_SEND_READ_FAILED_STRING = "STORE_SEND_READ_FAILED";
|
||||||
|
const char *STORE_READ_FAILED_STRING = "STORE_READ_FAILED";
|
||||||
|
const char *UNEXPECTED_MSG_STRING = "UNEXPECTED_MSG";
|
||||||
|
const char *STORING_FAILED_STRING = "STORING_FAILED";
|
||||||
|
const char *TM_DUMP_FAILED_STRING = "TM_DUMP_FAILED";
|
||||||
|
const char *STORE_INIT_FAILED_STRING = "STORE_INIT_FAILED";
|
||||||
|
const char *STORE_INIT_EMPTY_STRING = "STORE_INIT_EMPTY";
|
||||||
|
const char *STORE_CONTENT_CORRUPTED_STRING = "STORE_CONTENT_CORRUPTED";
|
||||||
|
const char *STORE_INITIALIZE_STRING = "STORE_INITIALIZE";
|
||||||
|
const char *INIT_DONE_STRING = "INIT_DONE";
|
||||||
|
const char *DUMP_FINISHED_STRING = "DUMP_FINISHED";
|
||||||
|
const char *DELETION_FINISHED_STRING = "DELETION_FINISHED";
|
||||||
|
const char *DELETION_FAILED_STRING = "DELETION_FAILED";
|
||||||
|
const char *AUTO_CATALOGS_SENDING_FAILED_STRING = "AUTO_CATALOGS_SENDING_FAILED";
|
||||||
|
const char *GET_DATA_FAILED_STRING = "GET_DATA_FAILED";
|
||||||
|
const char *STORE_DATA_FAILED_STRING = "STORE_DATA_FAILED";
|
||||||
|
const char *DEVICE_BUILDING_COMMAND_FAILED_STRING = "DEVICE_BUILDING_COMMAND_FAILED";
|
||||||
|
const char *DEVICE_SENDING_COMMAND_FAILED_STRING = "DEVICE_SENDING_COMMAND_FAILED";
|
||||||
|
const char *DEVICE_REQUESTING_REPLY_FAILED_STRING = "DEVICE_REQUESTING_REPLY_FAILED";
|
||||||
|
const char *DEVICE_READING_REPLY_FAILED_STRING = "DEVICE_READING_REPLY_FAILED";
|
||||||
|
const char *DEVICE_INTERPRETING_REPLY_FAILED_STRING = "DEVICE_INTERPRETING_REPLY_FAILED";
|
||||||
|
const char *DEVICE_MISSED_REPLY_STRING = "DEVICE_MISSED_REPLY";
|
||||||
|
const char *DEVICE_UNKNOWN_REPLY_STRING = "DEVICE_UNKNOWN_REPLY";
|
||||||
|
const char *DEVICE_UNREQUESTED_REPLY_STRING = "DEVICE_UNREQUESTED_REPLY";
|
||||||
|
const char *INVALID_DEVICE_COMMAND_STRING = "INVALID_DEVICE_COMMAND";
|
||||||
|
const char *MONITORING_LIMIT_EXCEEDED_STRING = "MONITORING_LIMIT_EXCEEDED";
|
||||||
|
const char *MONITORING_AMBIGUOUS_STRING = "MONITORING_AMBIGUOUS";
|
||||||
|
const char *FUSE_CURRENT_HIGH_STRING = "FUSE_CURRENT_HIGH";
|
||||||
|
const char *FUSE_WENT_OFF_STRING = "FUSE_WENT_OFF";
|
||||||
|
const char *POWER_ABOVE_HIGH_LIMIT_STRING = "POWER_ABOVE_HIGH_LIMIT";
|
||||||
|
const char *POWER_BELOW_LOW_LIMIT_STRING = "POWER_BELOW_LOW_LIMIT";
|
||||||
|
const char *SWITCH_WENT_OFF_STRING = "SWITCH_WENT_OFF";
|
||||||
|
const char *HEATER_ON_STRING = "HEATER_ON";
|
||||||
|
const char *HEATER_OFF_STRING = "HEATER_OFF";
|
||||||
|
const char *HEATER_TIMEOUT_STRING = "HEATER_TIMEOUT";
|
||||||
|
const char *HEATER_STAYED_ON_STRING = "HEATER_STAYED_ON";
|
||||||
|
const char *HEATER_STAYED_OFF_STRING = "HEATER_STAYED_OFF";
|
||||||
|
const char *TEMP_SENSOR_HIGH_STRING = "TEMP_SENSOR_HIGH";
|
||||||
|
const char *TEMP_SENSOR_LOW_STRING = "TEMP_SENSOR_LOW";
|
||||||
|
const char *TEMP_SENSOR_GRADIENT_STRING = "TEMP_SENSOR_GRADIENT";
|
||||||
|
const char *COMPONENT_TEMP_LOW_STRING = "COMPONENT_TEMP_LOW";
|
||||||
|
const char *COMPONENT_TEMP_HIGH_STRING = "COMPONENT_TEMP_HIGH";
|
||||||
|
const char *COMPONENT_TEMP_OOL_LOW_STRING = "COMPONENT_TEMP_OOL_LOW";
|
||||||
|
const char *COMPONENT_TEMP_OOL_HIGH_STRING = "COMPONENT_TEMP_OOL_HIGH";
|
||||||
|
const char *TEMP_NOT_IN_OP_RANGE_STRING = "TEMP_NOT_IN_OP_RANGE";
|
||||||
|
const char *FDIR_CHANGED_STATE_STRING = "FDIR_CHANGED_STATE";
|
||||||
|
const char *FDIR_STARTS_RECOVERY_STRING = "FDIR_STARTS_RECOVERY";
|
||||||
|
const char *FDIR_TURNS_OFF_DEVICE_STRING = "FDIR_TURNS_OFF_DEVICE";
|
||||||
|
const char *MONITOR_CHANGED_STATE_STRING = "MONITOR_CHANGED_STATE";
|
||||||
|
const char *VALUE_BELOW_LOW_LIMIT_STRING = "VALUE_BELOW_LOW_LIMIT";
|
||||||
|
const char *VALUE_ABOVE_HIGH_LIMIT_STRING = "VALUE_ABOVE_HIGH_LIMIT";
|
||||||
|
const char *VALUE_OUT_OF_RANGE_STRING = "VALUE_OUT_OF_RANGE";
|
||||||
|
const char *SWITCHING_TM_FAILED_STRING = "SWITCHING_TM_FAILED";
|
||||||
|
const char *CHANGING_MODE_STRING = "CHANGING_MODE";
|
||||||
|
const char *MODE_INFO_STRING = "MODE_INFO";
|
||||||
|
const char *FALLBACK_FAILED_STRING = "FALLBACK_FAILED";
|
||||||
|
const char *MODE_TRANSITION_FAILED_STRING = "MODE_TRANSITION_FAILED";
|
||||||
|
const char *CANT_KEEP_MODE_STRING = "CANT_KEEP_MODE";
|
||||||
|
const char *OBJECT_IN_INVALID_MODE_STRING = "OBJECT_IN_INVALID_MODE";
|
||||||
|
const char *FORCING_MODE_STRING = "FORCING_MODE";
|
||||||
|
const char *MODE_CMD_REJECTED_STRING = "MODE_CMD_REJECTED";
|
||||||
|
const char *HEALTH_INFO_STRING = "HEALTH_INFO";
|
||||||
|
const char *CHILD_CHANGED_HEALTH_STRING = "CHILD_CHANGED_HEALTH";
|
||||||
|
const char *CHILD_PROBLEMS_STRING = "CHILD_PROBLEMS";
|
||||||
|
const char *OVERWRITING_HEALTH_STRING = "OVERWRITING_HEALTH";
|
||||||
|
const char *TRYING_RECOVERY_STRING = "TRYING_RECOVERY";
|
||||||
|
const char *RECOVERY_STEP_STRING = "RECOVERY_STEP";
|
||||||
|
const char *RECOVERY_DONE_STRING = "RECOVERY_DONE";
|
||||||
|
const char *RF_AVAILABLE_STRING = "RF_AVAILABLE";
|
||||||
|
const char *RF_LOST_STRING = "RF_LOST";
|
||||||
|
const char *BIT_LOCK_STRING = "BIT_LOCK";
|
||||||
|
const char *BIT_LOCK_LOST_STRING = "BIT_LOCK_LOST";
|
||||||
|
const char *FRAME_PROCESSING_FAILED_STRING = "FRAME_PROCESSING_FAILED";
|
||||||
|
const char *CLOCK_SET_STRING = "CLOCK_SET";
|
||||||
|
const char *CLOCK_SET_FAILURE_STRING = "CLOCK_SET_FAILURE";
|
||||||
|
const char *TEST_STRING = "TEST";
|
||||||
|
|
||||||
|
const char * translateEvents(Event event) {
|
||||||
|
switch( (event & 0xffff) ) {
|
||||||
|
case(2200):
|
||||||
|
return STORE_SEND_WRITE_FAILED_STRING;
|
||||||
|
case(2201):
|
||||||
|
return STORE_WRITE_FAILED_STRING;
|
||||||
|
case(2202):
|
||||||
|
return STORE_SEND_READ_FAILED_STRING;
|
||||||
|
case(2203):
|
||||||
|
return STORE_READ_FAILED_STRING;
|
||||||
|
case(2204):
|
||||||
|
return UNEXPECTED_MSG_STRING;
|
||||||
|
case(2205):
|
||||||
|
return STORING_FAILED_STRING;
|
||||||
|
case(2206):
|
||||||
|
return TM_DUMP_FAILED_STRING;
|
||||||
|
case(2207):
|
||||||
|
return STORE_INIT_FAILED_STRING;
|
||||||
|
case(2208):
|
||||||
|
return STORE_INIT_EMPTY_STRING;
|
||||||
|
case(2209):
|
||||||
|
return STORE_CONTENT_CORRUPTED_STRING;
|
||||||
|
case(2210):
|
||||||
|
return STORE_INITIALIZE_STRING;
|
||||||
|
case(2211):
|
||||||
|
return INIT_DONE_STRING;
|
||||||
|
case(2212):
|
||||||
|
return DUMP_FINISHED_STRING;
|
||||||
|
case(2213):
|
||||||
|
return DELETION_FINISHED_STRING;
|
||||||
|
case(2214):
|
||||||
|
return DELETION_FAILED_STRING;
|
||||||
|
case(2215):
|
||||||
|
return AUTO_CATALOGS_SENDING_FAILED_STRING;
|
||||||
|
case(2600):
|
||||||
|
return GET_DATA_FAILED_STRING;
|
||||||
|
case(2601):
|
||||||
|
return STORE_DATA_FAILED_STRING;
|
||||||
|
case(2800):
|
||||||
|
return DEVICE_BUILDING_COMMAND_FAILED_STRING;
|
||||||
|
case(2801):
|
||||||
|
return DEVICE_SENDING_COMMAND_FAILED_STRING;
|
||||||
|
case(2802):
|
||||||
|
return DEVICE_REQUESTING_REPLY_FAILED_STRING;
|
||||||
|
case(2803):
|
||||||
|
return DEVICE_READING_REPLY_FAILED_STRING;
|
||||||
|
case(2804):
|
||||||
|
return DEVICE_INTERPRETING_REPLY_FAILED_STRING;
|
||||||
|
case(2805):
|
||||||
|
return DEVICE_MISSED_REPLY_STRING;
|
||||||
|
case(2806):
|
||||||
|
return DEVICE_UNKNOWN_REPLY_STRING;
|
||||||
|
case(2807):
|
||||||
|
return DEVICE_UNREQUESTED_REPLY_STRING;
|
||||||
|
case(2808):
|
||||||
|
return INVALID_DEVICE_COMMAND_STRING;
|
||||||
|
case(2809):
|
||||||
|
return MONITORING_LIMIT_EXCEEDED_STRING;
|
||||||
|
case(2810):
|
||||||
|
return MONITORING_AMBIGUOUS_STRING;
|
||||||
|
case(4201):
|
||||||
|
return FUSE_CURRENT_HIGH_STRING;
|
||||||
|
case(4202):
|
||||||
|
return FUSE_WENT_OFF_STRING;
|
||||||
|
case(4204):
|
||||||
|
return POWER_ABOVE_HIGH_LIMIT_STRING;
|
||||||
|
case(4205):
|
||||||
|
return POWER_BELOW_LOW_LIMIT_STRING;
|
||||||
|
case(4300):
|
||||||
|
return SWITCH_WENT_OFF_STRING;
|
||||||
|
case(5000):
|
||||||
|
return HEATER_ON_STRING;
|
||||||
|
case(5001):
|
||||||
|
return HEATER_OFF_STRING;
|
||||||
|
case(5002):
|
||||||
|
return HEATER_TIMEOUT_STRING;
|
||||||
|
case(5003):
|
||||||
|
return HEATER_STAYED_ON_STRING;
|
||||||
|
case(5004):
|
||||||
|
return HEATER_STAYED_OFF_STRING;
|
||||||
|
case(5200):
|
||||||
|
return TEMP_SENSOR_HIGH_STRING;
|
||||||
|
case(5201):
|
||||||
|
return TEMP_SENSOR_LOW_STRING;
|
||||||
|
case(5202):
|
||||||
|
return TEMP_SENSOR_GRADIENT_STRING;
|
||||||
|
case(5901):
|
||||||
|
return COMPONENT_TEMP_LOW_STRING;
|
||||||
|
case(5902):
|
||||||
|
return COMPONENT_TEMP_HIGH_STRING;
|
||||||
|
case(5903):
|
||||||
|
return COMPONENT_TEMP_OOL_LOW_STRING;
|
||||||
|
case(5904):
|
||||||
|
return COMPONENT_TEMP_OOL_HIGH_STRING;
|
||||||
|
case(5905):
|
||||||
|
return TEMP_NOT_IN_OP_RANGE_STRING;
|
||||||
|
case(7101):
|
||||||
|
return FDIR_CHANGED_STATE_STRING;
|
||||||
|
case(7102):
|
||||||
|
return FDIR_STARTS_RECOVERY_STRING;
|
||||||
|
case(7103):
|
||||||
|
return FDIR_TURNS_OFF_DEVICE_STRING;
|
||||||
|
case(7201):
|
||||||
|
return MONITOR_CHANGED_STATE_STRING;
|
||||||
|
case(7202):
|
||||||
|
return VALUE_BELOW_LOW_LIMIT_STRING;
|
||||||
|
case(7203):
|
||||||
|
return VALUE_ABOVE_HIGH_LIMIT_STRING;
|
||||||
|
case(7204):
|
||||||
|
return VALUE_OUT_OF_RANGE_STRING;
|
||||||
|
case(7301):
|
||||||
|
return SWITCHING_TM_FAILED_STRING;
|
||||||
|
case(7400):
|
||||||
|
return CHANGING_MODE_STRING;
|
||||||
|
case(7401):
|
||||||
|
return MODE_INFO_STRING;
|
||||||
|
case(7402):
|
||||||
|
return FALLBACK_FAILED_STRING;
|
||||||
|
case(7403):
|
||||||
|
return MODE_TRANSITION_FAILED_STRING;
|
||||||
|
case(7404):
|
||||||
|
return CANT_KEEP_MODE_STRING;
|
||||||
|
case(7405):
|
||||||
|
return OBJECT_IN_INVALID_MODE_STRING;
|
||||||
|
case(7406):
|
||||||
|
return FORCING_MODE_STRING;
|
||||||
|
case(7407):
|
||||||
|
return MODE_CMD_REJECTED_STRING;
|
||||||
|
case(7506):
|
||||||
|
return HEALTH_INFO_STRING;
|
||||||
|
case(7507):
|
||||||
|
return CHILD_CHANGED_HEALTH_STRING;
|
||||||
|
case(7508):
|
||||||
|
return CHILD_PROBLEMS_STRING;
|
||||||
|
case(7509):
|
||||||
|
return OVERWRITING_HEALTH_STRING;
|
||||||
|
case(7510):
|
||||||
|
return TRYING_RECOVERY_STRING;
|
||||||
|
case(7511):
|
||||||
|
return RECOVERY_STEP_STRING;
|
||||||
|
case(7512):
|
||||||
|
return RECOVERY_DONE_STRING;
|
||||||
|
case(7900):
|
||||||
|
return RF_AVAILABLE_STRING;
|
||||||
|
case(7901):
|
||||||
|
return RF_LOST_STRING;
|
||||||
|
case(7902):
|
||||||
|
return BIT_LOCK_STRING;
|
||||||
|
case(7903):
|
||||||
|
return BIT_LOCK_LOST_STRING;
|
||||||
|
case(7905):
|
||||||
|
return FRAME_PROCESSING_FAILED_STRING;
|
||||||
|
case(8900):
|
||||||
|
return CLOCK_SET_STRING;
|
||||||
|
case(8901):
|
||||||
|
return CLOCK_SET_FAILURE_STRING;
|
||||||
|
case(9700):
|
||||||
|
return TEST_STRING;
|
||||||
|
default:
|
||||||
|
return "UNKNOWN_EVENT";
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
8
generators/events/translateEvents.h
Normal file
8
generators/events/translateEvents.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef FSFWCONFIG_EVENTS_TRANSLATEEVENTS_H_
|
||||||
|
#define FSFWCONFIG_EVENTS_TRANSLATEEVENTS_H_
|
||||||
|
|
||||||
|
#include <fsfw/events/Event.h>
|
||||||
|
|
||||||
|
const char * translateEvents(Event event);
|
||||||
|
|
||||||
|
#endif /* FSFWCONFIG_EVENTS_TRANSLATEEVENTS_H_ */
|
@ -1 +1 @@
|
|||||||
Subproject commit fa507cc4f7b947cd9e4de30e9be6167ff1c15ec7
|
Subproject commit 78e890f947f55a9417d390fea8d9bd5684d11730
|
338
generators/mod_exporter.py
Normal file
338
generators/mod_exporter.py
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
#! /usr/bin/python3.8
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
@file mod_exporter.py
|
||||||
|
@brief Mission Information Base Exporter for the SOURCE project by KSat.
|
||||||
|
@details
|
||||||
|
Parses OBSW which is based on FSFW developed by the Institute of Space Systems (IRS) Stuttgart.
|
||||||
|
Python 3.8 required
|
||||||
|
This exporter generates the MIB from the SOURCE On-Board Software directly
|
||||||
|
by using file parser implementations
|
||||||
|
This exporter has the following capabilities :
|
||||||
|
1. Export MIB tables CSV files
|
||||||
|
2. Export MIB tables into a SQL database
|
||||||
|
|
||||||
|
This exporter currently has parser for following data:
|
||||||
|
1. Objects
|
||||||
|
2. Returnvalues
|
||||||
|
3. Packet content (Telemetry/Telecommands)
|
||||||
|
4. Events
|
||||||
|
5. Subservices
|
||||||
|
6. Device Commands
|
||||||
|
7. Global datapool
|
||||||
|
|
||||||
|
@developers
|
||||||
|
Basic Instructions to implement new parserbase:
|
||||||
|
This parser uses a generic parser class. A specific parser implementation
|
||||||
|
can be built by implementing the generic parser class.
|
||||||
|
The parser generally takes a list with all files to parse and a dictionary
|
||||||
|
with the structure of the MiB table.
|
||||||
|
This website can be used to experiment with regular expressions: https://regex101.com/
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
1. Maybe make this file object oriented too.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
from utility.mib_csv_writer import CsvWriter
|
||||||
|
from utility.mib_printer import Printer, PrettyPrinter
|
||||||
|
from utility.mib_sql_writer import SqlWriter
|
||||||
|
from utility import mib_globals as g
|
||||||
|
from parserbase.mib_file_list_parser import FileListParser
|
||||||
|
from packetcontent.mib_packet_content_parser import (
|
||||||
|
PacketContentParser,
|
||||||
|
PACKET_CONTENT_DEFINITION_DESTINATION,
|
||||||
|
PACKET_CONTENT_CSV_NAME,
|
||||||
|
PACKET_CONTENT_HEADER_COLUMN,
|
||||||
|
SQL_CREATE_PACKET_DATA_CONTENT_CMD,
|
||||||
|
SQL_INSERT_PACKET_DATA_CMD,
|
||||||
|
SQL_DELETE_PACKET_DATA_CONTENT_CMD
|
||||||
|
)
|
||||||
|
from subservice.mib_subservice_parser import (
|
||||||
|
SubserviceParser,
|
||||||
|
SUBSERVICE_DEFINITION_DESTINATION,
|
||||||
|
SUBSERVICE_CSV_NAME,
|
||||||
|
SUBSERVICE_COLUMN_HEADER,
|
||||||
|
SQL_CREATE_SUBSVC_CMD,
|
||||||
|
SQL_DELETE_SUBSVC_CMD,
|
||||||
|
SQL_INSERT_INTO_SUBSVC_CMD,
|
||||||
|
)
|
||||||
|
from devicecommands.device_command_parser import (
|
||||||
|
DeviceHandlerInformationParser,
|
||||||
|
DeviceHandlerCommandParser,
|
||||||
|
DH_COMMAND_PACKET_DEFINITION_DESTINATION,
|
||||||
|
DH_DEFINITION_DESTINATION,
|
||||||
|
DH_COMMANDS_CSV_NAME,
|
||||||
|
DH_COMMAND_HEADER_COLUMNS,
|
||||||
|
SQL_CREATE_CMDTABLE_CMD,
|
||||||
|
SQL_INSERT_INTO_CMDTABLE_CMD,
|
||||||
|
SQL_DELETE_CMDTABLE_CMD
|
||||||
|
)
|
||||||
|
from returnvalues.returnvalues_parser import (
|
||||||
|
InterfaceParser,
|
||||||
|
ReturnValueParser,
|
||||||
|
INTERFACE_DEFINITION_FILES,
|
||||||
|
RETURNVALUE_DESTINATIONS,
|
||||||
|
sql_retval_exporter,
|
||||||
|
CSV_RETVAL_FILENAME
|
||||||
|
)
|
||||||
|
from objects.objects import (
|
||||||
|
ObjectDefinitionParser,
|
||||||
|
OBJECTS_DEFINITIONS,
|
||||||
|
export_object_file,
|
||||||
|
CSV_OBJECT_FILENAME,
|
||||||
|
sql_object_exporter
|
||||||
|
)
|
||||||
|
DO_EXPORT_MIB = True
|
||||||
|
PRINT_TABLES_TO_CONSOLE = False
|
||||||
|
EXPORT_TO_CSV = True
|
||||||
|
EXPORT_TO_SQL = True
|
||||||
|
COPY_FILE = False
|
||||||
|
COPY_DESTINATION = "."
|
||||||
|
FILE_SEPARATOR = ";"
|
||||||
|
EXECUTE_SQL_COMMANDS = False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
Performs MIB generation.
|
||||||
|
"""
|
||||||
|
parse_mib()
|
||||||
|
|
||||||
|
|
||||||
|
def parse_mib():
|
||||||
|
"""
|
||||||
|
This is the core function. It builds parses all files,
|
||||||
|
builds all tables and returns them in a tuple.
|
||||||
|
The structure of respective tables is generated in a
|
||||||
|
separate functions and is easily modifiable:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
handle_subservices_generation()
|
||||||
|
print()
|
||||||
|
# handle_packet_content_generation()
|
||||||
|
# print()
|
||||||
|
# handle_device_handler_command_generation()
|
||||||
|
# print()
|
||||||
|
handle_returnvalue_generation()
|
||||||
|
print()
|
||||||
|
handle_objects_generation()
|
||||||
|
print()
|
||||||
|
handle_events_generation()
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def handle_subservices_generation():
|
||||||
|
print("MIB Exporter: Parsing subservices")
|
||||||
|
subservice_table = generate_subservice_table()
|
||||||
|
print("MIB Exporter: Found " + str(len(subservice_table)) + " subservice entries.")
|
||||||
|
if PRINT_TABLES_TO_CONSOLE:
|
||||||
|
print("MIB Exporter: Printing subservice table: ")
|
||||||
|
Printer.print_content(subservice_table)
|
||||||
|
if EXPORT_TO_CSV:
|
||||||
|
subservice_writer = CsvWriter(
|
||||||
|
SUBSERVICE_CSV_NAME, subservice_table, SUBSERVICE_COLUMN_HEADER
|
||||||
|
)
|
||||||
|
print("MIB Exporter: Exporting to file: " + SUBSERVICE_CSV_NAME)
|
||||||
|
subservice_writer.write_to_csv()
|
||||||
|
if EXPORT_TO_SQL:
|
||||||
|
print("MIB Exporter: Exporting subservices to SQL")
|
||||||
|
sql_writer = SqlWriter()
|
||||||
|
sql_writer.delete(SQL_DELETE_SUBSVC_CMD)
|
||||||
|
sql_writer.sql_writing_helper(
|
||||||
|
SQL_CREATE_SUBSVC_CMD, SQL_INSERT_INTO_SUBSVC_CMD, subservice_table
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_subservice_table():
|
||||||
|
""" Generate the subservice table. """
|
||||||
|
subservice_header_parser = FileListParser(
|
||||||
|
destination_corrected(SUBSERVICE_DEFINITION_DESTINATION)
|
||||||
|
)
|
||||||
|
subservice_header_list = subservice_header_parser.parse_header_files(
|
||||||
|
False, "MIB Exporter: Parsing subservice files: "
|
||||||
|
)
|
||||||
|
subservice_file_parser = SubserviceParser(subservice_header_list)
|
||||||
|
subservice_table = subservice_file_parser.parse_files()
|
||||||
|
return subservice_table
|
||||||
|
|
||||||
|
|
||||||
|
def handle_packet_content_generation():
|
||||||
|
print("MIB Exporter: Parsing packing content")
|
||||||
|
packet_content_table = generate_packet_content_table()
|
||||||
|
print("MIB Exporter: Found " + str(len(packet_content_table)) + " packet content entries.")
|
||||||
|
if PRINT_TABLES_TO_CONSOLE:
|
||||||
|
print("MIB Exporter: Print packet content table: ")
|
||||||
|
Printer.print_content(packet_content_table)
|
||||||
|
if EXPORT_TO_CSV:
|
||||||
|
packet_content_writer = CsvWriter(
|
||||||
|
PACKET_CONTENT_CSV_NAME, packet_content_table, PACKET_CONTENT_HEADER_COLUMN
|
||||||
|
)
|
||||||
|
print("MIB Exporter: Exporting to file " + PACKET_CONTENT_CSV_NAME)
|
||||||
|
packet_content_writer.write_to_csv()
|
||||||
|
if EXPORT_TO_SQL:
|
||||||
|
print("MIB Exporter: Exporting packet content to SQL")
|
||||||
|
sql_writer = SqlWriter()
|
||||||
|
|
||||||
|
sql_writer.sql_writing_helper(
|
||||||
|
SQL_CREATE_PACKET_DATA_CONTENT_CMD,
|
||||||
|
SQL_INSERT_PACKET_DATA_CMD,
|
||||||
|
packet_content_table,
|
||||||
|
SQL_DELETE_PACKET_DATA_CONTENT_CMD
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_packet_content_table():
|
||||||
|
""" Generate packet content table """
|
||||||
|
packet_data_header_parser = FileListParser(
|
||||||
|
destination_corrected(PACKET_CONTENT_DEFINITION_DESTINATION)
|
||||||
|
)
|
||||||
|
packet_data_header_list = packet_data_header_parser.parse_header_files(
|
||||||
|
False, "MIB Exporter: Parsing packet data files: "
|
||||||
|
)
|
||||||
|
packet_content_file_parser = PacketContentParser(packet_data_header_list)
|
||||||
|
packet_content_table = packet_content_file_parser.parse_files()
|
||||||
|
return packet_content_table
|
||||||
|
|
||||||
|
|
||||||
|
def handle_device_handler_command_generation():
|
||||||
|
print("MIB Exporter: Parsing device handler commands.")
|
||||||
|
dh_command_table = generate_device_command_table()
|
||||||
|
print("MIB Exporter: Found " + str(len(dh_command_table)) + " device handler command entries")
|
||||||
|
if PRINT_TABLES_TO_CONSOLE:
|
||||||
|
print("MIB Exporter: Printing device handler command table: ")
|
||||||
|
Printer.print_content(dh_command_table)
|
||||||
|
if EXPORT_TO_CSV:
|
||||||
|
device_command_writer = CsvWriter(
|
||||||
|
DH_COMMANDS_CSV_NAME, dh_command_table, DH_COMMAND_HEADER_COLUMNS
|
||||||
|
)
|
||||||
|
print("MIB Exporter: Exporting device handler commands to " + DH_COMMANDS_CSV_NAME)
|
||||||
|
device_command_writer.write_to_csv()
|
||||||
|
if EXPORT_TO_SQL:
|
||||||
|
print("MIB Exporter: Exporting device handler commands to SQL")
|
||||||
|
sql_writer = SqlWriter()
|
||||||
|
sql_writer.sql_writing_helper(
|
||||||
|
SQL_CREATE_CMDTABLE_CMD, SQL_INSERT_INTO_CMDTABLE_CMD, dh_command_table,
|
||||||
|
SQL_DELETE_CMDTABLE_CMD
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_device_command_table(print_info_table: bool = False):
|
||||||
|
""" Generate device command table """
|
||||||
|
info_header_file_parser = FileListParser(
|
||||||
|
destination_corrected(DH_DEFINITION_DESTINATION)
|
||||||
|
)
|
||||||
|
info_header_file_list = info_header_file_parser.parse_header_files(
|
||||||
|
False, "MIB Exporter: Parsing device handler informations: "
|
||||||
|
)
|
||||||
|
dh_information_parser = DeviceHandlerInformationParser(info_header_file_list)
|
||||||
|
dh_information_table = dh_information_parser.parse_files()
|
||||||
|
print("MIB Exporter: Found " + str(len(dh_information_table)) +
|
||||||
|
" device handler information entries.")
|
||||||
|
if print_info_table:
|
||||||
|
Printer.print_content(
|
||||||
|
dh_information_table, "MIB Exporter: Priting device handler command information table: "
|
||||||
|
)
|
||||||
|
|
||||||
|
header_file_parser = FileListParser(
|
||||||
|
destination_corrected(DH_COMMAND_PACKET_DEFINITION_DESTINATION)
|
||||||
|
)
|
||||||
|
header_file_list = header_file_parser.parse_header_files(
|
||||||
|
False, "MIB Exporter: Parsing device handler command files: "
|
||||||
|
)
|
||||||
|
packet_subservice_parser = DeviceHandlerCommandParser(
|
||||||
|
header_file_list, dh_information_table
|
||||||
|
)
|
||||||
|
dh_command_table = packet_subservice_parser.parse_files()
|
||||||
|
return dh_command_table
|
||||||
|
|
||||||
|
|
||||||
|
def handle_returnvalue_generation():
|
||||||
|
print("MIB Exporter: Parsing returnvalues")
|
||||||
|
returnvalue_table = generate_returnvalue_table()
|
||||||
|
print("MIB Exporter: Found " + str(len(returnvalue_table)) + " returnvalues.")
|
||||||
|
if PRINT_TABLES_TO_CONSOLE:
|
||||||
|
print("MIB Exporter: Printing returnvalue table: ")
|
||||||
|
Printer.print_content(returnvalue_table)
|
||||||
|
if EXPORT_TO_CSV:
|
||||||
|
print("MIB Exporter: Exporting returnvalues to " + CSV_RETVAL_FILENAME)
|
||||||
|
ReturnValueParser.export_to_file(CSV_RETVAL_FILENAME, returnvalue_table)
|
||||||
|
if EXPORT_TO_SQL:
|
||||||
|
print("MIB Exporter: Export returnvalues to SQL: ")
|
||||||
|
sql_retval_exporter(returnvalue_table)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_returnvalue_table():
|
||||||
|
interface_parser = InterfaceParser(
|
||||||
|
destination_corrected(INTERFACE_DEFINITION_FILES), False
|
||||||
|
)
|
||||||
|
interfaces = interface_parser.parse_files()
|
||||||
|
print("MIB Exporter: Found interfaces : " + str(len(interfaces)))
|
||||||
|
header_parser = FileListParser(destination_corrected(RETURNVALUE_DESTINATIONS))
|
||||||
|
header_list = header_parser.parse_header_files(True, "MIB Exporter: Parsing header file list: ")
|
||||||
|
returnvalue_parser = ReturnValueParser(interfaces, header_list, False)
|
||||||
|
returnvalue_table = returnvalue_parser.parse_files(False)
|
||||||
|
if PRINT_TABLES_TO_CONSOLE:
|
||||||
|
Printer.print_content(returnvalue_table, "Returnvalue Table: ")
|
||||||
|
return returnvalue_table
|
||||||
|
|
||||||
|
|
||||||
|
def handle_objects_generation():
|
||||||
|
print("MIB Exporter: Parsing Objects")
|
||||||
|
object_parser = ObjectDefinitionParser(destination_corrected(OBJECTS_DEFINITIONS))
|
||||||
|
object_table = object_parser.parse_files()
|
||||||
|
object_list_sorted = sorted(object_table.items())
|
||||||
|
print("MIB Exporter: Found " + str(len(object_table)) + " entries")
|
||||||
|
if EXPORT_TO_CSV:
|
||||||
|
print("MIB Exporter: Exporting to file: " + CSV_OBJECT_FILENAME)
|
||||||
|
export_object_file(CSV_OBJECT_FILENAME, object_list_sorted)
|
||||||
|
if EXPORT_TO_SQL:
|
||||||
|
print("MIB Exporter: Exporting objects into SQL table")
|
||||||
|
sql_object_exporter(object_list_sorted)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_events_generation():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def destination_corrected(destination_string):
|
||||||
|
"""
|
||||||
|
If headers are parsed here instead of the respective subdirectories,
|
||||||
|
the destination files are located in a different relative destination
|
||||||
|
"""
|
||||||
|
if isinstance(destination_string, list):
|
||||||
|
destination_list = []
|
||||||
|
for destination in destination_string:
|
||||||
|
destination_list.append(destination[3:])
|
||||||
|
return destination_list
|
||||||
|
|
||||||
|
return destination_string[3:]
|
||||||
|
|
||||||
|
|
||||||
|
def handle_external_file_running():
|
||||||
|
"""
|
||||||
|
Generates the MIB parser from external files
|
||||||
|
TODO: Make this stuff OOP too. Retvals and objects were already refactored
|
||||||
|
"""
|
||||||
|
os.chdir("events")
|
||||||
|
os.system("python event_parser.py")
|
||||||
|
os.chdir("..")
|
||||||
|
print_string = "Exported to file: MIB_Events.csv\r\n"
|
||||||
|
return print_string
|
||||||
|
|
||||||
|
|
||||||
|
def update_globals():
|
||||||
|
""" Updates the global variables """
|
||||||
|
g.PP = pprint.PrettyPrinter(indent=0, width=250)
|
||||||
|
g.doExportMIB = DO_EXPORT_MIB
|
||||||
|
g.executeSQLcommands = False
|
||||||
|
g.printToConsole = PRINT_TABLES_TO_CONSOLE
|
||||||
|
g.exportToCSV = EXPORT_TO_CSV
|
||||||
|
g.copyFile = COPY_FILE
|
||||||
|
g.copyDestination = COPY_DESTINATION
|
||||||
|
g.fileSeparator = FILE_SEPARATOR
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
0
generators/objects/__init__.py
Normal file
0
generators/objects/__init__.py
Normal file
109
generators/objects/objects.py
Normal file
109
generators/objects/objects.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
"""
|
||||||
|
@file objects.py
|
||||||
|
@brief Part of the Mission Information Base Exporter for the SOURCE project by KSat.
|
||||||
|
@details
|
||||||
|
Object exporter.
|
||||||
|
To use MySQLdb, run pip install mysqlclient or install in IDE.
|
||||||
|
On Windows, Build Tools installation might be necessary
|
||||||
|
@data 21.11.2019
|
||||||
|
"""
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from fsfwgen.objects.objects import ObjectDefinitionParser, sql_object_exporter, write_translation_file, \
|
||||||
|
export_object_file, write_translation_header_file
|
||||||
|
from fsfwgen.utility.printer import PrettyPrinter
|
||||||
|
from fsfwgen.utility.file_management import copy_file, move_file
|
||||||
|
from definitions import DATABASE_NAME, BspSelect, BspFolderDict
|
||||||
|
|
||||||
|
DATE_TODAY = datetime.datetime.now()
|
||||||
|
DATE_STRING_FULL = DATE_TODAY.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
|
GENERATE_CSV = True
|
||||||
|
MOVE_CSV = True
|
||||||
|
|
||||||
|
GENERATE_CPP = True
|
||||||
|
COPY_CPP = True
|
||||||
|
|
||||||
|
GENERATE_HEADER = True
|
||||||
|
|
||||||
|
PARSE_HOST_BSP = False
|
||||||
|
|
||||||
|
EXPORT_TO_SQL = True
|
||||||
|
|
||||||
|
BSP_SELECT = BspSelect.BSP_HOSTED.value
|
||||||
|
BSP_FOLDER = BspFolderDict[BSP_SELECT]
|
||||||
|
|
||||||
|
CPP_COPY_DESTINATION = f"../../{BSP_FOLDER}/fsfwconfig/objects/"
|
||||||
|
CSV_MOVE_DESTINATION = "../"
|
||||||
|
CPP_FILENAME = "translateObjects.cpp"
|
||||||
|
CPP_H_FILENAME = "translateObjects.h"
|
||||||
|
CSV_OBJECT_FILENAME = f"{BSP_FOLDER}_objects.csv"
|
||||||
|
FILE_SEPARATOR = ";"
|
||||||
|
|
||||||
|
|
||||||
|
OBJECTS_PATH = f"../../{BSP_FOLDER}/fsfwconfig/objects/systemObjectList.h"
|
||||||
|
FRAMEWORK_OBJECTS_PATH = "../../fsfw/objectmanager/frameworkObjects.h"
|
||||||
|
COMMON_OBJECTS_PATH = "../../common/config/commonSystemObjects.h"
|
||||||
|
OBJECTS_DEFINITIONS = [OBJECTS_PATH, FRAMEWORK_OBJECTS_PATH, COMMON_OBJECTS_PATH]
|
||||||
|
|
||||||
|
SQL_DELETE_OBJECTS_CMD = """
|
||||||
|
DROP TABLE IF EXISTS Objects
|
||||||
|
"""
|
||||||
|
|
||||||
|
SQL_CREATE_OBJECTS_CMD = """
|
||||||
|
CREATE TABLE IF NOT EXISTS Objects(
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
objectid TEXT,
|
||||||
|
name TEXT
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
|
SQL_INSERT_INTO_OBJECTS_CMD = """
|
||||||
|
INSERT INTO Objects(objectid, name)
|
||||||
|
VALUES(?,?)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Parsing objects: ")
|
||||||
|
list_items = parse_objects()
|
||||||
|
handle_file_export(list_items)
|
||||||
|
if EXPORT_TO_SQL:
|
||||||
|
print("ObjectParser: Exporting to SQL")
|
||||||
|
sql_object_exporter(
|
||||||
|
object_table=list_items, delete_cmd=SQL_DELETE_OBJECTS_CMD, insert_cmd=SQL_INSERT_INTO_OBJECTS_CMD,
|
||||||
|
create_cmd=SQL_CREATE_OBJECTS_CMD, db_filename=f"../{DATABASE_NAME}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_objects():
|
||||||
|
# fetch objects
|
||||||
|
object_parser = ObjectDefinitionParser(OBJECTS_DEFINITIONS)
|
||||||
|
subsystem_definitions = object_parser.parse_files()
|
||||||
|
# id_subsystem_definitions.update(framework_subsystem_definitions)
|
||||||
|
list_items = sorted(subsystem_definitions.items())
|
||||||
|
PrettyPrinter.pprint(list_items)
|
||||||
|
print("ObjectParser: Number of objects: ", len(list_items))
|
||||||
|
return list_items
|
||||||
|
|
||||||
|
|
||||||
|
def handle_file_export(list_items):
|
||||||
|
if GENERATE_CPP:
|
||||||
|
print("ObjectParser: Generating translation C++ file.")
|
||||||
|
write_translation_file(filename=CPP_FILENAME, list_of_entries=list_items, date_string_full=DATE_STRING_FULL)
|
||||||
|
if COPY_CPP:
|
||||||
|
print("ObjectParser: Copying object file to " + CPP_COPY_DESTINATION)
|
||||||
|
copy_file(CPP_FILENAME, CPP_COPY_DESTINATION)
|
||||||
|
if GENERATE_HEADER:
|
||||||
|
write_translation_header_file(filename=CPP_H_FILENAME)
|
||||||
|
copy_file(filename=CPP_H_FILENAME, destination=CPP_COPY_DESTINATION)
|
||||||
|
if GENERATE_CSV:
|
||||||
|
print("ObjectParser: Generating text export.")
|
||||||
|
export_object_file(filename=CSV_OBJECT_FILENAME, object_list=list_items, file_separator=FILE_SEPARATOR)
|
||||||
|
if MOVE_CSV:
|
||||||
|
move_file(file_name=CSV_OBJECT_FILENAME, destination=CSV_MOVE_DESTINATION)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
127
generators/objects/translateObjects.cpp
Normal file
127
generators/objects/translateObjects.cpp
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/**
|
||||||
|
* @brief Auto-generated object translation file.
|
||||||
|
* @details
|
||||||
|
* Contains 37 translations.
|
||||||
|
* Generated on: 2021-05-28 18:12:56
|
||||||
|
*/
|
||||||
|
#include "translateObjects.h"
|
||||||
|
|
||||||
|
const char *TEST_ASSEMBLY_STRING = "TEST_ASSEMBLY";
|
||||||
|
const char *TEST_CONTROLLER_STRING = "TEST_CONTROLLER";
|
||||||
|
const char *TEST_DEVICE_HANDLER_0_STRING = "TEST_DEVICE_HANDLER_0";
|
||||||
|
const char *TEST_DEVICE_HANDLER_1_STRING = "TEST_DEVICE_HANDLER_1";
|
||||||
|
const char *TEST_ECHO_COM_IF_STRING = "TEST_ECHO_COM_IF";
|
||||||
|
const char *FSFW_OBJECTS_START_STRING = "FSFW_OBJECTS_START";
|
||||||
|
const char *PUS_SERVICE_1_VERIFICATION_STRING = "PUS_SERVICE_1_VERIFICATION";
|
||||||
|
const char *PUS_SERVICE_2_DEVICE_ACCESS_STRING = "PUS_SERVICE_2_DEVICE_ACCESS";
|
||||||
|
const char *PUS_SERVICE_3_HOUSEKEEPING_STRING = "PUS_SERVICE_3_HOUSEKEEPING";
|
||||||
|
const char *PUS_SERVICE_5_EVENT_REPORTING_STRING = "PUS_SERVICE_5_EVENT_REPORTING";
|
||||||
|
const char *PUS_SERVICE_8_FUNCTION_MGMT_STRING = "PUS_SERVICE_8_FUNCTION_MGMT";
|
||||||
|
const char *PUS_SERVICE_9_TIME_MGMT_STRING = "PUS_SERVICE_9_TIME_MGMT";
|
||||||
|
const char *PUS_SERVICE_17_TEST_STRING = "PUS_SERVICE_17_TEST";
|
||||||
|
const char *PUS_SERVICE_20_PARAMETERS_STRING = "PUS_SERVICE_20_PARAMETERS";
|
||||||
|
const char *PUS_SERVICE_200_MODE_MGMT_STRING = "PUS_SERVICE_200_MODE_MGMT";
|
||||||
|
const char *PUS_SERVICE_201_HEALTH_STRING = "PUS_SERVICE_201_HEALTH";
|
||||||
|
const char *HEALTH_TABLE_STRING = "HEALTH_TABLE";
|
||||||
|
const char *MODE_STORE_STRING = "MODE_STORE";
|
||||||
|
const char *EVENT_MANAGER_STRING = "EVENT_MANAGER";
|
||||||
|
const char *INTERNAL_ERROR_REPORTER_STRING = "INTERNAL_ERROR_REPORTER";
|
||||||
|
const char *TC_STORE_STRING = "TC_STORE";
|
||||||
|
const char *TM_STORE_STRING = "TM_STORE";
|
||||||
|
const char *IPC_STORE_STRING = "IPC_STORE";
|
||||||
|
const char *TIME_STAMPER_STRING = "TIME_STAMPER";
|
||||||
|
const char *FSFW_OBJECTS_END_STRING = "FSFW_OBJECTS_END";
|
||||||
|
const char *UDP_BRIDGE_STRING = "UDP_BRIDGE";
|
||||||
|
const char *UDP_POLLING_TASK_STRING = "UDP_POLLING_TASK";
|
||||||
|
const char *CCSDS_DISTRIBUTOR_STRING = "CCSDS_DISTRIBUTOR";
|
||||||
|
const char *PUS_DISTRIBUTOR_STRING = "PUS_DISTRIBUTOR";
|
||||||
|
const char *TM_FUNNEL_STRING = "TM_FUNNEL";
|
||||||
|
const char *TEST_DUMMY_1_STRING = "TEST_DUMMY_1";
|
||||||
|
const char *TEST_DUMMY_2_STRING = "TEST_DUMMY_2";
|
||||||
|
const char *TEST_DUMMY_3_STRING = "TEST_DUMMY_3";
|
||||||
|
const char *TEST_DUMMY_4_STRING = "TEST_DUMMY_4";
|
||||||
|
const char *TEST_DUMMY_5_STRING = "TEST_DUMMY_5";
|
||||||
|
const char *TEST_TASK_STRING = "TEST_TASK";
|
||||||
|
const char *NO_OBJECT_STRING = "NO_OBJECT";
|
||||||
|
|
||||||
|
const char* translateObject(object_id_t object) {
|
||||||
|
switch( (object & 0xFFFFFFFF) ) {
|
||||||
|
case 0x4100CAFE:
|
||||||
|
return TEST_ASSEMBLY_STRING;
|
||||||
|
case 0x4301CAFE:
|
||||||
|
return TEST_CONTROLLER_STRING;
|
||||||
|
case 0x4401AFFE:
|
||||||
|
return TEST_DEVICE_HANDLER_0_STRING;
|
||||||
|
case 0x4402AFFE:
|
||||||
|
return TEST_DEVICE_HANDLER_1_STRING;
|
||||||
|
case 0x4900AFFE:
|
||||||
|
return TEST_ECHO_COM_IF_STRING;
|
||||||
|
case 0x53000000:
|
||||||
|
return FSFW_OBJECTS_START_STRING;
|
||||||
|
case 0x53000001:
|
||||||
|
return PUS_SERVICE_1_VERIFICATION_STRING;
|
||||||
|
case 0x53000002:
|
||||||
|
return PUS_SERVICE_2_DEVICE_ACCESS_STRING;
|
||||||
|
case 0x53000003:
|
||||||
|
return PUS_SERVICE_3_HOUSEKEEPING_STRING;
|
||||||
|
case 0x53000005:
|
||||||
|
return PUS_SERVICE_5_EVENT_REPORTING_STRING;
|
||||||
|
case 0x53000008:
|
||||||
|
return PUS_SERVICE_8_FUNCTION_MGMT_STRING;
|
||||||
|
case 0x53000009:
|
||||||
|
return PUS_SERVICE_9_TIME_MGMT_STRING;
|
||||||
|
case 0x53000017:
|
||||||
|
return PUS_SERVICE_17_TEST_STRING;
|
||||||
|
case 0x53000020:
|
||||||
|
return PUS_SERVICE_20_PARAMETERS_STRING;
|
||||||
|
case 0x53000200:
|
||||||
|
return PUS_SERVICE_200_MODE_MGMT_STRING;
|
||||||
|
case 0x53000201:
|
||||||
|
return PUS_SERVICE_201_HEALTH_STRING;
|
||||||
|
case 0x53010000:
|
||||||
|
return HEALTH_TABLE_STRING;
|
||||||
|
case 0x53010100:
|
||||||
|
return MODE_STORE_STRING;
|
||||||
|
case 0x53030000:
|
||||||
|
return EVENT_MANAGER_STRING;
|
||||||
|
case 0x53040000:
|
||||||
|
return INTERNAL_ERROR_REPORTER_STRING;
|
||||||
|
case 0x534f0100:
|
||||||
|
return TC_STORE_STRING;
|
||||||
|
case 0x534f0200:
|
||||||
|
return TM_STORE_STRING;
|
||||||
|
case 0x534f0300:
|
||||||
|
return IPC_STORE_STRING;
|
||||||
|
case 0x53500010:
|
||||||
|
return TIME_STAMPER_STRING;
|
||||||
|
case 0x53ffffff:
|
||||||
|
return FSFW_OBJECTS_END_STRING;
|
||||||
|
case 0x62000300:
|
||||||
|
return UDP_BRIDGE_STRING;
|
||||||
|
case 0x62000400:
|
||||||
|
return UDP_POLLING_TASK_STRING;
|
||||||
|
case 0x63000000:
|
||||||
|
return CCSDS_DISTRIBUTOR_STRING;
|
||||||
|
case 0x63000001:
|
||||||
|
return PUS_DISTRIBUTOR_STRING;
|
||||||
|
case 0x63000002:
|
||||||
|
return TM_FUNNEL_STRING;
|
||||||
|
case 0x74000001:
|
||||||
|
return TEST_DUMMY_1_STRING;
|
||||||
|
case 0x74000002:
|
||||||
|
return TEST_DUMMY_2_STRING;
|
||||||
|
case 0x74000003:
|
||||||
|
return TEST_DUMMY_3_STRING;
|
||||||
|
case 0x74000004:
|
||||||
|
return TEST_DUMMY_4_STRING;
|
||||||
|
case 0x74000005:
|
||||||
|
return TEST_DUMMY_5_STRING;
|
||||||
|
case 0x7400CAFE:
|
||||||
|
return TEST_TASK_STRING;
|
||||||
|
case 0xFFFFFFFF:
|
||||||
|
return NO_OBJECT_STRING;
|
||||||
|
default:
|
||||||
|
return "UNKNOWN_OBJECT";
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
8
generators/objects/translateObjects.h
Normal file
8
generators/objects/translateObjects.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef FSFWCONFIG_OBJECTS_TRANSLATEOBJECTS_H_
|
||||||
|
#define FSFWCONFIG_OBJECTS_TRANSLATEOBJECTS_H_
|
||||||
|
|
||||||
|
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||||
|
|
||||||
|
const char* translateObject(object_id_t object);
|
||||||
|
|
||||||
|
#endif /* FSFWCONFIG_OBJECTS_TRANSLATEOBJECTS_H_ */
|
0
generators/packetcontent/__init__.py
Normal file
0
generators/packetcontent/__init__.py
Normal file
305
generators/packetcontent/mib_packet_content_parser.py
Normal file
305
generators/packetcontent/mib_packet_content_parser.py
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
#! /usr/bin/python3.8
|
||||||
|
"""
|
||||||
|
@file mib_packet_content_parser.py
|
||||||
|
@brief Parses the Service Packet Definition files for all variables
|
||||||
|
@details Used by the Mib Exporter, inherits generic File Parser
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
|
||||||
|
from parserbase.mib_file_list_parser import FileListParser
|
||||||
|
from parserbase.mib_parser import FileParser
|
||||||
|
from utility.mib_csv_writer import CsvWriter
|
||||||
|
from utility.mib_printer import Printer
|
||||||
|
|
||||||
|
PACKET_CONTENT_DEFINITION_DESTINATION = ["../../mission/pus/servicepackets/",
|
||||||
|
"../../fsfw/pus/servicepackets/"]
|
||||||
|
PACKET_CONTENT_CSV_NAME = "mib_packet_data_content.csv"
|
||||||
|
PACKET_CONTENT_HEADER_COLUMN = ["Service", "Subservice", "Packet Name", "Datatype", "Name",
|
||||||
|
"Size [Bytes]", "Comment"]
|
||||||
|
|
||||||
|
SQL_DELETE_PACKET_DATA_CONTENT_CMD = """
|
||||||
|
DROP TABLE IF EXISTS PacketContent;
|
||||||
|
"""
|
||||||
|
|
||||||
|
SQL_CREATE_PACKET_DATA_CONTENT_CMD = """
|
||||||
|
CREATE TABLE IF NOT EXISTS PacketContent (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
service INTEGER,
|
||||||
|
subsvc INTEGER,
|
||||||
|
packetName TEXT ,
|
||||||
|
dataType TEXT,
|
||||||
|
name TEXT,
|
||||||
|
size INTEGER,
|
||||||
|
comment TEXT
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
|
SQL_INSERT_PACKET_DATA_CMD = """
|
||||||
|
INSERT INTO PacketContent(service,subsvc,packetName,dataType,name,size,comment)
|
||||||
|
VALUES(?,?,?,?,?,?,?)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("PacketContentParser: Parsing for header files.")
|
||||||
|
header_file_parser = FileListParser(PACKET_CONTENT_DEFINITION_DESTINATION)
|
||||||
|
header_file_list = header_file_parser.parse_header_files(False, "Parsing packet data files: ")
|
||||||
|
packet_content_parser = PacketContentParser(header_file_list)
|
||||||
|
subservice_table = packet_content_parser.parse_files(True)
|
||||||
|
Printer.print_content(subservice_table, "PacketContentParser: Printing packet data table:")
|
||||||
|
subservice_writer = CsvWriter(PACKET_CONTENT_CSV_NAME,
|
||||||
|
subservice_table, PACKET_CONTENT_HEADER_COLUMN)
|
||||||
|
subservice_writer.write_to_csv()
|
||||||
|
subservice_writer.move_csv("..")
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyTypeChecker
|
||||||
|
class PacketContentParser(FileParser):
|
||||||
|
# Initialize all needed columns
|
||||||
|
def __init__(self, file_list):
|
||||||
|
super().__init__(file_list)
|
||||||
|
self.serviceColumn = 0
|
||||||
|
self.subserviceColumn = 1
|
||||||
|
self.classNameColumn = 2
|
||||||
|
self.datatypeColumn = 3
|
||||||
|
self.nameColumn = 4
|
||||||
|
self.sizeColumn = 5
|
||||||
|
self.commentColumn = 6
|
||||||
|
self.lastEntryColumn = 7
|
||||||
|
self.columnListLength = 8
|
||||||
|
self.dictEntryList = list(range(self.columnListLength-1))
|
||||||
|
|
||||||
|
self.datatypeMatch = False
|
||||||
|
self.ignoreFlag = False
|
||||||
|
|
||||||
|
def _handle_file_parsing(self, file_name: str, *args: any):
|
||||||
|
self_print_parsing_info = False
|
||||||
|
if len(args) == 1 and isinstance(args[0], bool):
|
||||||
|
self_print_parsing_info = args[0]
|
||||||
|
|
||||||
|
# Read service from file name
|
||||||
|
self.dictEntryList[self.serviceColumn] = re.search('[0-9]{1,3}', file_name).group(0)
|
||||||
|
self.dictEntryList[self.subserviceColumn] = " "
|
||||||
|
file = open(file_name, "r")
|
||||||
|
if self_print_parsing_info:
|
||||||
|
print("Parsing " + file_name + " ...")
|
||||||
|
# Scans each line for possible variables
|
||||||
|
for line in file.readlines():
|
||||||
|
# Looks for class and struct definitions which mark a PUS packet
|
||||||
|
self.scan_for_class_and_struct_match_and_handle_it(line)
|
||||||
|
# Looks for variables
|
||||||
|
self.scan_for_variable_match_and_handle_it(line)
|
||||||
|
|
||||||
|
# Operation taken when file parsing is complete
|
||||||
|
# All packet content sizes are set by analysing the datatype
|
||||||
|
def _post_parsing_operation(self):
|
||||||
|
self.update_packet_content_sizes()
|
||||||
|
|
||||||
|
def scan_for_class_and_struct_match_and_handle_it(self, line):
|
||||||
|
class_or_struct_match = re.search('[\s]*class[\s]*([\w]*)[\s]*.*[\s]*{[\s]*([^\n]*)', line)
|
||||||
|
if not class_or_struct_match:
|
||||||
|
class_or_struct_match = re.search(
|
||||||
|
'[\s]*struct[\s]*([\w]*)[\s]*.*[\s]*{[\s]*([^\n]*)', line)
|
||||||
|
if class_or_struct_match:
|
||||||
|
self.dictEntryList[self.classNameColumn] = class_or_struct_match.group(1)
|
||||||
|
if class_or_struct_match.group(2):
|
||||||
|
self.dictEntryList[self.subserviceColumn] = \
|
||||||
|
self.check_for_subservice_string(class_or_struct_match.group(2))
|
||||||
|
|
||||||
|
def scan_for_variable_match_and_handle_it(self, line):
|
||||||
|
# Look for datatype definitions
|
||||||
|
var_match = self.packet_content_matcher(line)
|
||||||
|
if var_match:
|
||||||
|
# Attempts to find variable definition inside that packet
|
||||||
|
self.update_packet_content_table()
|
||||||
|
|
||||||
|
def packet_content_matcher(self, line):
|
||||||
|
# First step: Search for possible parameter definitions
|
||||||
|
# Generic serialize element or datatypes
|
||||||
|
var_match = re.search(
|
||||||
|
r'[\w]*(?:<)?[\s]*(uint32_t|uint8_t|uint16_t|ReturnValue_t|Mode_t|Submode_t|'
|
||||||
|
r'object_id_t|float|double|bool|ActionId_t|EventId_t|sid_t|ParameterId_t)'
|
||||||
|
r'(?:>)?[\s]*([\w]*)[\s]*(?:[= 0-9]*)?[;](?:[\/!< ]*([^\n]*))?', line)
|
||||||
|
if var_match:
|
||||||
|
# Debug printout
|
||||||
|
# print(var_match.group(0))
|
||||||
|
self.handle_generic_variable_match(var_match)
|
||||||
|
# Serial Fixed Array List with Size Header
|
||||||
|
else:
|
||||||
|
var_match = re.search(r'[ \w]*<SerialFixedArrayListAdapter<([\w_, ()]*)>>'
|
||||||
|
r'[\s]*([\w]*)[\s]*[;](?:[/!< ]*([^\n]*))?', line)
|
||||||
|
if var_match:
|
||||||
|
self.handle_serial_fixed_array_match(var_match)
|
||||||
|
# Serial Buffer, No length field
|
||||||
|
if not var_match:
|
||||||
|
var_match = re.search(r'[ \w]*<SerialBufferAdapter<([\w_,]*)>>'
|
||||||
|
r'[\s]*([\w]*)[\s]*[;](?:[/!< ]*([^\n]*))?', line)
|
||||||
|
if not var_match:
|
||||||
|
var_match = re.search(r'[\w ]*(?:<)?(uint32_t|uint8_t|uint16_t)[\s]*\*'
|
||||||
|
r'(?:>)?[\s]*([\w]*)[\s]*[;](?:[/!< ]*([^\n]*))?', line)
|
||||||
|
if var_match:
|
||||||
|
self.handle_serial_buffer_match(var_match)
|
||||||
|
# exclude size definition in serialize adapter or any definitions which are not parameter initializations
|
||||||
|
# or typedefs
|
||||||
|
if var_match and re.search("typedef", var_match.group(0)):
|
||||||
|
var_match = False
|
||||||
|
return var_match
|
||||||
|
|
||||||
|
def update_packet_content_table(self):
|
||||||
|
self.index = self.index + 1
|
||||||
|
dict_entry_tuple = tuple(self.dictEntryList[:self.columnListLength])
|
||||||
|
if not self.ignoreFlag:
|
||||||
|
self.mib_table.update({self.index: dict_entry_tuple})
|
||||||
|
else:
|
||||||
|
self.ignoreFlag = False
|
||||||
|
|
||||||
|
def handle_generic_variable_match(self, var_match):
|
||||||
|
self.handle_var_match(var_match)
|
||||||
|
self.handle_exporter_string(var_match.group(3))
|
||||||
|
|
||||||
|
def handle_serial_fixed_array_match(self, var_match):
|
||||||
|
if self.check_for_ignore_string(var_match.group(0)):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
fixed_array_properties = re.search(
|
||||||
|
'([\w_]*)[\s]*,[\s]*([\w_()]*)[\s]*,[\s]*([\w_()]*)[\s]*', var_match.group(1))
|
||||||
|
if fixed_array_properties:
|
||||||
|
type_of_next_buffer_size = fixed_array_properties.group(3)
|
||||||
|
self.index = self.index + 1
|
||||||
|
self.dictEntryList[self.datatypeColumn] = type_of_next_buffer_size
|
||||||
|
self.dictEntryList[self.nameColumn] = "Size of following buffer"
|
||||||
|
dict_entry_tuple = tuple(self.dictEntryList[:self.columnListLength])
|
||||||
|
self.mib_table.update({self.index: dict_entry_tuple})
|
||||||
|
self.handle_var_match(var_match)
|
||||||
|
self.dictEntryList[self.datatypeColumn] = fixed_array_properties.group(1) + " *"
|
||||||
|
self.handle_exporter_string(var_match.group(3))
|
||||||
|
|
||||||
|
def handle_serial_buffer_match(self, var_match):
|
||||||
|
self.handle_var_match(var_match)
|
||||||
|
self.dictEntryList[self.datatypeColumn] = var_match.group(1) + " *"
|
||||||
|
self.dictEntryList[self.sizeColumn] = "deduced"
|
||||||
|
self.handle_exporter_string(var_match.group(3))
|
||||||
|
|
||||||
|
def handle_var_match(self, var_match):
|
||||||
|
self.dictEntryList[self.commentColumn] = ""
|
||||||
|
self.dictEntryList[self.sizeColumn] = ""
|
||||||
|
self.dictEntryList[self.datatypeColumn] = var_match.group(1)
|
||||||
|
self.dictEntryList[self.nameColumn] = var_match.group(2)
|
||||||
|
|
||||||
|
def update_packet_content_sizes(self):
|
||||||
|
self.dictEntryList[self.sizeColumn] = " "
|
||||||
|
for key, content in self.mib_table.items():
|
||||||
|
content = self.attempt_uint_match(content)
|
||||||
|
if not self.datatypeMatch:
|
||||||
|
content = self.attempt_eight_byte_match(content)
|
||||||
|
if not self.datatypeMatch:
|
||||||
|
content = self.attempt_four_byte_match(content)
|
||||||
|
if not self.datatypeMatch:
|
||||||
|
content = self.attempt_two_byte_match(content)
|
||||||
|
if not self.datatypeMatch:
|
||||||
|
content = self.attempt_one_byte_match(content)
|
||||||
|
content = self.handle_uint_buffer_type(content)
|
||||||
|
self.mib_table.update({key: content})
|
||||||
|
|
||||||
|
def attempt_uint_match(self, content):
|
||||||
|
self.datatypeMatch = re.search('uint([\d]{1,2})_t', content[self.datatypeColumn])
|
||||||
|
if self.datatypeMatch:
|
||||||
|
content = list(content)
|
||||||
|
content[self.sizeColumn] = round(int(self.datatypeMatch.group(1)) / 8)
|
||||||
|
content = tuple(content)
|
||||||
|
return content
|
||||||
|
|
||||||
|
def attempt_four_byte_match(self, content):
|
||||||
|
self.datatypeMatch = re.search(
|
||||||
|
r'object_id_t|ActionId_t|Mode_t|float|sid_t|ParameterId_t',
|
||||||
|
content[self.datatypeColumn])
|
||||||
|
if self.datatypeMatch:
|
||||||
|
content = list(content)
|
||||||
|
content[self.sizeColumn] = 4
|
||||||
|
content = tuple(content)
|
||||||
|
return content
|
||||||
|
|
||||||
|
def attempt_eight_byte_match(self, content):
|
||||||
|
self.datatypeMatch = re.search('double', content[self.datatypeColumn])
|
||||||
|
if self.datatypeMatch:
|
||||||
|
content = list(content)
|
||||||
|
content[self.sizeColumn] = 8
|
||||||
|
content = tuple(content)
|
||||||
|
return content
|
||||||
|
|
||||||
|
def attempt_two_byte_match(self, content):
|
||||||
|
self.datatypeMatch = re.search('ReturnValue_t|EventId_t', content[self.datatypeColumn])
|
||||||
|
if self.datatypeMatch:
|
||||||
|
content = list(content)
|
||||||
|
content[self.sizeColumn] = 2
|
||||||
|
content = tuple(content)
|
||||||
|
return content
|
||||||
|
|
||||||
|
def attempt_one_byte_match(self, content):
|
||||||
|
self.datatypeMatch = re.search('Submode_t|bool', content[self.datatypeColumn])
|
||||||
|
if self.datatypeMatch:
|
||||||
|
content = list(content)
|
||||||
|
content[self.sizeColumn] = 1
|
||||||
|
content = tuple(content)
|
||||||
|
return content
|
||||||
|
|
||||||
|
def handle_uint_buffer_type(self, content):
|
||||||
|
if re.search('\*', content[self.datatypeColumn]):
|
||||||
|
content = list(content)
|
||||||
|
content[self.sizeColumn] = "deduced"
|
||||||
|
content = tuple(content)
|
||||||
|
return content
|
||||||
|
|
||||||
|
# Used to scan exporter string for ignore flag or store any comments
|
||||||
|
def handle_exporter_string(self, match):
|
||||||
|
exporter_string = re.search('[ /!<]*\[EXPORT[\w]*\][\s]*:[\s]*([^\n]*)', match)
|
||||||
|
if exporter_string:
|
||||||
|
type_string = re.search("\[TYPE|BUFFERTYPE\][\s]*([\w]*)[^\n|\[]*", exporter_string.group(0),
|
||||||
|
re.IGNORECASE)
|
||||||
|
if type_string:
|
||||||
|
self.dictEntryList[self.datatypeColumn] = str(type_string.group(1)) + " *"
|
||||||
|
comment_string = re.search("\[COMMENT\][\s]*([\w]*)[^\n|\[]*", exporter_string.group(0),
|
||||||
|
re.IGNORECASE)
|
||||||
|
if comment_string:
|
||||||
|
self.dictEntryList[self.commentColumn] = comment_string.group(1)
|
||||||
|
self.check_for_ignore_string(exporter_string.group(0))
|
||||||
|
if not comment_string:
|
||||||
|
self.dictEntryList[self.commentColumn] = exporter_string.group(1)
|
||||||
|
|
||||||
|
# Used to transform comma separated subservice numbers into specific subservice numbers
|
||||||
|
def check_for_subservice_string(self, full_description):
|
||||||
|
subservice_info = re.search(
|
||||||
|
r'^.*//[\s]*[!<]*[\s]*\[EXPORT[\w]*\][\s]*:[\s]*\[SUBSERVICE\][\s]*([^\n]*)',
|
||||||
|
full_description, re.IGNORECASE)
|
||||||
|
description = ' '
|
||||||
|
if subservice_info:
|
||||||
|
description = self.handle_subservice_string(subservice_info)
|
||||||
|
if full_description == '':
|
||||||
|
description = ' '
|
||||||
|
return description
|
||||||
|
|
||||||
|
def check_for_ignore_string(self, string):
|
||||||
|
ignore_string = re.search("IGNORE", string, re.IGNORECASE)
|
||||||
|
if ignore_string:
|
||||||
|
self.ignoreFlag = True
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def handle_subservice_string(subservice_info):
|
||||||
|
description = ' '
|
||||||
|
subservice_list = [int(x) for x in subservice_info.group(1).split(',')]
|
||||||
|
subservice_number = len(subservice_list)
|
||||||
|
for i in range(subservice_number):
|
||||||
|
description = description + str(subservice_list[i])
|
||||||
|
if i == subservice_number - 2:
|
||||||
|
description = description + " and "
|
||||||
|
elif i < subservice_number - 1:
|
||||||
|
description = description + ", "
|
||||||
|
return description
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
||||||
|
|
0
generators/returnvalues/__init__.py
Normal file
0
generators/returnvalues/__init__.py
Normal file
102
generators/returnvalues/returnvalues_parser.py
Normal file
102
generators/returnvalues/returnvalues_parser.py
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#! /usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
:file: returnvalues_parser.py
|
||||||
|
:brief: Part of the MOD export tools for the SOURCE project by KSat.
|
||||||
|
TODO: Integrate into Parser Structure instead of calling this file (no cpp file generated yet)
|
||||||
|
:details:
|
||||||
|
Returnvalue exporter.
|
||||||
|
To use MySQLdb, run pip install mysqlclient or install in IDE. On Windows, Build Tools installation might be necessary.
|
||||||
|
:data: 21.11.2019
|
||||||
|
"""
|
||||||
|
from fsfwgen.parserbase.file_list_parser import FileListParser
|
||||||
|
from fsfwgen.returnvalues.returnvalues_parser import InterfaceParser, ReturnValueParser
|
||||||
|
from fsfwgen.utility.sql_writer import SqlWriter
|
||||||
|
from fsfwgen.utility.file_management import move_file
|
||||||
|
|
||||||
|
from definitions import DATABASE_NAME, BspSelect, BspFolderDict
|
||||||
|
|
||||||
|
EXPORT_TO_FILE = True
|
||||||
|
MOVE_CSV_FILE = True
|
||||||
|
EXPORT_TO_SQL = True
|
||||||
|
PRINT_TABLES = True
|
||||||
|
|
||||||
|
BSP_SELECT = BspSelect.BSP_HOSTED.value
|
||||||
|
BSP_FOLDER = BspFolderDict[BSP_SELECT]
|
||||||
|
|
||||||
|
CSV_RETVAL_FILENAME = f"{BSP_FOLDER}_returnvalues.csv"
|
||||||
|
CSV_MOVE_DESTINATION = "../"
|
||||||
|
FILE_SEPARATOR = ';'
|
||||||
|
MAX_STRING_LENGTH = 32
|
||||||
|
INTERFACE_DEFINITION_FILES = [
|
||||||
|
"../../fsfw/returnvalues/FwClassIds.h",
|
||||||
|
"../../common/config/commonClassIds.h",
|
||||||
|
f"../../{BSP_FOLDER}/fsfwconfig/returnvalues/classIds.h"
|
||||||
|
]
|
||||||
|
RETURNVALUE_DESTINATIONS = [
|
||||||
|
"../../mission/", "../../fsfw/", f"../../{BSP_FOLDER}"
|
||||||
|
]
|
||||||
|
|
||||||
|
SQL_DELETE_RETURNVALUES_CMD = """
|
||||||
|
DROP TABLE IF EXISTS Returnvalues
|
||||||
|
"""
|
||||||
|
|
||||||
|
SQL_CREATE_RETURNVALUES_CMD = """
|
||||||
|
CREATE TABLE IF NOT EXISTS Returnvalues (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
code TEXT,
|
||||||
|
name TEXT,
|
||||||
|
interface TEXT,
|
||||||
|
file TEXT,
|
||||||
|
description TEXT
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
|
SQL_INSERT_RETURNVALUES_CMD = """
|
||||||
|
INSERT INTO Returnvalues(code,name,interface,file,description)
|
||||||
|
VALUES(?,?,?,?,?)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
returnvalue_table = parse_returnvalues()
|
||||||
|
print("")
|
||||||
|
if EXPORT_TO_FILE:
|
||||||
|
ReturnValueParser.export_to_file(CSV_RETVAL_FILENAME, returnvalue_table, FILE_SEPARATOR)
|
||||||
|
if MOVE_CSV_FILE:
|
||||||
|
move_file(file_name=CSV_RETVAL_FILENAME, destination=CSV_MOVE_DESTINATION)
|
||||||
|
if EXPORT_TO_SQL:
|
||||||
|
print("ReturnvalueParser: Exporting to SQL")
|
||||||
|
sql_retval_exporter(returnvalue_table, db_filename=f"../{DATABASE_NAME}")
|
||||||
|
|
||||||
|
|
||||||
|
def parse_returnvalues():
|
||||||
|
""" Core function to parse for the return values """
|
||||||
|
interface_parser = InterfaceParser(file_list=INTERFACE_DEFINITION_FILES, print_table=PRINT_TABLES)
|
||||||
|
interfaces = interface_parser.parse_files()
|
||||||
|
header_parser = FileListParser(RETURNVALUE_DESTINATIONS)
|
||||||
|
header_list = header_parser.parse_header_files(True, "Parsing header file list: ")
|
||||||
|
print("")
|
||||||
|
returnvalue_parser = ReturnValueParser(interfaces, header_list, PRINT_TABLES)
|
||||||
|
returnvalue_parser.set_moving_window_mode(moving_window_size=7)
|
||||||
|
returnvalue_table = returnvalue_parser.parse_files(True)
|
||||||
|
print(f"ReturnvalueParser: Found {len(returnvalue_table)} returnvalues.")
|
||||||
|
return returnvalue_table
|
||||||
|
|
||||||
|
|
||||||
|
def sql_retval_exporter(returnvalue_table, db_filename: str):
|
||||||
|
sql_writer = SqlWriter(db_filename=db_filename)
|
||||||
|
sql_writer.open(SQL_CREATE_RETURNVALUES_CMD)
|
||||||
|
for entry in returnvalue_table.items():
|
||||||
|
sql_writer.write_entries(
|
||||||
|
SQL_INSERT_RETURNVALUES_CMD, (entry[0],
|
||||||
|
entry[1][2],
|
||||||
|
entry[1][4],
|
||||||
|
entry[1][3],
|
||||||
|
entry[1][1]))
|
||||||
|
sql_writer.commit()
|
||||||
|
sql_writer.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
0
generators/subservice/__init__.py
Normal file
0
generators/subservice/__init__.py
Normal file
242
generators/subservice/mib_subservice_parser.py
Normal file
242
generators/subservice/mib_subservice_parser.py
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
"""
|
||||||
|
@file mib_subservice_parser.py
|
||||||
|
@brief Parses the Subservice definitions for the Mission Information Base.
|
||||||
|
@details Used by the MIB Exporter, inherits generic File Parser
|
||||||
|
@author R. Mueller
|
||||||
|
@date 14.11.2019
|
||||||
|
|
||||||
|
Example Stringset to scan for:
|
||||||
|
|
||||||
|
enum Subservice: uint8_t {
|
||||||
|
//!< [EXPORT] : [COMMAND] Perform connection test
|
||||||
|
CONNECTION_TEST = 1,
|
||||||
|
//!< [EXPORT] : [REPLY] Connection test reply
|
||||||
|
CONNECTION_TEST_REPORT = 2,
|
||||||
|
EVENT_TRIGGER_TEST = 128, //!< [EXPORT] : [COMMAND] Trigger test reply and test event
|
||||||
|
MULTIPLE_EVENT_TRIGGER_TEST = 129, //!< [EXPORT] : [COMMAND] Trigger multiple events (5)
|
||||||
|
MULTIPLE_CONNECTION_TEST = 130 //!< [EXPORT] : [COMMAND] Trigger multiple connection tests
|
||||||
|
};
|
||||||
|
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
from fsfwgen.parserbase.file_list_parser import FileListParser
|
||||||
|
from fsfwgen.parserbase.parser import FileParser
|
||||||
|
from utility.mib_csv_writer import CsvWriter
|
||||||
|
from utility.mib_printer import Printer
|
||||||
|
|
||||||
|
SUBSERVICE_DEFINITION_DESTINATION = ["../../mission/", "../../fsfw/pus/"]
|
||||||
|
SUBSERVICE_CSV_NAME = "mib_subservices.csv"
|
||||||
|
SUBSERVICE_COLUMN_HEADER = ["Service", "Subservice Name", "Subservice Number", "Type", "Comment"]
|
||||||
|
|
||||||
|
SQL_DELETE_SUBSVC_CMD = """
|
||||||
|
DROP TABLE IF EXISTS Subservice;
|
||||||
|
"""
|
||||||
|
|
||||||
|
SQL_CREATE_SUBSVC_CMD = """
|
||||||
|
CREATE TABLE IF NOT EXISTS Subservice(
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
service INTEGER,
|
||||||
|
subsvcName TEXT,
|
||||||
|
subsvcNumber INTEGER,
|
||||||
|
type TEXT CHECK( type IN ('TC','TM')),
|
||||||
|
comment TEXT
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
|
SQL_INSERT_INTO_SUBSVC_CMD = """
|
||||||
|
INSERT INTO Subservice(service,subsvcName,subsvcNumber,type,comment)
|
||||||
|
VALUES(?,?,?,?,?)
|
||||||
|
"""
|
||||||
|
|
||||||
|
class SubserviceColumns(Enum):
|
||||||
|
"""
|
||||||
|
Specifies order of MIB columns
|
||||||
|
"""
|
||||||
|
SERVICE = 0
|
||||||
|
NAME = 1
|
||||||
|
NUMBER = 2
|
||||||
|
TYPE = 3
|
||||||
|
COMMENT = 4
|
||||||
|
|
||||||
|
|
||||||
|
Clmns = SubserviceColumns
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
If this file is run separately, this main will be run.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
header_parser = FileListParser(SUBSERVICE_DEFINITION_DESTINATION)
|
||||||
|
header_file_list = header_parser.parse_header_files(False, "Parsing subservice header files: ")
|
||||||
|
packet_subservice_parser = SubserviceParser(header_file_list)
|
||||||
|
subservice_table = packet_subservice_parser.parse_files()
|
||||||
|
Printer.print_content(subservice_table, "Printing subservice table:")
|
||||||
|
print("Found " + str(len(subservice_table)) + " subservice entries.")
|
||||||
|
subservice_writer = CsvWriter(SUBSERVICE_CSV_NAME, subservice_table, SUBSERVICE_COLUMN_HEADER)
|
||||||
|
subservice_writer.write_to_csv()
|
||||||
|
subservice_writer.move_csv("..")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Not really happy with the multi-line implementation, but this is not trivial..
|
||||||
|
# Right not, we are not using the last lines stored, we just store the string
|
||||||
|
# of the last line (if its only a comment). It propably would be better to always
|
||||||
|
# scan 3 or 4 lines at once. However, this is not easy too..
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
class SubserviceParser(FileParser):
|
||||||
|
"""
|
||||||
|
This parser class can parse the subservice definitions.
|
||||||
|
"""
|
||||||
|
def __init__(self, file_list: list):
|
||||||
|
super().__init__(file_list)
|
||||||
|
# Column System allows reshuffling of table columns in constructor
|
||||||
|
self.clmns_len = SubserviceColumns.__len__()
|
||||||
|
# this table includes the current new table entry,
|
||||||
|
# which will be updated for target parameter
|
||||||
|
self.dict_entry_list = list(range(self.clmns_len))
|
||||||
|
self.dict_entry_list[Clmns.COMMENT.value] = ""
|
||||||
|
self.subservice_enum_found = False
|
||||||
|
# This list will store the last three lines for longer comments.
|
||||||
|
self.last_line_list = ["", "", ""]
|
||||||
|
# If an export command was found, cache the possibility of a match.
|
||||||
|
self.possible_match_on_next_lines = False
|
||||||
|
|
||||||
|
# This is called for every file
|
||||||
|
def _handle_file_parsing(self, file_name: str, *args: any, **kwargs):
|
||||||
|
self_print_parsing_info = False
|
||||||
|
if len(args) == 1 and isinstance(args[0], bool):
|
||||||
|
self_print_parsing_info = args[0]
|
||||||
|
|
||||||
|
# Read service from file name
|
||||||
|
service_match = re.search('Service[^0-9]*([0-9]{1,3})', file_name)
|
||||||
|
if service_match:
|
||||||
|
self.dict_entry_list[Clmns.SERVICE.value] = service_match.group(1)
|
||||||
|
self.dict_entry_list[Clmns.NAME.value] = " "
|
||||||
|
file = open(file_name, "r")
|
||||||
|
if self_print_parsing_info:
|
||||||
|
print("Parsing " + file_name + " ...")
|
||||||
|
# Scans each line for possible variables
|
||||||
|
for line in file.readlines():
|
||||||
|
self.__handle_line_reading(line)
|
||||||
|
|
||||||
|
def __handle_line_reading(self, line):
|
||||||
|
"""
|
||||||
|
Handles the reading of single lines.
|
||||||
|
:param line:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# Case insensitive matching
|
||||||
|
enum_match = re.search(r'[\s]*enum[\s]*Subservice([^\n]*)', line, re.IGNORECASE)
|
||||||
|
if enum_match:
|
||||||
|
self.subservice_enum_found = True
|
||||||
|
if self.subservice_enum_found:
|
||||||
|
self.__handle_enum_scanning(line)
|
||||||
|
self.last_line_list[2] = self.last_line_list[1]
|
||||||
|
self.last_line_list[1] = self.last_line_list[0]
|
||||||
|
self.last_line_list[0] = line
|
||||||
|
|
||||||
|
def __handle_enum_scanning(self, line: str):
|
||||||
|
"""
|
||||||
|
Two-line reading. First check last line. For export command.
|
||||||
|
"""
|
||||||
|
self.__scan_for_export_command(self.last_line_list[0])
|
||||||
|
subservice_match = self.__scan_subservices(line)
|
||||||
|
if subservice_match:
|
||||||
|
self.index = self.index + 1
|
||||||
|
dict_entry_tuple = tuple(self.dict_entry_list[:self.clmns_len])
|
||||||
|
self.mib_table.update({self.index: dict_entry_tuple})
|
||||||
|
self.__clear_tuple()
|
||||||
|
|
||||||
|
def __clear_tuple(self):
|
||||||
|
self.dict_entry_list[Clmns.NAME.value] = ""
|
||||||
|
self.dict_entry_list[Clmns.TYPE.value] = ""
|
||||||
|
self.dict_entry_list[Clmns.NUMBER.value] = ""
|
||||||
|
self.dict_entry_list[Clmns.COMMENT.value] = ""
|
||||||
|
self.possible_match_on_next_lines = False
|
||||||
|
|
||||||
|
|
||||||
|
def __scan_for_export_command(self, line: str) -> bool:
|
||||||
|
command_string = re.search(r"([^\[]*)\[export\][: ]*\[([\w]*)\][\s]*([^\n]*)",
|
||||||
|
line, re.IGNORECASE)
|
||||||
|
if command_string:
|
||||||
|
# Check whether there is a separated export command
|
||||||
|
# (export command is not on same line as subservice definition)
|
||||||
|
# ugly solution but has worked so far.
|
||||||
|
string = command_string.group(1).lstrip()
|
||||||
|
if len(string) <= 8:
|
||||||
|
self.possible_match_on_next_lines = True
|
||||||
|
if self.__scan_for_type(line):
|
||||||
|
self.__scan_for_comment(line)
|
||||||
|
return True
|
||||||
|
self.__add_possible_comment_string(line)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __add_possible_comment_string(self, line):
|
||||||
|
"""
|
||||||
|
If no command was found, the line might be a continuation of a comment.
|
||||||
|
Strip whitespaces and comment symbols and add to comment buffer.
|
||||||
|
"""
|
||||||
|
possible_multiline_comment = line.lstrip()
|
||||||
|
possible_multiline_comment = possible_multiline_comment.lstrip('/')
|
||||||
|
possible_multiline_comment = possible_multiline_comment.lstrip('<')
|
||||||
|
possible_multiline_comment = possible_multiline_comment.lstrip('!')
|
||||||
|
possible_multiline_comment = possible_multiline_comment.rstrip()
|
||||||
|
if len(possible_multiline_comment) > 0:
|
||||||
|
self.dict_entry_list[Clmns.COMMENT.value] += possible_multiline_comment
|
||||||
|
|
||||||
|
def __scan_subservices(self, line):
|
||||||
|
"""
|
||||||
|
Scan for subservice match.
|
||||||
|
:param line:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
subservice_match = \
|
||||||
|
re.search(r"[\s]*([\w]*)[\s]*=[\s]*([0-9]{1,3})(?:,)?(?:[ /!<>]*([^\n]*))?", line)
|
||||||
|
if subservice_match:
|
||||||
|
self.dict_entry_list[Clmns.NAME.value] = subservice_match.group(1)
|
||||||
|
self.dict_entry_list[Clmns.NUMBER.value] = subservice_match.group(2)
|
||||||
|
# I am assuming that an export string is longer than 7 chars.
|
||||||
|
if len(subservice_match.group(3)) > 7:
|
||||||
|
# Export command on same line overrides old commands. Read for comment.
|
||||||
|
if self.__process_comment_string(subservice_match.group(3)):
|
||||||
|
return True
|
||||||
|
# Check whether exporting was commanded on last lines
|
||||||
|
return bool(self.possible_match_on_next_lines)
|
||||||
|
if re.search(r'}[\s]*;', line):
|
||||||
|
self.subservice_enum_found = False
|
||||||
|
return subservice_match
|
||||||
|
|
||||||
|
def __process_comment_string(self, comment_string) -> bool:
|
||||||
|
# look for packet type specifier
|
||||||
|
export_command_found = self.__scan_for_type(comment_string)
|
||||||
|
# Look for everything after [EXPORT] : [TYPESPECIFIER] as comment
|
||||||
|
if export_command_found:
|
||||||
|
self.__scan_for_comment(comment_string)
|
||||||
|
return export_command_found
|
||||||
|
|
||||||
|
def __scan_for_type(self, string) -> bool:
|
||||||
|
type_match = re.search(r'\[reply\]|\[tm\]', string, re.IGNORECASE)
|
||||||
|
if type_match:
|
||||||
|
self.dict_entry_list[Clmns.TYPE.value] = 'TM'
|
||||||
|
return True
|
||||||
|
type_match = re.search(r'\[command\]|\[tc\]', string, re.IGNORECASE)
|
||||||
|
if type_match:
|
||||||
|
self.dict_entry_list[Clmns.TYPE.value] = 'TC'
|
||||||
|
return True
|
||||||
|
self.dict_entry_list[Clmns.TYPE.value] = 'Unspecified'
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __scan_for_comment(self, comment_string):
|
||||||
|
comment_match = re.search(r':[\s]*\[[\w]*\][\s]*([^\n]*)', comment_string)
|
||||||
|
if comment_match:
|
||||||
|
self.dict_entry_list[Clmns.COMMENT.value] = comment_match.group(1)
|
||||||
|
|
||||||
|
def _post_parsing_operation(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
0
generators/utility/__init__.py
Normal file
0
generators/utility/__init__.py
Normal file
18
generators/utility/mib_globals.py
Normal file
18
generators/utility/mib_globals.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
"""
|
||||||
|
@file
|
||||||
|
mib_globals.py
|
||||||
|
@date
|
||||||
|
16.11.2019
|
||||||
|
@brief
|
||||||
|
Global settings for MIB exporter
|
||||||
|
"""
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
|
||||||
|
doExportMiB = True
|
||||||
|
executeSQLcommands = False
|
||||||
|
printToConsole = True
|
||||||
|
exportToCSV = True
|
||||||
|
doCopyFile = False
|
||||||
|
copyDestination = "."
|
||||||
|
fileSeparator = ';'
|
Loading…
x
Reference in New Issue
Block a user