fprime-gds 3.4.3__py3-none-any.whl → 3.4.4a2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fprime_gds/common/communication/adapters/base.py +30 -58
- fprime_gds/common/communication/adapters/ip.py +23 -5
- fprime_gds/common/communication/adapters/uart.py +20 -7
- fprime_gds/common/communication/checksum.py +1 -3
- fprime_gds/common/communication/framing.py +53 -4
- fprime_gds/common/data_types/event_data.py +6 -1
- fprime_gds/common/data_types/exceptions.py +16 -11
- fprime_gds/common/loaders/ch_json_loader.py +107 -0
- fprime_gds/common/loaders/ch_xml_loader.py +5 -5
- fprime_gds/common/loaders/cmd_json_loader.py +85 -0
- fprime_gds/common/loaders/dict_loader.py +1 -1
- fprime_gds/common/loaders/event_json_loader.py +108 -0
- fprime_gds/common/loaders/event_xml_loader.py +10 -6
- fprime_gds/common/loaders/json_loader.py +222 -0
- fprime_gds/common/loaders/xml_loader.py +31 -9
- fprime_gds/common/pipeline/dictionaries.py +38 -3
- fprime_gds/common/tools/seqgen.py +4 -4
- fprime_gds/common/utils/string_util.py +57 -65
- fprime_gds/common/zmq_transport.py +37 -20
- fprime_gds/executables/apps.py +150 -0
- fprime_gds/executables/cli.py +239 -103
- fprime_gds/executables/comm.py +17 -27
- fprime_gds/executables/data_product_writer.py +935 -0
- fprime_gds/executables/run_deployment.py +55 -14
- fprime_gds/executables/utils.py +24 -12
- fprime_gds/flask/sequence.py +1 -1
- fprime_gds/flask/static/addons/commanding/command-input.js +3 -2
- fprime_gds/plugin/__init__.py +0 -0
- fprime_gds/plugin/definitions.py +71 -0
- fprime_gds/plugin/system.py +225 -0
- {fprime_gds-3.4.3.dist-info → fprime_gds-3.4.4a2.dist-info}/METADATA +3 -2
- {fprime_gds-3.4.3.dist-info → fprime_gds-3.4.4a2.dist-info}/RECORD +37 -28
- {fprime_gds-3.4.3.dist-info → fprime_gds-3.4.4a2.dist-info}/WHEEL +1 -1
- {fprime_gds-3.4.3.dist-info → fprime_gds-3.4.4a2.dist-info}/entry_points.txt +2 -3
- {fprime_gds-3.4.3.dist-info → fprime_gds-3.4.4a2.dist-info}/LICENSE.txt +0 -0
- {fprime_gds-3.4.3.dist-info → fprime_gds-3.4.4a2.dist-info}/NOTICE.txt +0 -0
- {fprime_gds-3.4.3.dist-info → fprime_gds-3.4.4a2.dist-info}/top_level.txt +0 -0
fprime_gds/executables/cli.py
CHANGED
@@ -7,6 +7,7 @@ code that they are importing.
|
|
7
7
|
|
8
8
|
@author mstarch
|
9
9
|
"""
|
10
|
+
|
10
11
|
import argparse
|
11
12
|
import datetime
|
12
13
|
import errno
|
@@ -23,27 +24,14 @@ from typing import Any, Dict, List, Tuple
|
|
23
24
|
# Required to set the checksum as a module variable
|
24
25
|
import fprime_gds.common.communication.checksum
|
25
26
|
import fprime_gds.common.logger
|
26
|
-
from fprime_gds.common.communication.adapters.base import BaseAdapter
|
27
27
|
from fprime_gds.common.communication.adapters.ip import check_port
|
28
28
|
from fprime_gds.common.pipeline.standard import StandardPipeline
|
29
29
|
from fprime_gds.common.transport import ThreadedTCPSocketClient
|
30
30
|
from fprime_gds.common.utils.config_manager import ConfigManager
|
31
31
|
from fprime_gds.executables.utils import find_app, find_dict, get_artifacts_root
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
import zmq
|
36
|
-
|
37
|
-
from fprime_gds.common.zmq_transport import ZmqClient
|
38
|
-
except ImportError:
|
39
|
-
zmq = None
|
40
|
-
ZmqClient = None
|
41
|
-
|
42
|
-
# Optional import: Serial Adapter. Requires package: SerialAdapter
|
43
|
-
try:
|
44
|
-
from fprime_gds.common.communication.adapters.uart import SerialAdapter
|
45
|
-
except ImportError:
|
46
|
-
SerialAdapter = None
|
32
|
+
from fprime_gds.plugin.definitions import PluginType
|
33
|
+
from fprime_gds.plugin.system import Plugins
|
34
|
+
from fprime_gds.common.zmq_transport import ZmqClient
|
47
35
|
|
48
36
|
|
49
37
|
GUIS = ["none", "html"]
|
@@ -85,11 +73,31 @@ class ParserBase(ABC):
|
|
85
73
|
Return:
|
86
74
|
argparse parser for supplied arguments
|
87
75
|
"""
|
88
|
-
parser = argparse.ArgumentParser(
|
89
|
-
|
90
|
-
|
76
|
+
parser = argparse.ArgumentParser(
|
77
|
+
description=self.description,
|
78
|
+
add_help=True,
|
79
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
80
|
+
)
|
81
|
+
self.fill_parser(parser)
|
91
82
|
return parser
|
92
83
|
|
84
|
+
def fill_parser(self, parser):
|
85
|
+
""" Fill supplied parser with arguments
|
86
|
+
|
87
|
+
Fills the supplied parser with the arguments returned via the `get_arguments` method invocation. This
|
88
|
+
implementation add the arguments directly to the parser.
|
89
|
+
|
90
|
+
Args:
|
91
|
+
parser: parser to fill with arguments
|
92
|
+
|
93
|
+
"""
|
94
|
+
for flags, keywords in self.get_arguments().items():
|
95
|
+
try:
|
96
|
+
parser.add_argument(*flags, **keywords)
|
97
|
+
except argparse.ArgumentError:
|
98
|
+
# flag has already been added, pass
|
99
|
+
pass
|
100
|
+
|
93
101
|
def reproduce_cli_args(self, args_ns):
|
94
102
|
"""Reproduce the list of arguments needed on the command line"""
|
95
103
|
|
@@ -245,6 +253,162 @@ class DetectionParser(ParserBase):
|
|
245
253
|
return args
|
246
254
|
|
247
255
|
|
256
|
+
class PluginArgumentParser(ParserBase):
|
257
|
+
"""Parser for arguments coming from plugins"""
|
258
|
+
|
259
|
+
DESCRIPTION = "Plugin options"
|
260
|
+
FPRIME_CHOICES = {
|
261
|
+
"framing": "fprime",
|
262
|
+
"communication": "ip",
|
263
|
+
}
|
264
|
+
|
265
|
+
def __init__(self):
|
266
|
+
"""Initialize the plugin information for this parser"""
|
267
|
+
self._plugin_map = {
|
268
|
+
category: Plugins.system().get_plugins(category)
|
269
|
+
for category in Plugins.system().get_categories()
|
270
|
+
}
|
271
|
+
|
272
|
+
@staticmethod
|
273
|
+
def safe_add_argument(parser, *flags, **keywords):
|
274
|
+
""" Add an argument allowing duplicates
|
275
|
+
|
276
|
+
Add arguments to the parser (passes through *flags and **keywords) to the supplied parser. This method traps
|
277
|
+
errors to prevent duplicates.
|
278
|
+
|
279
|
+
Args:
|
280
|
+
parser: parser or argument group to add arguments to
|
281
|
+
*flags: positional arguments passed to `add_argument`
|
282
|
+
**keywords: key word arguments passed to `add_argument`
|
283
|
+
"""
|
284
|
+
try:
|
285
|
+
parser.add_argument(*flags, **keywords)
|
286
|
+
except argparse.ArgumentError:
|
287
|
+
# flag has already been added, pass
|
288
|
+
pass
|
289
|
+
|
290
|
+
def fill_parser(self, parser):
|
291
|
+
""" File supplied parser with grouped arguments
|
292
|
+
|
293
|
+
Fill the supplied parser with arguments from the `get_arguments` method invocation. This implementation groups
|
294
|
+
arguments based on the constituent that sources the argument.
|
295
|
+
|
296
|
+
Args:
|
297
|
+
parser: parser to fill
|
298
|
+
"""
|
299
|
+
for category, plugins in self._plugin_map.items():
|
300
|
+
argument_group = parser.add_argument_group(title=f"{category.title()} Plugin Options")
|
301
|
+
for flags, keywords in self.get_category_arguments(category).items():
|
302
|
+
self.safe_add_argument(argument_group, *flags, **keywords)
|
303
|
+
|
304
|
+
for plugin in plugins:
|
305
|
+
argument_group = parser.add_argument_group(title=f"{category.title()} Plugin '{plugin.get_name()}' Options")
|
306
|
+
if plugin.type == PluginType.FEATURE:
|
307
|
+
self.safe_add_argument(argument_group,
|
308
|
+
f"--disable-{plugin.get_name()}",
|
309
|
+
action="store_true",
|
310
|
+
default=False,
|
311
|
+
help=f"Disable the {category} plugin '{plugin.get_name()}'")
|
312
|
+
for flags, keywords in plugin.get_arguments().items():
|
313
|
+
self.safe_add_argument(argument_group, *flags, **keywords)
|
314
|
+
|
315
|
+
def get_category_arguments(self, category):
|
316
|
+
""" Get arguments for a plugin category """
|
317
|
+
arguments: Dict[Tuple[str, ...], Dict[str, Any]] = {}
|
318
|
+
plugins = self._plugin_map[category]
|
319
|
+
# Add category options: SELECTION plugins add a selection flag
|
320
|
+
plugin_type = Plugins.get_category_plugin_type(category)
|
321
|
+
if plugin_type == PluginType.SELECTION:
|
322
|
+
arguments.update(
|
323
|
+
{
|
324
|
+
(f"--{category}-selection",): {
|
325
|
+
"choices": [choice.get_name() for choice in plugins],
|
326
|
+
"help": f"Select {category} implementer.",
|
327
|
+
"default": self.FPRIME_CHOICES.get(
|
328
|
+
category, list(plugins)[0].get_name()
|
329
|
+
),
|
330
|
+
}
|
331
|
+
}
|
332
|
+
)
|
333
|
+
return arguments
|
334
|
+
|
335
|
+
def get_arguments(self) -> Dict[Tuple[str, ...], Dict[str, Any]]:
|
336
|
+
"""Return arguments to used in plugins"""
|
337
|
+
arguments: Dict[Tuple[str, ...], Dict[str, Any]] = {}
|
338
|
+
for category, plugins in self._plugin_map.items():
|
339
|
+
arguments.update(self.get_category_arguments(category))
|
340
|
+
for plugin in plugins:
|
341
|
+
# Add disable flags for feature type plugins
|
342
|
+
if plugin.type == PluginType.FEATURE:
|
343
|
+
arguments.update({
|
344
|
+
(f"--disable-{plugin.get_name()}", ): {
|
345
|
+
"action": "store_true",
|
346
|
+
"default": False,
|
347
|
+
"help": f"Disable the {category} plugin '{plugin.get_name()}'"
|
348
|
+
}
|
349
|
+
})
|
350
|
+
arguments.update(plugin.get_arguments())
|
351
|
+
return arguments
|
352
|
+
|
353
|
+
def handle_arguments(self, args, **kwargs):
|
354
|
+
"""Handles the arguments"""
|
355
|
+
for category, plugins in self._plugin_map.items():
|
356
|
+
plugin_type = Plugins.get_category_plugin_type(category)
|
357
|
+
|
358
|
+
# Selection plugins choose one plugin and instantiate it
|
359
|
+
if plugin_type == PluginType.SELECTION:
|
360
|
+
selection_string = getattr(args, f"{category}_selection")
|
361
|
+
matching_plugins = [plugin for plugin in plugins if plugin.get_name() == selection_string]
|
362
|
+
assert len(matching_plugins) == 1, "Plugin selection system failed"
|
363
|
+
selection_class = matching_plugins[0].plugin_class
|
364
|
+
filled_arguments = self.extract_plugin_arguments(args, selection_class)
|
365
|
+
selection_instance = selection_class(**filled_arguments)
|
366
|
+
setattr(args, f"{category}_selection_instance", selection_instance)
|
367
|
+
# Feature plugins instantiate all enabled plugins
|
368
|
+
elif plugin_type == PluginType.FEATURE:
|
369
|
+
enabled_plugins = [
|
370
|
+
plugin for plugin in plugins
|
371
|
+
if not getattr(args, f"disable_{plugin.get_name().replace('-', '_')}", False)
|
372
|
+
]
|
373
|
+
plugin_instantiations = [
|
374
|
+
plugin.plugin_class(**self.extract_plugin_arguments(args, plugin))
|
375
|
+
for plugin in enabled_plugins
|
376
|
+
]
|
377
|
+
setattr(args, f"{category}_enabled_instances", plugin_instantiations)
|
378
|
+
return args
|
379
|
+
|
380
|
+
@staticmethod
|
381
|
+
def extract_plugin_arguments(args, plugin) -> Dict[str, Any]:
|
382
|
+
"""Extract plugin argument values from the args namespace into a map
|
383
|
+
|
384
|
+
Plugin arguments will be supplied to the `__init__` function of the plugin via a keyword argument dictionary.
|
385
|
+
This function maps from the argument namespace from parsing back into that dictionary.
|
386
|
+
|
387
|
+
Args:
|
388
|
+
args: argument namespace from argparse
|
389
|
+
plugin: plugin to extract arguments for
|
390
|
+
Return:
|
391
|
+
filled arguments dictionary
|
392
|
+
"""
|
393
|
+
expected_args = plugin.get_arguments()
|
394
|
+
argument_destinations = [
|
395
|
+
(
|
396
|
+
value["dest"]
|
397
|
+
if "dest" in value
|
398
|
+
else key[0].replace("--", "").replace("-", "_")
|
399
|
+
)
|
400
|
+
for key, value in expected_args.items()
|
401
|
+
]
|
402
|
+
filled_arguments = {
|
403
|
+
destination: getattr(args, destination)
|
404
|
+
for destination in argument_destinations
|
405
|
+
}
|
406
|
+
# Check arguments or yield a Value error
|
407
|
+
if hasattr(plugin, "check_arguments"):
|
408
|
+
plugin.check_arguments(**filled_arguments)
|
409
|
+
return filled_arguments
|
410
|
+
|
411
|
+
|
248
412
|
class CompositeParser(ParserBase):
|
249
413
|
"""Composite parser handles parsing as a composition of multiple other parsers"""
|
250
414
|
|
@@ -258,6 +422,22 @@ class CompositeParser(ParserBase):
|
|
258
422
|
]
|
259
423
|
self.constituent_parsers = {*itertools.chain.from_iterable(flattened)}
|
260
424
|
|
425
|
+
def fill_parser(self, parser):
|
426
|
+
""" File supplied parser with grouped arguments
|
427
|
+
|
428
|
+
Fill the supplied parser with arguments from the `get_arguments` method invocation. This implementation groups
|
429
|
+
arguments based on the constituent that sources the argument.
|
430
|
+
|
431
|
+
Args:
|
432
|
+
parser: parser to fill
|
433
|
+
"""
|
434
|
+
for constituent in sorted(self.constituents, key=lambda x: x.description):
|
435
|
+
if isinstance(constituent, (PluginArgumentParser, CompositeParser)):
|
436
|
+
constituent.fill_parser(parser)
|
437
|
+
else:
|
438
|
+
argument_group = parser.add_argument_group(title=constituent.description)
|
439
|
+
constituent.fill_parser(argument_group)
|
440
|
+
|
261
441
|
@property
|
262
442
|
def constituents(self):
|
263
443
|
"""Get constituent"""
|
@@ -286,49 +466,14 @@ class CompositeParser(ParserBase):
|
|
286
466
|
return args
|
287
467
|
|
288
468
|
|
289
|
-
class
|
290
|
-
"""
|
291
|
-
Handles parsing of all of the comm-layer arguments. This means selecting a comm adapter, and passing the arguments
|
292
|
-
required to setup that comm adapter. In addition, this parser uses the import parser to import modules such that a
|
293
|
-
user may import other adapter implementation files.
|
294
|
-
"""
|
469
|
+
class CommExtraParser(ParserBase):
|
470
|
+
"""Parses extra communication arguments"""
|
295
471
|
|
296
|
-
DESCRIPTION = "
|
472
|
+
DESCRIPTION = "Communications options"
|
297
473
|
|
298
474
|
def get_arguments(self) -> Dict[Tuple[str, ...], Dict[str, Any]]:
|
299
475
|
"""Get arguments for the comm-layer parser"""
|
300
|
-
adapter_definition_dictionaries = BaseAdapter.get_adapters()
|
301
|
-
adapter_arguments = {}
|
302
|
-
for name, adapter in adapter_definition_dictionaries.items():
|
303
|
-
adapter_arguments_callable = getattr(adapter, "get_arguments", None)
|
304
|
-
if not callable(adapter_arguments_callable):
|
305
|
-
print(
|
306
|
-
f"[WARNING] '{name}' does not have 'get_arguments' method, skipping.",
|
307
|
-
file=sys.stderr,
|
308
|
-
)
|
309
|
-
continue
|
310
|
-
adapter_arguments.update(adapter.get_arguments())
|
311
476
|
com_arguments = {
|
312
|
-
("--comm-adapter",): {
|
313
|
-
"dest": "adapter",
|
314
|
-
"action": "store",
|
315
|
-
"type": str,
|
316
|
-
"help": "Adapter for communicating to flight deployment. [default: %(default)s]",
|
317
|
-
"choices": ["none"] + list(adapter_definition_dictionaries),
|
318
|
-
"default": "ip",
|
319
|
-
},
|
320
|
-
("--comm-checksum-type",): {
|
321
|
-
"dest": "checksum_type",
|
322
|
-
"action": "store",
|
323
|
-
"type": str,
|
324
|
-
"help": "Setup the checksum algorithm. [default: %(default)s]",
|
325
|
-
"choices": [
|
326
|
-
item
|
327
|
-
for item in fprime_gds.common.communication.checksum.CHECKSUM_MAPPING.keys()
|
328
|
-
if item != "default"
|
329
|
-
],
|
330
|
-
"default": fprime_gds.common.communication.checksum.CHECKSUM_SELECTION,
|
331
|
-
},
|
332
477
|
("--output-unframed-data",): {
|
333
478
|
"dest": "output_unframed_data",
|
334
479
|
"action": "store",
|
@@ -339,17 +484,9 @@ class CommAdapterParser(ParserBase):
|
|
339
484
|
"required": False,
|
340
485
|
},
|
341
486
|
}
|
342
|
-
return
|
487
|
+
return com_arguments
|
343
488
|
|
344
489
|
def handle_arguments(self, args, **kwargs):
|
345
|
-
"""
|
346
|
-
Handle the input arguments for the parser. This will help setup the adapter with its expected arguments.
|
347
|
-
|
348
|
-
:param args: parsed arguments in namespace format
|
349
|
-
:return: namespace with "comm_adapter" value added
|
350
|
-
"""
|
351
|
-
args.comm_adapter = BaseAdapter.construct_adapter(args.adapter, args)
|
352
|
-
fprime_gds.common.communication.checksum.CHECKSUM_SELECTION = args.checksum_type
|
353
490
|
return args
|
354
491
|
|
355
492
|
|
@@ -360,7 +497,7 @@ class LogDeployParser(ParserBase):
|
|
360
497
|
to end up in the proper place.
|
361
498
|
"""
|
362
499
|
|
363
|
-
DESCRIPTION = "
|
500
|
+
DESCRIPTION = "Logging options"
|
364
501
|
|
365
502
|
def get_arguments(self) -> Dict[Tuple[str, ...], Dict[str, Any]]:
|
366
503
|
"""Return arguments to parse logging options"""
|
@@ -423,50 +560,41 @@ class MiddleWareParser(ParserBase):
|
|
423
560
|
however; it should be close enough.
|
424
561
|
"""
|
425
562
|
|
426
|
-
DESCRIPTION = "
|
563
|
+
DESCRIPTION = "Middleware options"
|
427
564
|
|
428
565
|
def get_arguments(self) -> Dict[Tuple[str, ...], Dict[str, Any]]:
|
429
566
|
"""Return arguments necessary to run a and connect to the GDS middleware"""
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
"
|
443
|
-
"
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
"nargs": 2,
|
449
|
-
"help": "Pair of URls used with --zmq to setup ZeroMQ transportation [default: %(default)s]",
|
450
|
-
"default": [
|
451
|
-
"ipc:///tmp/fprime-server-in",
|
452
|
-
"ipc:///tmp/fprime-server-out",
|
453
|
-
],
|
454
|
-
"metavar": ("serverInUrl", "serverOutUrl"),
|
455
|
-
},
|
456
|
-
}
|
567
|
+
zmq_arguments = {
|
568
|
+
("--no-zmq",): {
|
569
|
+
"dest": "zmq",
|
570
|
+
"action": "store_false",
|
571
|
+
"help": "Disable ZMQ transportation layer, falling back to TCP socket server.",
|
572
|
+
"default": True,
|
573
|
+
},
|
574
|
+
("--zmq-transport",): {
|
575
|
+
"dest": "zmq_transport",
|
576
|
+
"nargs": 2,
|
577
|
+
"help": "Pair of URls used with --zmq to setup ZeroMQ transportation [default: %(default)s]",
|
578
|
+
"default": [
|
579
|
+
"ipc:///tmp/fprime-server-in",
|
580
|
+
"ipc:///tmp/fprime-server-out",
|
581
|
+
],
|
582
|
+
"metavar": ("serverInUrl", "serverOutUrl"),
|
583
|
+
},
|
584
|
+
}
|
457
585
|
tts_arguments = {
|
458
586
|
("--tts-port",): {
|
459
587
|
"dest": "tts_port",
|
460
588
|
"action": "store",
|
461
589
|
"type": int,
|
462
|
-
"help": "Set the threaded TCP socket server port [default: %(default)s]",
|
590
|
+
"help": "Set the threaded TCP socket server port when ZMQ is not used [default: %(default)s]",
|
463
591
|
"default": 50050,
|
464
592
|
},
|
465
593
|
("--tts-addr",): {
|
466
594
|
"dest": "tts_addr",
|
467
595
|
"action": "store",
|
468
596
|
"type": str,
|
469
|
-
"help": "Set the threaded TCP socket server address [default: %(default)s]",
|
597
|
+
"help": "Set the threaded TCP socket server address when ZMQ is not used [default: %(default)s]",
|
470
598
|
"default": "0.0.0.0",
|
471
599
|
},
|
472
600
|
}
|
@@ -481,7 +609,6 @@ class MiddleWareParser(ParserBase):
|
|
481
609
|
:return: args namespace
|
482
610
|
"""
|
483
611
|
is_client = kwargs.get("client", False)
|
484
|
-
args.zmq = getattr(args, "zmq", False)
|
485
612
|
tts_connection_address = (
|
486
613
|
args.tts_addr.replace("0.0.0.0", "127.0.0.1")
|
487
614
|
if is_client
|
@@ -501,6 +628,8 @@ class MiddleWareParser(ParserBase):
|
|
501
628
|
class DictionaryParser(DetectionParser):
|
502
629
|
"""Parser for deployments"""
|
503
630
|
|
631
|
+
DESCRIPTION = "Dictionary options"
|
632
|
+
|
504
633
|
def get_arguments(self) -> Dict[Tuple[str, ...], Dict[str, Any]]:
|
505
634
|
"""Arguments to handle deployments"""
|
506
635
|
return {
|
@@ -540,6 +669,8 @@ class DictionaryParser(DetectionParser):
|
|
540
669
|
class FileHandlingParser(ParserBase):
|
541
670
|
"""Parser for deployments"""
|
542
671
|
|
672
|
+
DESCRIPTION = "File handling options"
|
673
|
+
|
543
674
|
def get_arguments(self) -> Dict[Tuple[str, ...], Dict[str, Any]]:
|
544
675
|
"""Arguments to handle deployments"""
|
545
676
|
|
@@ -618,7 +749,12 @@ class StandardPipelineParser(CompositeParser):
|
|
618
749
|
class CommParser(CompositeParser):
|
619
750
|
"""Comm Executable Parser"""
|
620
751
|
|
621
|
-
CONSTITUENTS = [
|
752
|
+
CONSTITUENTS = [
|
753
|
+
CommExtraParser,
|
754
|
+
MiddleWareParser,
|
755
|
+
LogDeployParser,
|
756
|
+
PluginArgumentParser,
|
757
|
+
]
|
622
758
|
|
623
759
|
def __init__(self):
|
624
760
|
"""Initialization"""
|
@@ -639,7 +775,7 @@ class GdsParser(ParserBase):
|
|
639
775
|
Note: deployment can help in setting both dictionary and logs, but isn't strictly required.
|
640
776
|
"""
|
641
777
|
|
642
|
-
DESCRIPTION = "
|
778
|
+
DESCRIPTION = "GUI options"
|
643
779
|
|
644
780
|
def get_arguments(self) -> Dict[Tuple[str, ...], Dict[str, Any]]:
|
645
781
|
"""Return arguments necessary to run a binary deployment via the GDS"""
|
@@ -686,7 +822,7 @@ class BinaryDeployment(DetectionParser):
|
|
686
822
|
and represents the flight-side of the equation.
|
687
823
|
"""
|
688
824
|
|
689
|
-
DESCRIPTION = "
|
825
|
+
DESCRIPTION = "FPrime binary options"
|
690
826
|
|
691
827
|
def get_arguments(self) -> Dict[Tuple[str, ...], Dict[str, Any]]:
|
692
828
|
"""Return arguments necessary to run a binary deployment via the GDS"""
|
@@ -732,7 +868,7 @@ class SearchArgumentsParser(ParserBase):
|
|
732
868
|
"""Parser for search arguments"""
|
733
869
|
|
734
870
|
DESCRIPTION = (
|
735
|
-
"
|
871
|
+
"Searching and filtering options"
|
736
872
|
)
|
737
873
|
|
738
874
|
def __init__(self, command_name: str) -> None:
|
@@ -778,7 +914,7 @@ class SearchArgumentsParser(ParserBase):
|
|
778
914
|
class RetrievalArgumentsParser(ParserBase):
|
779
915
|
"""Parser for retrieval arguments"""
|
780
916
|
|
781
|
-
DESCRIPTION = "
|
917
|
+
DESCRIPTION = "Data retrieval options"
|
782
918
|
|
783
919
|
def __init__(self, command_name: str) -> None:
|
784
920
|
self.command_name = command_name
|
fprime_gds/executables/comm.py
CHANGED
@@ -16,26 +16,19 @@ Note: assuming the module containing the ground adapter has been imported, then
|
|
16
16
|
@author lestarch
|
17
17
|
"""
|
18
18
|
|
19
|
-
|
20
19
|
import logging
|
21
20
|
import signal
|
22
21
|
import sys
|
23
|
-
|
24
22
|
from pathlib import Path
|
25
23
|
|
26
24
|
# Required adapters built on standard tools
|
27
|
-
try:
|
28
|
-
from fprime_gds.common.zmq_transport import ZmqGround
|
29
|
-
except ImportError:
|
30
|
-
ZmqGround = None
|
31
25
|
import fprime_gds.common.communication.adapters.base
|
32
26
|
import fprime_gds.common.communication.adapters.ip
|
33
|
-
import fprime_gds.common.communication.checksum
|
34
27
|
import fprime_gds.common.communication.ground
|
35
28
|
import fprime_gds.common.logger
|
36
29
|
import fprime_gds.executables.cli
|
37
|
-
from fprime_gds.common.communication.framing import FpFramerDeframer
|
38
30
|
from fprime_gds.common.communication.updown import Downlinker, Uplinker
|
31
|
+
from fprime_gds.common.zmq_transport import ZmqGround
|
39
32
|
|
40
33
|
# Uses non-standard PIP package pyserial, so test the waters before getting a hard-import crash
|
41
34
|
try:
|
@@ -58,38 +51,35 @@ def main():
|
|
58
51
|
fprime_gds.executables.cli.LogDeployParser,
|
59
52
|
fprime_gds.executables.cli.MiddleWareParser,
|
60
53
|
fprime_gds.executables.cli.CommParser,
|
54
|
+
fprime_gds.executables.cli.PluginArgumentParser,
|
61
55
|
],
|
62
56
|
description="F prime communications layer.",
|
63
57
|
client=True,
|
64
58
|
)
|
65
|
-
|
66
|
-
|
67
|
-
|
59
|
+
if args.communication_selection == "none":
|
60
|
+
print(
|
61
|
+
"[ERROR] Comm adapter set to 'none'. Nothing to do but exit.",
|
62
|
+
file=sys.stderr,
|
63
|
+
)
|
68
64
|
sys.exit(-1)
|
69
65
|
|
70
66
|
# Create the handling components for either side of this script, adapter for hardware, and ground for the GDS side
|
71
|
-
if args.zmq
|
72
|
-
|
73
|
-
sys.exit(-1)
|
74
|
-
elif args.zmq:
|
75
|
-
ground = fprime_gds.common.zmq_transport.ZmqGround(args.zmq_transport)
|
76
|
-
# Check for need to make this a server
|
77
|
-
if args.zmq_server:
|
78
|
-
ground.make_server()
|
67
|
+
if args.zmq:
|
68
|
+
ground = ZmqGround(args.zmq_transport)
|
79
69
|
else:
|
80
70
|
ground = fprime_gds.common.communication.ground.TCPGround(
|
81
71
|
args.tts_addr, args.tts_port
|
82
72
|
)
|
83
73
|
|
84
|
-
adapter = args.
|
74
|
+
adapter = args.communication_selection_instance
|
85
75
|
|
86
76
|
# Set the framing class used and pass it to the uplink and downlink component constructions giving each a separate
|
87
77
|
# instantiation
|
88
|
-
|
78
|
+
framer_instance = args.framing_selection_instance
|
89
79
|
LOGGER.info(
|
90
80
|
"Starting uplinker/downlinker connecting to FSW using %s with %s",
|
91
|
-
|
92
|
-
|
81
|
+
args.communication_selection,
|
82
|
+
args.framing_selection,
|
93
83
|
)
|
94
84
|
discarded_file_handle = None
|
95
85
|
try:
|
@@ -108,9 +98,9 @@ def main():
|
|
108
98
|
discarded_file_handle_path,
|
109
99
|
)
|
110
100
|
downlinker = Downlinker(
|
111
|
-
adapter, ground,
|
101
|
+
adapter, ground, framer_instance, discarded=discarded_file_handle
|
112
102
|
)
|
113
|
-
uplinker = Uplinker(adapter, ground,
|
103
|
+
uplinker = Uplinker(adapter, ground, framer_instance, downlinker)
|
114
104
|
|
115
105
|
# Open resources for the handlers on either side, this prepares the resources needed for reading/writing data
|
116
106
|
ground.open()
|
@@ -121,8 +111,8 @@ def main():
|
|
121
111
|
uplinker.start()
|
122
112
|
LOGGER.debug("Uplinker and downlinker running")
|
123
113
|
|
124
|
-
# Wait for shutdown event in the form of a KeyboardInterrupt then stop the processing, close resources,
|
125
|
-
# everything to terminate as expected.
|
114
|
+
# Wait for shutdown event in the form of a KeyboardInterrupt then stop the processing, close resources,
|
115
|
+
# and wait for everything to terminate as expected.
|
126
116
|
def shutdown(*_):
|
127
117
|
"""Shutdown function for signals"""
|
128
118
|
uplinker.stop()
|