Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2316b3c299 |
No files matched your search
@@ -8,18 +8,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
## Fixed
|
||||
|
||||
- Moving window parsers dropped the last `moving_window_size - 1 - center_idx` lines of every
|
||||
file, so events and returnvalues declared near the end of a header were silently missing from
|
||||
the generated tables. The post-EOF loop shifted the window but never ran the analysis on it,
|
||||
and it cleared trailing entries before shifting, which overwrote lines that had not reached
|
||||
the window centre yet.
|
||||
|
||||
# [v0.4.0]
|
||||
|
||||
- Update event handling for new `constexpr` templated arguments
|
||||
|
||||
# [v0.3.4]
|
||||
|
||||
- Hotfixes for pyproject.toml file
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import re
|
||||
import sys
|
||||
import enum
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import List, Optional, Dict
|
||||
@@ -16,6 +16,25 @@ SUBSYSTEM_ID_NAMESPACE = "SUBSYSTEM_ID"
|
||||
EVENT_NAME_IDX = 1
|
||||
|
||||
|
||||
class Severity(enum.IntEnum):
|
||||
INFO = 0
|
||||
LOW = 1
|
||||
MEDIUM = 2
|
||||
HIGH = 3
|
||||
|
||||
|
||||
def severity_str_to_enum(severity: str) -> Severity | None:
|
||||
if severity == "INFO":
|
||||
return Severity.INFO
|
||||
if severity == "LOW":
|
||||
return Severity.LOW
|
||||
if severity == "MEDIUM":
|
||||
return Severity.MEDIUM
|
||||
if severity == "HIGH":
|
||||
return Severity.HIGH
|
||||
return None
|
||||
|
||||
|
||||
class SubsystemDefinitionParser(FileParser):
|
||||
def __init__(self, file_list):
|
||||
super().__init__(file_list)
|
||||
@@ -48,16 +67,15 @@ class SubsystemDefinitionParser(FileParser):
|
||||
|
||||
|
||||
class EventEntry:
|
||||
def __init__(self, name: str, subsystem: int, severity: str, description: str, file_name: Path):
|
||||
def __init__(self, name: str, severity: str, description: str, file_name: Path):
|
||||
self.name = name
|
||||
self.subsystem = subsystem
|
||||
self.severity = severity
|
||||
self.description = description
|
||||
self.file_name = file_name
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
f"EventEntry(name={self.name!r}, subsystem={self.subsystem!r}, severity={self.severity!r}, "
|
||||
f"EventEntry(name={self.name!r}, severity={self.severity!r}, "
|
||||
f"description={self.description!r}, file_name={self.file_name!r}"
|
||||
)
|
||||
|
||||
@@ -71,9 +89,8 @@ class EventParser(FileParser):
|
||||
self.set_moving_window_mode(moving_window_size)
|
||||
self.interfaces = interface_list
|
||||
self.count = 0
|
||||
self.subsystem_id = None
|
||||
self.current_id = None
|
||||
self.current_file = None
|
||||
self.current_group_id = 0
|
||||
self.current_unique_id = 0
|
||||
self.mib_table: EventDictT = dict()
|
||||
self.obsw_root_path: Optional[Path] = None
|
||||
self.last_lines = ["", "", ""]
|
||||
@@ -91,10 +108,6 @@ class EventParser(FileParser):
|
||||
*args,
|
||||
**kwargs,
|
||||
):
|
||||
if file_name != self.current_file:
|
||||
self.current_file = file_name
|
||||
self.subsystem_id = None
|
||||
self.current_id = None
|
||||
subsystem_id_assignment_match = re.search(
|
||||
rf"{SUBSYSTEM_ID_NAMESPACE}::([A-Z_0-9]*)",
|
||||
moving_window[self.moving_window_center_idx],
|
||||
@@ -103,8 +116,8 @@ class EventParser(FileParser):
|
||||
# For now, it is assumed that there is only going to be one subsystem ID per
|
||||
# class / source file
|
||||
try:
|
||||
self.current_id = self.interfaces[subsystem_id_assignment_match.group(1)][0]
|
||||
self.subsystem_id = self.return_number_from_string(self.current_id)
|
||||
self.current_group_id = self.interfaces[subsystem_id_assignment_match.group(1)][0]
|
||||
self.current_group_id = self.return_number_from_string(self.current_group_id)
|
||||
except KeyError as e:
|
||||
print(f"Key not found: {e}")
|
||||
# Now try to look for event definitions. Moving windows allows multi line event definitions
|
||||
@@ -161,20 +174,30 @@ class EventParser(FileParser):
|
||||
elif meta.type == MetaType.DESC:
|
||||
description = meta.value
|
||||
if event_full_match:
|
||||
if self.subsystem_id is None:
|
||||
_LOGGER.error("Subsystem ID not set, cannot parse event")
|
||||
sys.exit(1)
|
||||
name = event_match.group(EVENT_NAME_IDX)
|
||||
if macro_api_match:
|
||||
full_id = (self.subsystem_id * 100) + self.return_number_from_string(
|
||||
event_full_match.group(2)
|
||||
)
|
||||
severity = event_full_match.group(3)
|
||||
else:
|
||||
full_id = (self.subsystem_id * 100) + self.return_number_from_string(
|
||||
event_full_match.group(3)
|
||||
severity_num = severity_str_to_enum(severity)
|
||||
if severity_num is None:
|
||||
raise ValueError(f"Unknown severity: {severity}")
|
||||
full_id = (
|
||||
(severity_num << 30)
|
||||
| (self.current_group_id << 16)
|
||||
| self.return_number_from_string(event_full_match.group(2))
|
||||
)
|
||||
else:
|
||||
severity = event_full_match.group(4)
|
||||
severity_num = severity_str_to_enum(severity)
|
||||
if severity_num is None:
|
||||
raise ValueError(f"Unknown severity: {severity}")
|
||||
if event_full_match.group(1) == "EV_REPLY_INVALID_SIZE":
|
||||
print(f"Group 3: {event_full_match.group(3)}")
|
||||
full_id = (
|
||||
(severity_num << 30)
|
||||
| (self.current_group_id << 16)
|
||||
| self.return_number_from_string(event_full_match.group(3))
|
||||
)
|
||||
|
||||
if self.obsw_root_path is not None:
|
||||
file_name = file_name.relative_to(self.obsw_root_path)
|
||||
if self.mib_table.get(full_id) is not None:
|
||||
@@ -183,7 +206,7 @@ class EventParser(FileParser):
|
||||
f"Name: {self.mib_table.get(full_id).name}| "
|
||||
f"Description: {self.mib_table.get(full_id).description}"
|
||||
)
|
||||
self.mib_table.update({full_id: EventEntry(name, self.subsystem_id, severity, description, file_name)})
|
||||
self.mib_table.update({full_id: EventEntry(name, severity, description, file_name)})
|
||||
self.count = self.count + 1
|
||||
|
||||
@staticmethod
|
||||
@@ -194,20 +217,9 @@ class EventParser(FileParser):
|
||||
r"static const(?:expr)? Event[\s]*([\w]*)[\s]*=[\s]*"
|
||||
r"MAKE_EVENT\((0x[0-9a-fA-F]+|[0-9]{1,3}),[\s]*severity::([A-Z]*)\)[\s]*;"
|
||||
)
|
||||
return re.search(regex_string, full_string)
|
||||
|
||||
# Non compiletime const version kept for backwards compatibility
|
||||
regex_string = r"static const(?:expr)? Event\s*([\w]+)\s*=\s*event::makeEvent\(([\w:]+),\s*(0x[0-9a-fA-F]+|[0-9]{1,3})\s*,\s*severity::([A-Z]+)\)\s*;"
|
||||
else:
|
||||
regex_string = r"static const(?:expr)? Event\s*([\w]+)\s*=\s*event::makeEvent\(([\w:]+),\s*(0x[0-9a-fA-F]+|[0-9]{1,3})\s*,\s*severity::([A-Z]+)\)\s*;"
|
||||
event_full_match = re.search(regex_string, full_string)
|
||||
|
||||
# Using old, non compiletime const version
|
||||
if event_full_match:
|
||||
return event_full_match
|
||||
|
||||
# Using compiletime const version
|
||||
regex_string = r"static const(?:expr)? Event\s*([\w]+)\s*=\s*event::makeEvent<([\w:]+),\s*(0x[0-9a-fA-F]+|[0-9]{1,3})\s*,\s*severity::([A-Z]+)>\(\)\s*;"
|
||||
event_full_match = re.search(regex_string, full_string)
|
||||
|
||||
return event_full_match
|
||||
|
||||
def __build_multi_line_event_string(self, first_line: str, moving_window: List[str]) -> str:
|
||||
@@ -273,13 +285,15 @@ def export_to_csv(filename: Path, event_list: EventDictT, col_sep: str):
|
||||
|
||||
|
||||
def write_translation_source_file(
|
||||
event_list: EventDictT, date_string: str, filename: Path = "translateEvents.cpp"
|
||||
event_list: EventDictT,
|
||||
date_string: str,
|
||||
filename: Path = Path("translateEvents.cpp"),
|
||||
):
|
||||
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"
|
||||
function = "const char *translateEvents(Event event) {\n switch (event) {\n"
|
||||
for entry in event_list.items():
|
||||
event_id = entry[0]
|
||||
event_value = entry[1]
|
||||
@@ -291,8 +305,8 @@ def write_translation_source_file(
|
||||
_LOGGER.warning(f"Name: {name}, Event Entry: {event_value}")
|
||||
name = f"{name}_{event_id}"
|
||||
_LOGGER.info(f"Created unique name {name}")
|
||||
definitions += f"const char *{name}_STRING " f'= "{name}";\n'
|
||||
function += f" case ({event_id}):\n " f"return {name}_STRING;\n"
|
||||
definitions += f'const char *{name}_STRING = "{name}";\n'
|
||||
function += f" case ({event_id}):\n return {name}_STRING;\n"
|
||||
lut.update({name: event_value})
|
||||
function += ' default:\n return "UNKNOWN_EVENT";\n'
|
||||
out.write(
|
||||
@@ -305,7 +319,7 @@ def write_translation_source_file(
|
||||
out.write(definitions + "\n" + function + " }\n return 0;\n}\n")
|
||||
|
||||
|
||||
def write_translation_header_file(filename: Path = "translateEvents.h"):
|
||||
def write_translation_header_file(filename: Path = Path("translateEvents.h")):
|
||||
with open(filename, "w") as out:
|
||||
out.write(
|
||||
f"#ifndef FSFWCONFIG_EVENTS_TRANSLATEEVENTS_H_\n"
|
||||
|
||||
@@ -198,31 +198,21 @@ class FileParser:
|
||||
self._handle_file_parsing_moving_window(
|
||||
file_name, line_idx, moving_window_size, moving_window, *args, **kwargs
|
||||
)
|
||||
# Now the moving window moves past the end of the file, with empty strings shifted in
|
||||
# from beyond EOF. This has to keep calling the analysis: the loop above only ever gets
|
||||
# the window centre as far as the line moving_window_size - 1 - center_idx from the end,
|
||||
# so without this the last few lines of every file are never looked at and whatever they
|
||||
# declare is dropped without a warning.
|
||||
# Now the moving window moved past the end of the file. Sections which are outside
|
||||
# the file are assigned an empty string until the window has moved out of file completely
|
||||
for remaining_windows_idx in range(moving_window_size):
|
||||
if self.__debug_moving_window and self.__debug_moving_window_filename in file_name:
|
||||
print("Moving window pre line analysis post EOF")
|
||||
print(moving_window)
|
||||
# Shift by one, discarding the oldest line and appending the empty line which is now
|
||||
# past the end of the file. The previous implementation cleared trailing entries
|
||||
# before shifting, which overwrote lines that had not reached the centre yet.
|
||||
moving_window.pop(0)
|
||||
moving_window.append("")
|
||||
num_entries_to_clear = remaining_windows_idx + 1
|
||||
for idx_to_clear in range(num_entries_to_clear):
|
||||
moving_window[moving_window_size - 1 - idx_to_clear] = ""
|
||||
for idx_to_reassign in range(moving_window_size - 1 - num_entries_to_clear):
|
||||
moving_window[idx_to_reassign] = moving_window[idx_to_reassign + 1]
|
||||
if self.__debug_moving_window and self.__debug_moving_window_filename in file_name:
|
||||
print("Moving window post line analysis post EOF")
|
||||
print(moving_window)
|
||||
self._handle_file_parsing_moving_window(
|
||||
file_name,
|
||||
len(all_lines) + remaining_windows_idx,
|
||||
moving_window_size,
|
||||
moving_window,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def _open_file(file_name: Path) -> list:
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
|
||||
[project]
|
||||
name = "fsfwgen"
|
||||
description = "FSFW Generator Core"
|
||||
version = "0.4.0"
|
||||
version = "0.3.4"
|
||||
license = { text = "Apache-2.0" }
|
||||
authors = [
|
||||
{name = "Robin Mueller", email = "robin.mueller.m@gmail.com"}
|
||||
|
||||
Reference in new issue
Block a user