-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* loading channels working - minus glutton of choice * Handle struct member arrays (inline) * Add JsonLoader base type * working MVP for all cmd/channels/events * Remove commented out code * Update for latest JSON format * Formatting * Fix Python<3.10 compatibility (remove match statement) * Translate format strings at load-time * Remove tuple type hint that break Python3.8 * Fix CodeQL warnings in test code * spelling * Fix changed test case for more surface area * Formatting * Fix get_versions() * reorganize code * Improve behavior of default command selection * Prioritize selection of JSON dictionary over XML * Cache parsed_types in JsonLoader class * Add test cases * ignore some spelling * Code cleanup and formatting * Remove "tag" terminology * Exclude dictionary from spelling * few review notes * case-insensitive sorting in commandList * Improve error handling * Sort dictionaries at load time
- Loading branch information
Showing
19 changed files
with
10,621 additions
and
132 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
""" | ||
ch_json_loader.py: | ||
Loads flight dictionary (JSON) and returns id and mnemonic based Python dictionaries of channels | ||
@author thomas-bc | ||
""" | ||
|
||
from fprime_gds.common.templates.ch_template import ChTemplate | ||
from fprime_gds.common.loaders.json_loader import JsonLoader | ||
from fprime_gds.common.data_types.exceptions import GdsDictionaryParsingException | ||
|
||
|
||
class ChJsonLoader(JsonLoader): | ||
"""Class to load python based telemetry channel dictionaries""" | ||
|
||
CHANNELS_FIELD = "telemetryChannels" | ||
|
||
ID = "id" | ||
NAME = "name" | ||
DESC = "annotation" | ||
TYPE = "type" | ||
FMT_STR = "format" | ||
LIMIT_FIELD = "limit" | ||
LIMIT_LOW = "low" | ||
LIMIT_HIGH = "high" | ||
LIMIT_RED = "red" | ||
LIMIT_ORANGE = "orange" | ||
LIMIT_YELLOW = "yellow" | ||
|
||
def construct_dicts(self, _): | ||
""" | ||
Constructs and returns python dictionaries keyed on id and name | ||
Args: | ||
_: Unused argument (inherited) | ||
Returns: | ||
A tuple with two channel dictionaries (python type dict): | ||
(id_dict, name_dict). The keys should be the channels' id and | ||
name fields respectively and the values should be ChTemplate | ||
objects. | ||
""" | ||
id_dict = {} | ||
name_dict = {} | ||
|
||
if self.CHANNELS_FIELD not in self.json_dict: | ||
raise GdsDictionaryParsingException( | ||
f"Ground Dictionary missing '{self.CHANNELS_FIELD}' field: {str(self.json_file)}" | ||
) | ||
|
||
for ch_dict in self.json_dict[self.CHANNELS_FIELD]: | ||
# Create a channel template object | ||
ch_temp = self.construct_template_from_dict(ch_dict) | ||
|
||
id_dict[ch_temp.get_id()] = ch_temp | ||
name_dict[ch_temp.get_full_name()] = ch_temp | ||
|
||
return ( | ||
dict(sorted(id_dict.items())), | ||
dict(sorted(name_dict.items())), | ||
self.get_versions(), | ||
) | ||
|
||
def construct_template_from_dict(self, channel_dict: dict) -> ChTemplate: | ||
try: | ||
ch_id = channel_dict[self.ID] | ||
# The below assignment also raises a ValueError if the name does not contain a '.' | ||
component_name, channel_name = channel_dict[self.NAME].split(".") | ||
if not component_name or not channel_name: | ||
raise ValueError() | ||
|
||
type_obj = self.parse_type(channel_dict[self.TYPE]) | ||
except ValueError as e: | ||
raise GdsDictionaryParsingException( | ||
f"Channel dictionary entry malformed, expected name of the form '<COMP_NAME>.<CH_NAME>' in : {str(channel_dict)}" | ||
) | ||
except KeyError as e: | ||
raise GdsDictionaryParsingException( | ||
f"{str(e)} key missing from Channel dictionary entry or its associated type in the dictionary: {str(channel_dict)}" | ||
) | ||
|
||
format_str = JsonLoader.preprocess_format_str(channel_dict.get(self.FMT_STR)) | ||
|
||
limit_field = channel_dict.get(self.LIMIT_FIELD) | ||
limit_low = limit_field.get(self.LIMIT_LOW) if limit_field else None | ||
limit_high = limit_field.get(self.LIMIT_HIGH) if limit_field else None | ||
limit_low_yellow = limit_low.get(self.LIMIT_YELLOW) if limit_low else None | ||
limit_low_red = limit_low.get(self.LIMIT_RED) if limit_low else None | ||
limit_low_orange = limit_low.get(self.LIMIT_ORANGE) if limit_low else None | ||
limit_high_yellow = limit_high.get(self.LIMIT_YELLOW) if limit_high else None | ||
limit_high_red = limit_high.get(self.LIMIT_RED) if limit_high else None | ||
limit_high_orange = limit_high.get(self.LIMIT_ORANGE) if limit_high else None | ||
|
||
return ChTemplate( | ||
ch_id, | ||
channel_name, | ||
component_name, | ||
type_obj, | ||
ch_fmt_str=format_str, | ||
ch_desc=channel_dict.get(self.DESC), | ||
low_red=limit_low_red, | ||
low_orange=limit_low_orange, | ||
low_yellow=limit_low_yellow, | ||
high_yellow=limit_high_yellow, | ||
high_orange=limit_high_orange, | ||
high_red=limit_high_red, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
""" | ||
cmd_json_loader.py: | ||
Loads flight dictionary (JSON) and returns id and mnemonic based Python dictionaries of commands | ||
@author thomas-bc | ||
""" | ||
|
||
from fprime_gds.common.templates.cmd_template import CmdTemplate | ||
from fprime_gds.common.loaders.json_loader import JsonLoader | ||
from fprime_gds.common.data_types.exceptions import GdsDictionaryParsingException | ||
|
||
|
||
class CmdJsonLoader(JsonLoader): | ||
"""Class to load xml based command dictionaries""" | ||
|
||
COMMANDS_FIELD = "commands" | ||
|
||
NAME = "name" | ||
OPCODE = "opcode" | ||
DESC = "annotation" | ||
PARAMETERS = "formalParams" | ||
|
||
def construct_dicts(self, _): | ||
""" | ||
Constructs and returns python dictionaries keyed on id and name | ||
Args: | ||
_: Unused argument (inherited) | ||
Returns: | ||
A tuple with two command dictionaries (python type dict): | ||
(id_dict, name_dict). The keys are the events' id and name fields | ||
respectively and the values are CmdTemplate objects | ||
""" | ||
id_dict = {} | ||
name_dict = {} | ||
|
||
if self.COMMANDS_FIELD not in self.json_dict: | ||
raise GdsDictionaryParsingException( | ||
f"Ground Dictionary missing '{self.COMMANDS_FIELD}' field: {str(self.json_file)}" | ||
) | ||
|
||
for cmd_dict in self.json_dict[self.COMMANDS_FIELD]: | ||
cmd_temp = self.construct_template_from_dict(cmd_dict) | ||
|
||
id_dict[cmd_temp.get_id()] = cmd_temp | ||
name_dict[cmd_temp.get_full_name()] = cmd_temp | ||
|
||
return ( | ||
dict(sorted(id_dict.items())), | ||
dict(sorted(name_dict.items())), | ||
self.get_versions(), | ||
) | ||
|
||
def construct_template_from_dict(self, cmd_dict: dict) -> CmdTemplate: | ||
try: | ||
cmd_comp, cmd_mnemonic = cmd_dict[self.NAME].split(".") | ||
cmd_opcode = cmd_dict[self.OPCODE] | ||
cmd_desc = cmd_dict.get(self.DESC) | ||
except ValueError as e: | ||
raise GdsDictionaryParsingException( | ||
f"Command dictionary entry malformed, expected name of the form '<COMP_NAME>.<CMD_NAME>' in : {str(cmd_dict)}" | ||
) | ||
except KeyError as e: | ||
raise GdsDictionaryParsingException( | ||
f"{str(e)} key missing from Command dictionary entry: {str(cmd_dict)}" | ||
) | ||
# Parse Arguments | ||
cmd_args = [] | ||
for param in cmd_dict.get(self.PARAMETERS, []): | ||
try: | ||
param_name = param["name"] | ||
param_type = self.parse_type(param["type"]) | ||
except KeyError as e: | ||
raise GdsDictionaryParsingException( | ||
f"{str(e)} key missing from Command parameter or its associated type in the dictionary: {str(param)}" | ||
) | ||
cmd_args.append( | ||
( | ||
param_name, | ||
param.get("annotation"), | ||
param_type, | ||
) | ||
) | ||
return CmdTemplate(cmd_opcode, cmd_mnemonic, cmd_comp, cmd_args, cmd_desc) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.