fprime-gds 4.0.2a1__py3-none-any.whl → 4.0.2a3__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.
Files changed (30) hide show
  1. fprime_gds/common/decoders/ch_decoder.py +1 -1
  2. fprime_gds/common/decoders/event_decoder.py +1 -1
  3. fprime_gds/common/decoders/pkt_decoder.py +1 -1
  4. fprime_gds/common/distributor/distributor.py +1 -1
  5. fprime_gds/common/encoders/cmd_encoder.py +1 -1
  6. fprime_gds/common/encoders/encoder.py +1 -1
  7. fprime_gds/common/encoders/seq_writer.py +1 -1
  8. fprime_gds/common/gds_cli/base_commands.py +1 -1
  9. fprime_gds/common/gds_cli/channels.py +1 -1
  10. fprime_gds/common/gds_cli/command_send.py +1 -1
  11. fprime_gds/common/gds_cli/events.py +1 -1
  12. fprime_gds/common/handlers.py +56 -0
  13. fprime_gds/common/{pipeline → models}/dictionaries.py +24 -0
  14. fprime_gds/common/pipeline/publishing.py +111 -0
  15. fprime_gds/common/pipeline/standard.py +12 -21
  16. fprime_gds/common/testing_fw/api.py +8 -1
  17. fprime_gds/common/utils/config_manager.py +1 -1
  18. fprime_gds/executables/apps.py +59 -14
  19. fprime_gds/executables/cli.py +28 -5
  20. fprime_gds/executables/fprime_cli.py +1 -1
  21. fprime_gds/executables/run_deployment.py +19 -6
  22. {fprime_gds-4.0.2a1.dist-info → fprime_gds-4.0.2a3.dist-info}/METADATA +1 -1
  23. {fprime_gds-4.0.2a1.dist-info → fprime_gds-4.0.2a3.dist-info}/RECORD +28 -29
  24. fprime_gds/common/models/common/channel_telemetry.py +0 -174
  25. fprime_gds/common/models/common/event.py +0 -121
  26. {fprime_gds-4.0.2a1.dist-info → fprime_gds-4.0.2a3.dist-info}/WHEEL +0 -0
  27. {fprime_gds-4.0.2a1.dist-info → fprime_gds-4.0.2a3.dist-info}/entry_points.txt +0 -0
  28. {fprime_gds-4.0.2a1.dist-info → fprime_gds-4.0.2a3.dist-info}/licenses/LICENSE.txt +0 -0
  29. {fprime_gds-4.0.2a1.dist-info → fprime_gds-4.0.2a3.dist-info}/licenses/NOTICE.txt +0 -0
  30. {fprime_gds-4.0.2a1.dist-info → fprime_gds-4.0.2a3.dist-info}/top_level.txt +0 -0
@@ -41,7 +41,7 @@ class ChDecoder(Decoder):
41
41
 
42
42
  if config is None:
43
43
  # Retrieve singleton for the configs
44
- config = config_manager.ConfigManager().get_instance()
44
+ config = config_manager.ConfigManager.get_instance()
45
45
 
46
46
  self.__dict = ch_dict
47
47
  self.id_obj = config.get_type("FwChanIdType")
@@ -43,7 +43,7 @@ class EventDecoder(decoder.Decoder):
43
43
 
44
44
  if config is None:
45
45
  # Retrieve defaults for the configs
46
- config = config_manager.ConfigManager().get_instance()
46
+ config = config_manager.ConfigManager.get_instance()
47
47
 
48
48
  self.__dict = event_dict
49
49
  self.id_obj = config.get_type("FwEventIdType")
@@ -41,7 +41,7 @@ class PktDecoder(ChDecoder):
41
41
  An initialized PktDecoder object
42
42
  """
43
43
  if config is None:
44
- config = config_manager.ConfigManager().get_instance()
44
+ config = config_manager.ConfigManager.get_instance()
45
45
  super().__init__(ch_dict, config)
46
46
 
47
47
  self.__dict = pkt_name_dict
@@ -45,7 +45,7 @@ class Distributor(DataHandler):
45
45
  """
46
46
  if config is None:
47
47
  # Retrieve singleton for the configs, or defaults if singleton unused
48
- config = config_manager.ConfigManager().get_instance()
48
+ config = config_manager.ConfigManager.get_instance()
49
49
 
50
50
  self.__decoders = {key.name: [] for key in list(data_desc_type.DataDescType)}
51
51
 
@@ -68,7 +68,7 @@ class CmdEncoder(encoder.Encoder):
68
68
  """
69
69
 
70
70
  if config is None:
71
- config = config_manager.ConfigManager().get_instance()
71
+ config = config_manager.ConfigManager.get_instance()
72
72
  super().__init__(config)
73
73
 
74
74
  self.len_obj = self.config.get_type("msg_len")
@@ -49,7 +49,7 @@ class Encoder(
49
49
  super().__init__()
50
50
  if config is None:
51
51
  # Retrieve defaults for the configs
52
- config = ConfigManager()
52
+ config = ConfigManager.get_instance()
53
53
  self.config = config
54
54
 
55
55
  def data_callback(self, data, sender=None):
@@ -24,7 +24,7 @@ class SeqBinaryWriter:
24
24
  Constructor
25
25
  """
26
26
  if config is None:
27
- config = config_manager.ConfigManager().get_instance()
27
+ config = config_manager.ConfigManager.get_instance()
28
28
 
29
29
  self.__fd = None
30
30
  self.__timebase = timebase
@@ -10,7 +10,7 @@ from typing import Iterable
10
10
 
11
11
  import fprime_gds.common.gds_cli.filtering_utils as filtering_utils
12
12
  import fprime_gds.common.gds_cli.test_api_utils as test_api_utils
13
- from fprime_gds.common.pipeline.dictionaries import Dictionaries
13
+ from fprime_gds.common.models.dictionaries import Dictionaries
14
14
  from fprime_gds.common.testing_fw import predicates
15
15
  from fprime_gds.common.testing_fw.api import IntegrationTestAPI
16
16
  from fprime_gds.executables.cli import StandardPipelineParser
@@ -7,7 +7,7 @@ from typing import Iterable
7
7
  import fprime_gds.common.gds_cli.test_api_utils as test_api_utils
8
8
  from fprime_gds.common.data_types.ch_data import ChData
9
9
  from fprime_gds.common.gds_cli.base_commands import QueryHistoryCommand
10
- from fprime_gds.common.pipeline.dictionaries import Dictionaries
10
+ from fprime_gds.common.models.dictionaries import Dictionaries
11
11
  from fprime_gds.common.testing_fw import predicates
12
12
  from fprime_gds.common.testing_fw.api import IntegrationTestAPI
13
13
 
@@ -9,7 +9,7 @@ from fprime.common.models.serialize.type_exceptions import NotInitializedExcepti
9
9
 
10
10
  import fprime_gds.common.gds_cli.test_api_utils as test_api_utils
11
11
  from fprime_gds.common.gds_cli.base_commands import BaseCommand
12
- from fprime_gds.common.pipeline.dictionaries import Dictionaries
12
+ from fprime_gds.common.models.dictionaries import Dictionaries
13
13
  from fprime_gds.common.templates.cmd_template import CmdTemplate
14
14
  from fprime_gds.common.testing_fw import predicates
15
15
  from fprime_gds.common.testing_fw.api import IntegrationTestAPI
@@ -7,7 +7,7 @@ from typing import Iterable
7
7
  import fprime_gds.common.gds_cli.test_api_utils as test_api_utils
8
8
  from fprime_gds.common.data_types.event_data import EventData
9
9
  from fprime_gds.common.gds_cli.base_commands import QueryHistoryCommand
10
- from fprime_gds.common.pipeline.dictionaries import Dictionaries
10
+ from fprime_gds.common.models.dictionaries import Dictionaries
11
11
  from fprime_gds.common.testing_fw import predicates
12
12
  from fprime_gds.common.testing_fw.api import IntegrationTestAPI
13
13
 
@@ -37,6 +37,13 @@ class DataHandlerPlugin(DataHandler, abc.ABC):
37
37
  data types it handles (whereas DataHandler leaves that up to the registration call). Users shall concretely subclass
38
38
  this class with their own data handling functionality.
39
39
  """
40
+ def __init__(self, **kwargs):
41
+ """ Initialize """
42
+ self.publisher = None
43
+
44
+ def set_publisher(self, publisher):
45
+ """ Set publishing pipeline """
46
+ self.publisher = publisher
40
47
 
41
48
  @abc.abstractmethod
42
49
  def get_handled_descriptors() -> List[str]:
@@ -113,3 +120,52 @@ class HandlerRegistrar(abc.ABC):
113
120
  """
114
121
  for registrant in self._registrants:
115
122
  registrant.data_callback(data, sender)
123
+
124
+
125
+ class MappedRegistrar(abc.ABC):
126
+ """ Class to register a mapping """
127
+
128
+ def __init__(self):
129
+ """ Initialize an empty registrant list """
130
+ super().__init__()
131
+ self._registrants = {}
132
+
133
+ def register(self, id, registrant):
134
+ """
135
+ Register a registrant with this registrar associated with the ID. Will be stored and called back when asked to
136
+ send data to all the handlers registered at the id
137
+
138
+ :param id: id to register to
139
+ :param registrant: handler to register
140
+ """
141
+ self._registrants[id] = self._registrants.get(id, HandlerRegistrar())
142
+ self._registrants[id].register(registrant)
143
+
144
+ def deregister(self, id, registrant):
145
+ """
146
+ Remove a registrant from the registrar such that it will not be called back later. Note: ignores invalid
147
+ removals by trapping the error, as the desired effect is already satisfied.
148
+
149
+ :param id: id to register to
150
+ :param registrant: registrant to remove
151
+ :return: True if found, False if not. May safely be ignored.
152
+ """
153
+ try:
154
+ self._registrants[id].deregister(registrant)
155
+ return True
156
+ except (ValueError, KeyError):
157
+ return False
158
+
159
+ def send_to_all(self, id, data, sender=None):
160
+ """
161
+ Sends the given data to all registrants at id.
162
+
163
+ :param id: id to send to
164
+ :param data: data to send back to registrants
165
+ :param sender: (optional) sender to pass to data_callback
166
+ """
167
+ try:
168
+ self._registrants[id].send_to_all(data, sender)
169
+ except KeyError:
170
+ print("KeyERROR")
171
+ pass
@@ -49,6 +49,9 @@ class Dictionaries:
49
49
  self._fw_type_name_dict = None
50
50
  self._versions = None
51
51
  self._metadata = None
52
+ self._dictionary_path = None
53
+ self._packet_spec_path = None
54
+ self._packet_set_name = None
52
55
 
53
56
  def load_dictionaries(self, dictionary, packet_spec, packet_set_name):
54
57
  """
@@ -57,7 +60,13 @@ class Dictionaries:
57
60
 
58
61
  :param dictionary: dictionary path used for loading dictionaries
59
62
  :param packet_spec: specification for packets, or None, for packetized telemetry
63
+ :param packet_set_name: name of packet set in case multiple are available
60
64
  """
65
+ # Update the "from" values
66
+ self._dictionary_path = dictionary
67
+ self._packet_spec_path = packet_spec
68
+ self._packet_set_name = packet_set_name
69
+
61
70
  if Path(dictionary).is_file() and ".json" in Path(dictionary).suffixes:
62
71
  # Events
63
72
  json_event_loader = (
@@ -203,6 +212,21 @@ class Dictionaries:
203
212
  for legacy reasons. New code should use the metadata property."""
204
213
  return self._metadata
205
214
 
215
+ @property
216
+ def dictionary_path(self):
217
+ """ Dictionary Path """
218
+ return self._dictionary_path
219
+
220
+ @property
221
+ def packet_spec_path(self):
222
+ """ Dictionary Path """
223
+ return self._packet_spec_path
224
+
225
+ @property
226
+ def packet_set_name(self):
227
+ """ Dictionary Path """
228
+ return self._packet_set_name
229
+
206
230
  @property
207
231
  def packet(self):
208
232
  """Packet dictionary"""
@@ -0,0 +1,111 @@
1
+ """
2
+ publishing.py:
3
+
4
+ This file contains a basic publishing pipeline. It reads and writes data bound for the GDS.
5
+
6
+ :author: lestarch
7
+ """
8
+
9
+
10
+ from typing import Type
11
+
12
+ from fprime_gds.common.data_types.ch_data import ChData
13
+ from fprime_gds.common.data_types.event_data import EventData
14
+ from fprime_gds.common.encoders.ch_encoder import ChEncoder
15
+ from fprime_gds.common.encoders.event_encoder import EventEncoder
16
+ from fprime_gds.common.transport import RoutingTag, ThreadedTCPSocketClient
17
+ from fprime_gds.common.utils.config_manager import ConfigManager
18
+
19
+ from fprime_gds.common.handlers import DataHandler, MappedRegistrar
20
+ from ..models import dictionaries
21
+
22
+
23
+ class PublishingPipeline(DataHandler, MappedRegistrar):
24
+ """ Pipeline for publishing
25
+
26
+ This pipeline sets up the following process:
27
+
28
+ Data -> Encoder -> Client -> <wire>
29
+ """
30
+ DEFAULT_ENCODERS = {
31
+ "FW_PACKET_LOG": EventEncoder,
32
+ "FW_PACKET_TELEM": ChEncoder
33
+ }
34
+
35
+ def __init__(self):
36
+ """
37
+ Set core variables to None or their composition handlers.
38
+ """
39
+ super().__init__()
40
+ self.client_socket = None
41
+
42
+ self._dictionaries = dictionaries.Dictionaries()
43
+ self._transport_type = ThreadedTCPSocketClient
44
+
45
+ def setup(self, dictionaries):
46
+ """ Set up the publishing pipeline """
47
+ self._dictionaries = dictionaries
48
+ self.client_socket = self.__transport_type()
49
+ config = ConfigManager.get_instance()
50
+
51
+ for id, encoder_class in self.DEFAULT_ENCODERS.items():
52
+ encoder_instance = encoder_class(config=config)
53
+ encoder_instance.register(self.client_socket)
54
+ self.register(id, encoder_instance)
55
+
56
+ def data_callback(self, data, sender=None):
57
+ """ Publish data """
58
+ if isinstance(data, ChData):
59
+ self.send_to_all("FW_PACKET_TELEM", data)
60
+ elif isinstance(data, EventData):
61
+ self.send_to_all("FW_PACKET_LOG", data)
62
+ return super().data_callback(data, sender)
63
+
64
+ def publish_channel(self, name, value, time):
65
+ """ Publish channel value using name, time, and value
66
+
67
+ Looks up the channel template in the dictionary and constructs a new channel object given the time and value.
68
+ This ChData object is then sent into the outgoing "publish" pipeline.
69
+
70
+ """
71
+ template = self._dictionaries.channel_name[name]
72
+ copied_value_object = template.get_type_obj()(value)
73
+ copied_value_object.val = value
74
+ object = ChData(copied_value_object, time, template)
75
+ return self.data_callback(object, self)
76
+
77
+ @property
78
+ def transport_implementation(self):
79
+ """Get implementation type for transport"""
80
+ return self.__transport_type
81
+
82
+ @transport_implementation.setter
83
+ def transport_implementation(self, transport_type: Type[None]):
84
+ """Set the implementation type for transport"""
85
+ assert (
86
+ self.client_socket is None
87
+ ), "Cannot setup transport implementation type after setup"
88
+ self.__transport_type = transport_type
89
+
90
+
91
+ def connect(
92
+ self, connection_uri, incoming_tag=RoutingTag.GUI, outgoing_tag=RoutingTag.GUI
93
+ ):
94
+ """Connects to the middleware layer
95
+
96
+ Connect to the middleware layer. This connection needs to identify if the object is a a FSW or GUI client. The
97
+ default connection acts as a GUI client sending back to the GUI.
98
+
99
+ Args:
100
+ connection_uri: URI of the connection to make
101
+ incoming_tag: this pipeline will act as supplied tag (GUI, FSW). Default: GUI
102
+ outgoing_tag: this pipeline will produce data for supplied tag (FSW, GUI). Default: FSW
103
+ """
104
+ self.client_socket.connect(connection_uri, incoming_tag, outgoing_tag)
105
+
106
+ def disconnect(self):
107
+ """ Disconnect from the client socket """
108
+ if self.client_socket is not None:
109
+ self.client_socket.disconnect()
110
+
111
+
@@ -23,7 +23,7 @@ from fprime_gds.common.transport import RoutingTag, ThreadedTCPSocketClient
23
23
  from fprime_gds.common.utils.config_manager import ConfigManager
24
24
 
25
25
  # Local imports for the sake of composition
26
- from . import dictionaries, encoding, files, histories
26
+ from . import encoding, files, histories
27
27
 
28
28
 
29
29
  class StandardPipeline:
@@ -49,7 +49,7 @@ class StandardPipeline:
49
49
  self.up_store = None
50
50
  self.down_store = None
51
51
 
52
- self.__dictionaries = dictionaries.Dictionaries()
52
+ self.__dictionaries = None
53
53
  self.__coders = encoding.EncodingDecoding()
54
54
  self.__histories = histories.Histories()
55
55
  self.__filing = files.Filing()
@@ -58,11 +58,9 @@ class StandardPipeline:
58
58
  def setup(
59
59
  self,
60
60
  config: ConfigManager,
61
- dictionary,
61
+ dictionaries,
62
62
  file_store,
63
63
  logging_prefix=None,
64
- packet_spec=None,
65
- packet_set_name=None,
66
64
  data_logging_enabled=True
67
65
  ):
68
66
  """
@@ -70,14 +68,13 @@ class StandardPipeline:
70
68
  patterns. This allows just registering the consumers, and invoking 'setup' all other of the GDS support layer.
71
69
 
72
70
  :param config: config object used when constructing the pipeline.
73
- :param dictionary: dictionary path. Used to setup loading of dictionaries.
71
+ :param dictionaries: dictionary path. Used to setup loading of dictionaries.
74
72
  :param file_store: uplink/downlink storage directory
75
73
  :param logging_prefix: logging prefix. Defaults to not logging at all.
76
74
  :param packet_spec: location of packetized telemetry XML specification.
77
75
  """
78
- assert (
79
- dictionary is not None and Path(dictionary).is_file()
80
- ), f"Dictionary {dictionary} does not exist"
76
+ self.distributor = fprime_gds.common.distributor.distributor.Distributor(config)
77
+ self.client_socket = self.__transport_type()
81
78
  # File storage configuration for uplink and downlink
82
79
  self.up_store = Path(file_store) / "fprime-uplink"
83
80
  self.down_store = Path(file_store) / "fprime-downlink"
@@ -88,18 +85,7 @@ class StandardPipeline:
88
85
  raise PermissionError(
89
86
  f"{file_store} is not writable. Fix permissions or change storage directory with --file-storage-directory."
90
87
  )
91
- self.dictionary_path = Path(dictionary)
92
- # Loads the distributor and client socket
93
- self.distributor = fprime_gds.common.distributor.distributor.Distributor(config)
94
- self.client_socket = self.__transport_type()
95
- # Setup dictionaries encoders and decoders
96
- self.dictionaries.load_dictionaries(
97
- self.dictionary_path, packet_spec, packet_set_name
98
- )
99
- # Update config to use Fw types defined in the JSON dictionary
100
- if self.dictionaries.fw_type_name:
101
- for fw_type_name, fw_type in self.dictionaries.fw_type_name.items():
102
- config.set("types", fw_type_name, fw_type)
88
+ self.__dictionaries = dictionaries
103
89
  self.coders.setup_coders(
104
90
  self.dictionaries, self.distributor, self.client_socket, config
105
91
  )
@@ -253,3 +239,8 @@ class StandardPipeline:
253
239
  :return: filing compositions
254
240
  """
255
241
  return self.__filing
242
+
243
+ @property
244
+ def dictionaries(self):
245
+ """ Dictionaries member """
246
+ return self.__dictionaries
@@ -71,7 +71,7 @@ class IntegrationTestAPI(DataHandler):
71
71
 
72
72
  # Copy dictionaries and binary file to output directory
73
73
  if logpath is not None:
74
- base_dir = Path(self.pipeline.dictionary_path).parents[1]
74
+ base_dir = Path(self.dictionaries.dictionary_path).parents[1]
75
75
  for subdir in ["bin", "dict"]:
76
76
  dir_path = base_dir / subdir
77
77
  if dir_path.is_dir():
@@ -85,6 +85,13 @@ class IntegrationTestAPI(DataHandler):
85
85
  # Used by the data_callback method to detect if events have been received out of order.
86
86
  self.last_evr = None
87
87
 
88
+ @property
89
+ def dictionaries(self):
90
+ """ Return the dictionaries """
91
+ # Pipeline should not be exposed to the user, but it stores the dictionary
92
+ # thus delegate to it.
93
+ return self.pipeline.dictionaries
94
+
88
95
  def setup(self):
89
96
  """Set up the API, assumes pipeline is now setup"""
90
97
  self.pipeline.coders.register_event_consumer(self)
@@ -40,7 +40,7 @@ class ConfigBadTypeException(Exception):
40
40
  config_name (string): Name of the config containing the bad type
41
41
  type_str (string): Bad type string that caused the error
42
42
  """
43
- print(f"Invalid type string {type_str} read in configuration {config_name}")
43
+ super().__init__(f"Invalid type string {type_str} read in configuration {config_name}")
44
44
 
45
45
 
46
46
  class ConfigManager(configparser.ConfigParser):
@@ -14,8 +14,8 @@ command line that will be spun into its own process.
14
14
  import subprocess
15
15
  import sys
16
16
  from abc import ABC, abstractmethod
17
- from argparse import Namespace
18
- from typing import final, List, Dict, Tuple, Type
17
+ import argparse
18
+ from typing import final, List, Dict, Tuple, Type, Optional
19
19
 
20
20
  from fprime_gds.plugin.definitions import gds_plugin_specification, gds_plugin
21
21
  from fprime_gds.plugin.system import Plugins
@@ -23,10 +23,13 @@ from fprime_gds.executables.cli import (
23
23
  CompositeParser,
24
24
  ParserBase,
25
25
  BareArgumentParser,
26
+ MiddleWareParser,
27
+ DictionaryParser,
26
28
  StandardPipelineParser,
27
29
  PluginArgumentParser,
28
30
  )
29
31
  from fprime_gds.common.pipeline.standard import StandardPipeline
32
+ from fprime_gds.common.pipeline.publishing import PublishingPipeline
30
33
 
31
34
 
32
35
  class GdsBaseFunction(ABC):
@@ -40,7 +43,7 @@ class GdsBaseFunction(ABC):
40
43
  """
41
44
 
42
45
  @abstractmethod
43
- def run(self):
46
+ def run(self, parsed_args):
44
47
  """Run the start-up function
45
48
 
46
49
  Run the start-up function unconstrained by the limitations of running in a dedicated subprocess.
@@ -110,13 +113,13 @@ class GdsApp(GdsBaseFunction):
110
113
  self.process = None
111
114
  self.arguments = arguments
112
115
 
113
- def run(self):
116
+ def run(self, parsed_args):
114
117
  """Run the application as an isolated process
115
118
 
116
119
  GdsFunction objects require an implementation of the `run` command. This implementation will take the arguments
117
120
  provided from `get_process_invocation` function and supplies them as an invocation of the isolated subprocess.
118
121
  """
119
- invocation_arguments = self.get_process_invocation()
122
+ invocation_arguments = self.get_process_invocation(parsed_args)
120
123
  self.process = subprocess.Popen(invocation_arguments)
121
124
 
122
125
  def wait(self, timeout=None):
@@ -137,7 +140,9 @@ class GdsApp(GdsBaseFunction):
137
140
  return self.process.returncode
138
141
 
139
142
  @abstractmethod
140
- def get_process_invocation(self) -> List[str]:
143
+ def get_process_invocation(
144
+ self, namespace: Optional[argparse.Namespace] = None
145
+ ) -> List[str]:
141
146
  """Run the start-up function
142
147
 
143
148
  Run the start-up function unconstrained by the limitations of running in a dedicated subprocess.
@@ -199,6 +204,18 @@ class GdsStandardApp(GdsApp):
199
204
  dictionary of flag tuple to argparse kwargs
200
205
  """
201
206
  return {}
207
+
208
+ @classmethod
209
+ def get_additional_cli_parsers(cls) -> List[ParserBase]:
210
+ """ Supply a list of CLI parser objects
211
+
212
+ Supply a list of CLI parser objects to the CLI system. This allows use of full ParserBase objects instead of
213
+ the more restrictive dictionary approach seen in get_additional_arguments.
214
+
215
+ Returns:
216
+ list of parser objects as passed to ParserBase
217
+ """
218
+ return []
202
219
 
203
220
  @classmethod
204
221
  def init(cls):
@@ -230,7 +247,7 @@ class GdsStandardApp(GdsApp):
230
247
  """Start function to contain behavior based in standard pipeline"""
231
248
  raise NotImplementedError()
232
249
 
233
- def get_process_invocation(self):
250
+ def get_process_invocation(self, namespace=None):
234
251
  """Return the process invocation for this class' main
235
252
 
236
253
  The process invocation of this application is to run cls.main and supply it a reproduced version of the
@@ -247,7 +264,8 @@ class GdsStandardApp(GdsApp):
247
264
  composite_parser = CompositeParser(
248
265
  [self.get_cli_parser(), StandardPipelineParser]
249
266
  )
250
- namespace, _, _ = ParserBase.parse_known_args([composite_parser])
267
+ if namespace is None:
268
+ namespace, _, _ = ParserBase.parse_known_args([composite_parser], client=True)
251
269
  args = composite_parser.reproduce_cli_args(namespace)
252
270
  return [sys.executable, "-c", f"import {module}\n{module}.{cls}.main()"] + args
253
271
 
@@ -261,32 +279,39 @@ class GdsStandardApp(GdsApp):
261
279
  []
262
280
  ) # Disable plugin system unless specified through init
263
281
  # In the case where `init` sets up the plugin system, we want to pass the assertion
264
- # triggered by the code above that turns it off in the not-setup case.
282
+ # triggered by the code above that turns it off in the not-setup case.
265
283
  except AssertionError:
266
284
  pass
267
285
  plugin_name = getattr(cls, "get_name", lambda: cls.__name__)()
286
+ plugin_composite = CompositeParser([cls.get_cli_parser()] + cls.get_additional_cli_parsers())
287
+
268
288
  parsed_arguments, _ = ParserBase.parse_args(
269
- [cls.get_cli_parser(), StandardPipelineParser, PluginArgumentParser],
289
+ [ StandardPipelineParser, PluginArgumentParser, plugin_composite],
270
290
  f"{plugin_name}: a standard app plugin",
291
+ client=True,
271
292
  )
272
293
  pipeline = StandardPipeline()
273
- # Turn off history and filing
294
+ # Turn off history, file handling, and logging
274
295
  pipeline.histories.implementation = None
275
296
  pipeline.filing = None
297
+ parsed_arguments.disable_data_logging = True
276
298
  pipeline = StandardPipelineParser.pipeline_factory(
277
299
  parsed_arguments, pipeline
278
300
  )
279
301
  application = cls(
280
- **cls.get_cli_parser().extract_arguments(parsed_arguments)
302
+ **cls.get_cli_parser().extract_arguments(parsed_arguments),
303
+ namespace=parsed_arguments,
304
+
281
305
  )
282
306
  application.start(pipeline)
283
307
  sys.exit(0)
284
308
  except Exception as e:
285
309
  print(f"[ERROR] Error launching {cls.__name__}: {e}", file=sys.stderr)
286
- raise
287
310
  sys.exit(148)
288
311
 
289
312
 
313
+
314
+
290
315
  @gds_plugin(GdsApp)
291
316
  class CustomDataHandlers(GdsStandardApp):
292
317
  """Run an app that registers all custom data handlers
@@ -294,10 +319,25 @@ class CustomDataHandlers(GdsStandardApp):
294
319
  A GdsApp plugin, built using the GdsStandardApp helper, that uses the provided standard pipeline to register each
295
320
  custom DataHandler plugin as a consumer of the appropriate type.
296
321
  """
322
+ PLUGIN_PARSER = CompositeParser([MiddleWareParser, DictionaryParser])
297
323
 
298
- def __init__(self, **kwargs):
324
+ def __init__(self, namespace, **kwargs):
299
325
  """Required __init__ implementation"""
300
326
  super().__init__(**kwargs)
327
+ self.connection_transport = namespace.connection_transport
328
+ self.connection_uri = namespace.connection_uri
329
+ self.dictionaries = namespace.dictionaries
330
+
331
+ @classmethod
332
+ def get_additional_arguments(cls):
333
+ """ Supplies additional arguments needed """
334
+ return {}
335
+
336
+ @classmethod
337
+ def get_additional_cli_parsers(cls):
338
+ """ Requires MiddleWareParser and Dictionary Parser"""
339
+ return [cls.PLUGIN_PARSER]
340
+
301
341
 
302
342
  @classmethod
303
343
  def init(cls):
@@ -312,10 +352,15 @@ class CustomDataHandlers(GdsStandardApp):
312
352
  "FW_PACKET_FILE": pipeline.coders.register_file_consumer,
313
353
  "FW_PACKET_PACKETIZED_TLM": pipeline.coders.register_packet_consumer,
314
354
  }
355
+ self.publisher = PublishingPipeline()
356
+ self.publisher.transport_implementation = self.connection_transport
357
+ self.publisher.setup(self.dictionaries)
358
+ self.publisher.connect(self.connection_uri)
315
359
 
316
360
  data_handlers = Plugins.system().get_feature_classes("data_handler")
317
361
  for data_handler_class in data_handlers:
318
362
  data_handler = data_handler_class()
363
+ data_handler.set_publisher(self.publisher)
319
364
  descriptors = data_handler.get_handled_descriptors()
320
365
  for descriptor in descriptors:
321
366
  DESCRIPTOR_TO_FUNCTION.get(descriptor, lambda discard: discard)(
@@ -27,9 +27,9 @@ from pathlib import Path
27
27
  from typing import Any, Dict, List, Tuple
28
28
 
29
29
  # Required to set the checksum as a module variable
30
- import fprime_gds.common.communication.checksum
31
30
  import fprime_gds.common.logger
32
31
  from fprime_gds.common.communication.adapters.ip import check_port
32
+ from fprime_gds.common.models.dictionaries import Dictionaries
33
33
  from fprime_gds.common.pipeline.standard import StandardPipeline
34
34
  from fprime_gds.common.transport import ThreadedTCPSocketClient
35
35
  from fprime_gds.common.utils.config_manager import ConfigManager
@@ -176,6 +176,18 @@ class ParserBase(ABC):
176
176
  ]
177
177
  return list(itertools.chain.from_iterable(cli_pairs))
178
178
 
179
+ def handle_values(self, values: Dict[str, Any]):
180
+ """Post-process the parser's arguments in dictionary form
181
+
182
+ Handle arguments from the given parser in dictionary form. This will convert to/from the namespace and then
183
+ delegate to handle_arguments.
184
+
185
+ Args:
186
+ args: arguments namespace of processed arguments
187
+ Returns: dictionary with processed results of arguments.
188
+ """
189
+ return vars(self.handle_arguments(args=argparse.Namespace(**values), kwargs={}))
190
+
179
191
  @abstractmethod
180
192
  def handle_arguments(self, args, **kwargs):
181
193
  """Post-process the parser's arguments
@@ -1007,6 +1019,19 @@ class DictionaryParser(DetectionParser):
1007
1019
  elif args.dictionary is None:
1008
1020
  args = super().handle_arguments(args, **kwargs)
1009
1021
  args.dictionary = find_dict(args.deployment)
1022
+
1023
+ # Setup dictionaries encoders and decoders
1024
+ dictionaries = Dictionaries()
1025
+
1026
+ dictionaries.load_dictionaries(
1027
+ args.dictionary, args.packet_spec, args.packet_set_name
1028
+ )
1029
+ config = ConfigManager.get_instance()
1030
+ # Update config to use Fw types defined in the JSON dictionary
1031
+ if dictionaries.fw_type_name:
1032
+ for fw_type_name, fw_type in dictionaries.fw_type_name.items():
1033
+ config.set("types", fw_type_name, fw_type)
1034
+ args.dictionaries = dictionaries
1010
1035
  return args
1011
1036
 
1012
1037
 
@@ -1070,11 +1095,9 @@ class StandardPipelineParser(CompositeParser):
1070
1095
  def pipeline_factory(args_ns, pipeline=None) -> StandardPipeline:
1071
1096
  """A factory of the standard pipeline given the handled arguments"""
1072
1097
  pipeline_arguments = {
1073
- "config": ConfigManager(),
1074
- "dictionary": args_ns.dictionary,
1098
+ "config": ConfigManager.get_instance(),
1099
+ "dictionaries": args_ns.dictionaries,
1075
1100
  "file_store": args_ns.files_storage_directory,
1076
- "packet_spec": args_ns.packet_spec,
1077
- "packet_set_name": args_ns.packet_set_name,
1078
1101
  "logging_prefix": args_ns.logs,
1079
1102
  "data_logging_enabled": not args_ns.disable_data_logging
1080
1103
  }
@@ -227,7 +227,7 @@ class CommandSubparserInjector(CliSubparserInjectorBase):
227
227
  argcomplete.warn("No dictionary found to get command names from")
228
228
  return []
229
229
 
230
- from fprime_gds.common.pipeline.dictionaries import Dictionaries
230
+ from fprime_gds.common.models.dictionaries import Dictionaries
231
231
 
232
232
  dictionary = Dictionaries()
233
233
  dictionary.load_dictionaries(dict_path, None, None)
@@ -5,6 +5,7 @@
5
5
  ####
6
6
  import os
7
7
  import sys
8
+ import copy
8
9
  import webbrowser
9
10
 
10
11
  from fprime_gds.executables.cli import (
@@ -38,7 +39,9 @@ def parse_args():
38
39
  PluginArgumentParser,
39
40
  ]
40
41
  # Parse the arguments, and refine through all handlers
41
- args, parser = ConfigDrivenParser.parse_args(arg_handlers, "Run F prime deployment and GDS")
42
+ args, parser = ConfigDrivenParser.parse_args(
43
+ arg_handlers, "Run F prime deployment and GDS"
44
+ )
42
45
  return args
43
46
 
44
47
 
@@ -175,11 +178,21 @@ def launch_comm(parsed_args):
175
178
  )
176
179
 
177
180
 
178
- def launch_plugin(plugin_class_instance):
181
+ def launch_plugin(parsed_args, plugin_class_instance):
179
182
  """Launch a plugin instance"""
180
- plugin_name = getattr(plugin_class_instance, "get_name", lambda: plugin_class_instance.__class__.__name__)()
183
+ plugin_name = getattr(
184
+ plugin_class_instance,
185
+ "get_name",
186
+ lambda: plugin_class_instance.__class__.__name__,
187
+ )()
188
+ plugin_args = copy.deepcopy(parsed_args)
189
+ # Set logging to use a subdirectory within the root logs directory
190
+ plugin_logs = os.path.join(plugin_args.logs, plugin_name)
191
+ os.mkdir(plugin_logs)
192
+ plugin_args.logs = plugin_logs
193
+ plugin_args.log_directly = True
181
194
  return launch_process(
182
- plugin_class_instance.get_process_invocation(),
195
+ plugin_class_instance.get_process_invocation(plugin_args),
183
196
  name=f"{ plugin_name } Plugin App",
184
197
  launch_time=1,
185
198
  )
@@ -218,11 +231,11 @@ def main():
218
231
  try:
219
232
  procs = [launcher(parsed_args) for launcher in launchers]
220
233
  _ = [
221
- launch_plugin(cls())
234
+ launch_plugin(parsed_args, cls(namespace=parsed_args))
222
235
  for cls in Plugins.system().get_feature_classes("gds_app")
223
236
  ]
224
237
  _ = [
225
- instance().run()
238
+ instance().run(parsed_args)
226
239
  for instance in Plugins.system().get_feature_classes("gds_function")
227
240
  ]
228
241
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fprime-gds
3
- Version: 4.0.2a1
3
+ Version: 4.0.2a3
4
4
  Summary: F Prime Flight Software Ground Data System layer
5
5
  Author-email: Michael Starch <Michael.D.Starch@jpl.nasa.gov>, Thomas Boyer-Chammard <Thomas.Boyer.Chammard@jpl.nasa.gov>
6
6
  License:
@@ -2,7 +2,7 @@ fastentrypoints.py,sha256=2HO-tsTTZxpzYNd-BaLK3WDLknzCZKzb_yX2p3Ftqa8,4020
2
2
  fprime_gds/__init__.py,sha256=y2ljhCEHnvyfSDvXIEgBGIk8oHjjjjCWFxfddOGeYFk,115
3
3
  fprime_gds/version.py,sha256=dlUlfOKTsGaqz_L7TjhCVC-Vanx5cK67kdZlqcHCM8M,395
4
4
  fprime_gds/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- fprime_gds/common/handlers.py,sha256=YyhuF4yg3d7tFgWmbvXfxLDHYgea6Z1hpFd2A27gVZY,4464
5
+ fprime_gds/common/handlers.py,sha256=vPfW1jJpq-oI7c9OTFqZ1LovlhFjx1DEUrfZTk_iuNY,6344
6
6
  fprime_gds/common/transport.py,sha256=uYXWkM8TYEYz1vfY4AEn0PF8Gu4tkYmJ5t4w1YY1yW8,10565
7
7
  fprime_gds/common/zmq_transport.py,sha256=E_iBZ5sA4JKB99MWSOM6XnPrO-mbFyRvD9eQp9te6-Y,12397
8
8
  fprime_gds/common/communication/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -29,21 +29,21 @@ fprime_gds/common/data_types/file_data.py,sha256=4_G9kf4ThC5NzkxnKa0xNYBdi8UDvZg
29
29
  fprime_gds/common/data_types/pkt_data.py,sha256=cxqUnsPte0ijF1E8F1_uglVKIJFAIQbpoBlmwRjMrJY,3405
30
30
  fprime_gds/common/data_types/sys_data.py,sha256=Xfk5xryFg7zWS3VcGUDx9lQYBTajjWXvwkgFK5EUCG4,2095
31
31
  fprime_gds/common/decoders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
- fprime_gds/common/decoders/ch_decoder.py,sha256=mx0yfT-DQqQ8TrmRM3dr79eL9_E-c0gsKiKvvsjAu98,3849
32
+ fprime_gds/common/decoders/ch_decoder.py,sha256=-Vo_GJys-4ohs94XV0ZYB88SNqN0gxxY29Ijt1gwyXY,3847
33
33
  fprime_gds/common/decoders/decoder.py,sha256=9j7u05_nwXaEjR0etsoB--ATsHuILYCXlhk9m9yajKg,2655
34
- fprime_gds/common/decoders/event_decoder.py,sha256=ib-O18V5Z7bcnUUSDE9R0fU--bAZsfxLwuHXm964rzE,4505
34
+ fprime_gds/common/decoders/event_decoder.py,sha256=tF_mg98RDjR0PppymGhmXybYXA0mFqklZXwora-cVtw,4503
35
35
  fprime_gds/common/decoders/file_decoder.py,sha256=Ky2U8bli3YL6GbT9jSSvI73ySOtf0cdZLK4FXTuWjfA,2542
36
- fprime_gds/common/decoders/pkt_decoder.py,sha256=kW8k3OSbMy96w6MzsGWp656lAQvwxrIznWkD3Sbi8Ig,3329
36
+ fprime_gds/common/decoders/pkt_decoder.py,sha256=c1CebqBaD7rAZd9t0AXkGVRTCtvXj0YH9OBN2bJKaTk,3327
37
37
  fprime_gds/common/distributor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
- fprime_gds/common/distributor/distributor.py,sha256=jged1utucsYkVBm5tSaFEXHDg8suiJ_Hn-9YLPCaVXA,8036
38
+ fprime_gds/common/distributor/distributor.py,sha256=hP0mUknxxpKrQfYkf57dHbMItwgUTzpzmkrc1AOHVCw,8034
39
39
  fprime_gds/common/encoders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
40
  fprime_gds/common/encoders/ch_encoder.py,sha256=TBrTJ7TK4WwCh6KAspozh63WcPxrMImloB8tz7qeulw,2878
41
- fprime_gds/common/encoders/cmd_encoder.py,sha256=5wG5854ozmxctnYou3q9MdQNkTQEmpCiT4oBVgNRZdE,3499
42
- fprime_gds/common/encoders/encoder.py,sha256=xgFFCi-qKEKG7T5Qfo-qIadSiY0NSnfDgQUBq21fMhw,2984
41
+ fprime_gds/common/encoders/cmd_encoder.py,sha256=iFPi6uMlMPlApC47p9YKRjKJxMvz46p15Yy3NnGTyaE,3497
42
+ fprime_gds/common/encoders/encoder.py,sha256=jaN-uLHRGAzAs33ZdPm2FTdh3mAvsOCtqO6Ov9hspyI,2997
43
43
  fprime_gds/common/encoders/event_encoder.py,sha256=aM_3hWWx4OrLKF3-MlhmGSBYnzt-4iktSzMVrcUbfB8,3140
44
44
  fprime_gds/common/encoders/file_encoder.py,sha256=G9uUXQP-oD2eW_GJuGNBrN7xPafKFhmgKiNi-zvZz-g,3830
45
45
  fprime_gds/common/encoders/pkt_encoder.py,sha256=6hzwrAEg1tjGw9yGycWMuNgbGCoe87Cd-7eP1rvy2d4,3126
46
- fprime_gds/common/encoders/seq_writer.py,sha256=rH1I8trAHBKjqxQtNg1isTmLWqAjK3xtZbETTCp6RQI,6882
46
+ fprime_gds/common/encoders/seq_writer.py,sha256=g0Rmnlw4qLgJn290ORzJ21jZo0gB2dTvHFWs4pzbmio,6880
47
47
  fprime_gds/common/files/File Decoder Documentation.txt,sha256=a-VYHcUMqh7mBGY2fqvMf1nd3gdg3cLdPKwrulNKXjc,5314
48
48
  fprime_gds/common/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
49
  fprime_gds/common/files/downlinker.py,sha256=CZPfhH0J9-LNqW5Cv_ryicLTuoedLSWK8OPQmmQDZZY,7498
@@ -59,10 +59,10 @@ fprime_gds/common/fpy/parser.py,sha256=g-l67oZN_vB1JAdZ5S3u9m8APf6PdJ88GZyz0iX66
59
59
  fprime_gds/common/fpy/bytecode/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
60
  fprime_gds/common/fpy/bytecode/directives.py,sha256=tBpPQ2ZnQXA7juB85HhacDdil1vEHUKW8m_AsMf1KdQ,13360
61
61
  fprime_gds/common/gds_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
- fprime_gds/common/gds_cli/base_commands.py,sha256=nHnzHRMXs9haRjiUmq-Ciu1DSo1BXtcVscByk1Ypsxo,9432
63
- fprime_gds/common/gds_cli/channels.py,sha256=S8y0Mo2JbBFPvMzeW22HFVJ8p-UC-tzpYM7rXqIGWi4,2136
64
- fprime_gds/common/gds_cli/command_send.py,sha256=pMPwCixiuhk3r1mP7IbHLlItxYf_np8ez0hGhH0yTUw,6608
65
- fprime_gds/common/gds_cli/events.py,sha256=EpaUfDEaXvPwKu7qutkuU1f8zrFoVNsbyCIGUFUloWI,2123
62
+ fprime_gds/common/gds_cli/base_commands.py,sha256=js4SAXPfDYy_ewIL27066XylExxh9S1A-e4NNChWf9s,9430
63
+ fprime_gds/common/gds_cli/channels.py,sha256=BvADGBrsJ2G9zcGpSwJlxLRFiY1bUxtQSTfEOlA3UME,2134
64
+ fprime_gds/common/gds_cli/command_send.py,sha256=SnDBbwKzNluG-yJSsmsQJpNBPmv4O7nMvG6qYbdpI64,6606
65
+ fprime_gds/common/gds_cli/events.py,sha256=9Jpk0C7VI-KldFxo7neaG2MpcKhqH2VE2xaV8G-5pSw,2121
66
66
  fprime_gds/common/gds_cli/filtering_utils.py,sha256=2LxT9tzuNvnwm7HVItv87XkO6K29nOBift2bYcYn3zg,7554
67
67
  fprime_gds/common/gds_cli/test_api_utils.py,sha256=VphGie_VxTMZQGz6p_5AjdEZWXqKJTohrqslRS8VnNU,5109
68
68
  fprime_gds/common/history/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -88,19 +88,18 @@ fprime_gds/common/logger/__init__.py,sha256=TLUbrAnkCtckKGsLzh4hXgEshwQfZsWMDaOO
88
88
  fprime_gds/common/logger/data_logger.py,sha256=VjfhTGO1gGw954xNhSc0_zpw8JexCho5f8BlXDEYkL4,2505
89
89
  fprime_gds/common/logger/test_logger.py,sha256=wL8Lq49sVmxGRALgv-ei6AnXFh79qlHFehmKJ1A8X28,6475
90
90
  fprime_gds/common/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
+ fprime_gds/common/models/dictionaries.py,sha256=MlHR-KEYPzky0IZjhapGCNuvKz2lTo1wtQMKPBI-nOA,8726
91
92
  fprime_gds/common/models/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
- fprime_gds/common/models/common/channel_telemetry.py,sha256=UkLIgWLgVNi2AmPnuT3k9pAmUqNuw2zYHj_r6dB3q5o,4305
93
93
  fprime_gds/common/models/common/command.py,sha256=ASih9dwR_7F94nR1CV7cIuZEJSuaUAzX7JU2_lCAg4g,5476
94
- fprime_gds/common/models/common/event.py,sha256=gSFrCJT9ZddGJfkf3fGCCqk0aMIQV-SNeAhCX6hnbrc,3386
95
94
  fprime_gds/common/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
96
95
  fprime_gds/common/parsers/seq_file_parser.py,sha256=6DZrA0jmt8IqsutfK7pdLtYn4oVHO593rWgAOH63yRg,9587
97
96
  fprime_gds/common/pipeline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
- fprime_gds/common/pipeline/dictionaries.py,sha256=x3QCZAg6YB9bEumZ330PGo0ilJqODGyo_K70RgbQ53M,8009
99
97
  fprime_gds/common/pipeline/encoding.py,sha256=PttJ8NmXm75mLXyhlmxOJqE8RFt46q1dThaV19PyAr4,7216
100
98
  fprime_gds/common/pipeline/files.py,sha256=J2zm0sucvImtmSnv0iUp5uTpvUO8nlmz2lUdMuMC5aM,2244
101
99
  fprime_gds/common/pipeline/histories.py,sha256=7KyboNnm9OARQk4meVPSSeYpeqH0G8RWRiy0BLBL1rw,3671
100
+ fprime_gds/common/pipeline/publishing.py,sha256=A0Hb4RpK7RCBDN9BEiJZr9WQMSrmohYXCFOuzl23mPo,3953
102
101
  fprime_gds/common/pipeline/router.py,sha256=-P1wI0KXEh_snOzDaq8CjEoWuM_zRm8vUMR1T0oY9qQ,2327
103
- fprime_gds/common/pipeline/standard.py,sha256=5aivCoPKfZXH_g0pk4fHHwnNt_dEcj-HMWAa4LleCbA,9837
102
+ fprime_gds/common/pipeline/standard.py,sha256=w6L9kj6phA0twSB-TfEtZIcMWWZwNBm5wzSmz1lyNEA,9239
104
103
  fprime_gds/common/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
105
104
  fprime_gds/common/templates/ch_template.py,sha256=1MoDZsia0dI_CvnIttwyKLhbQhum35OcJnFc50Xohuo,3893
106
105
  fprime_gds/common/templates/cmd_template.py,sha256=n91z4WhFgHwTu6_fQqy7JqpkEObAkllIeEy0AR0DvrQ,5455
@@ -109,7 +108,7 @@ fprime_gds/common/templates/event_template.py,sha256=L0hkWB_kEMhTNodPUqBAev76SMm
109
108
  fprime_gds/common/templates/pkt_template.py,sha256=5Wi6389m5j8w7JITBGfeUnw6CYE1-hjcVJ42NJmLDcE,1794
110
109
  fprime_gds/common/templates/prm_template.py,sha256=qd0UX4ARZuPWvnFbU_DO3HkQY4QgMfqPxNcNhk-dl9A,2303
111
110
  fprime_gds/common/testing_fw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
112
- fprime_gds/common/testing_fw/api.py,sha256=ATxIUWVMjoVUllTr0zd42--xgHE1g_OJKq4ec0UFd5k,67848
111
+ fprime_gds/common/testing_fw/api.py,sha256=HcstOYK1_TYyzxo2O3TsI3QKtQbm6FBP-kG_7ZT1bDM,68091
113
112
  fprime_gds/common/testing_fw/predicates.py,sha256=CsHsVs_EVXCLQLd2NVOvy8MxmUQVxLMr3i1ouEUqOtQ,18371
114
113
  fprime_gds/common/testing_fw/pytest_integration.py,sha256=CAvuH9_3RuKplKQVB3t_jerPr-LPzwPWoM6z3lMs16g,6203
115
114
  fprime_gds/common/tools/README.md,sha256=WVEciyfsbEVGmb9xR5A6Ioy5pBVnCsWOIJfySLeq9YM,2325
@@ -117,18 +116,18 @@ fprime_gds/common/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
117
116
  fprime_gds/common/tools/params.py,sha256=htnMLlUW9HmBo4Qc7kYhnWr1sO6bK2mckdskLt5rDUk,9323
118
117
  fprime_gds/common/tools/seqgen.py,sha256=O57igktjWku5OJhBqezhCjPYUmh4GZM-9qKCChqEW7g,6034
119
118
  fprime_gds/common/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
120
- fprime_gds/common/utils/config_manager.py,sha256=EurtNdApA9zpIjAXmGSTgFUen0UaVDryH5g9LwMhu1E,5539
119
+ fprime_gds/common/utils/config_manager.py,sha256=dMqN204UKLiZzIs7-d--fdYMQ8kBzTX56xexkgFq18s,5550
121
120
  fprime_gds/common/utils/data_desc_type.py,sha256=0AkEMfEa5refd_moovf1hkgKiNakADRzv4soghvf9a4,883
122
121
  fprime_gds/common/utils/event_severity.py,sha256=7qPXHrDaM_REJ7sKBUEJTZIE0D4qVnVajsPDUuHg7sI,300
123
122
  fprime_gds/common/utils/string_util.py,sha256=u_2iahRG3ROu3lAAt_KVcK226gEByElXqrA8mH8eDpI,3584
124
123
  fprime_gds/executables/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
125
- fprime_gds/executables/apps.py,sha256=u79T_PlgMmNmA4YwWjs7LvPMCJnrjnURr05NMthOYP0,13350
126
- fprime_gds/executables/cli.py,sha256=Cv8gHPqPrDil87Gv0dNFyWpRrp4XBC82-tmIy5kbz_U,51223
124
+ fprime_gds/executables/apps.py,sha256=_OLWxby1XvYmmDcecsOAKu34XGf952_ya5uRWf_8Y3I,15127
125
+ fprime_gds/executables/cli.py,sha256=OqcBOpvnj8f8wZjntfbr-pNzCEF3P_-eA58kBqK7iDg,52216
127
126
  fprime_gds/executables/comm.py,sha256=08rO0o0MJgTRngB7Ygu2IL_gEAWKF7WFvFyro1CqReE,5214
128
127
  fprime_gds/executables/data_product_writer.py,sha256=e1Rp2LT_Cpg08f0Ki8GhirC7Wn6LtYiAef7KLAkZHUY,37773
129
128
  fprime_gds/executables/dictionary_merge.py,sha256=3Zy8LcbEdBwmNX2GLN_Nr1DfbLyWYHg-y4jdjTVCXgY,7966
130
- fprime_gds/executables/fprime_cli.py,sha256=CMoT7zWNwM8h2mSZW03AR96wl_XnZXoLNiOZN_sDi38,12431
131
- fprime_gds/executables/run_deployment.py,sha256=Zl0Y9-6i6c8tZhcS7XkAeVQtzn0d9fV-3UJQZ0bnBrc,7237
129
+ fprime_gds/executables/fprime_cli.py,sha256=9_eNU7AzUOMhz4FLPkD_byA9C13c509wGPZN-kdw9Ok,12429
130
+ fprime_gds/executables/run_deployment.py,sha256=4K3isTF7C8FojFvzxLC8vaj1GZpKOuPZQ3CtIYdyhRE,7638
132
131
  fprime_gds/executables/tcpserver.py,sha256=KspVpu5YIuiWKOk5E6UDMKvqXYrRB1j9aX8CkMxysfw,17555
133
132
  fprime_gds/executables/utils.py,sha256=SbzXRe1p41qMPdifvPap5_4v0T42gZZ_Rs_OYfITd80,7626
134
133
  fprime_gds/flask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -245,10 +244,10 @@ fprime_gds/flask/static/third-party/webfonts/fa-solid-900.woff2,sha256=mDS4KtJuK
245
244
  fprime_gds/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
246
245
  fprime_gds/plugin/definitions.py,sha256=QlxW1gNvoiqGMslSJjh3dTFZuv0igFHawN__3XJ0Wns,5355
247
246
  fprime_gds/plugin/system.py,sha256=M9xb-8jBhCUUx3X1z2uAP8Wx_v6NkL8JeaFgGcMnQqY,13432
248
- fprime_gds-4.0.2a1.dist-info/licenses/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
249
- fprime_gds-4.0.2a1.dist-info/licenses/NOTICE.txt,sha256=vXjA_xRcQhd83Vfk5D_vXg5kOjnnXvLuMi5vFKDEVmg,1612
250
- fprime_gds-4.0.2a1.dist-info/METADATA,sha256=7qyu-NnTZ5K22Lo9dJ4Db_4FqR05UWoWZnNDesd__Ks,24576
251
- fprime_gds-4.0.2a1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
252
- fprime_gds-4.0.2a1.dist-info/entry_points.txt,sha256=16r0xeF-Qn-ducW_QvHiyrFnNjnLK-OOaTbqQIQpd0o,494
253
- fprime_gds-4.0.2a1.dist-info/top_level.txt,sha256=6vzFLIX6ANfavKaXFHDMSLFtS94a6FaAsIWhjgYuSNE,27
254
- fprime_gds-4.0.2a1.dist-info/RECORD,,
247
+ fprime_gds-4.0.2a3.dist-info/licenses/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
248
+ fprime_gds-4.0.2a3.dist-info/licenses/NOTICE.txt,sha256=vXjA_xRcQhd83Vfk5D_vXg5kOjnnXvLuMi5vFKDEVmg,1612
249
+ fprime_gds-4.0.2a3.dist-info/METADATA,sha256=G-I0rASiP20RANqp57TUZN8009cPcrzZ2Lydwxx295w,24576
250
+ fprime_gds-4.0.2a3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
251
+ fprime_gds-4.0.2a3.dist-info/entry_points.txt,sha256=16r0xeF-Qn-ducW_QvHiyrFnNjnLK-OOaTbqQIQpd0o,494
252
+ fprime_gds-4.0.2a3.dist-info/top_level.txt,sha256=6vzFLIX6ANfavKaXFHDMSLFtS94a6FaAsIWhjgYuSNE,27
253
+ fprime_gds-4.0.2a3.dist-info/RECORD,,
@@ -1,174 +0,0 @@
1
- """
2
- Created on Apr. 27, 2015
3
-
4
- @author: reder
5
- """
6
-
7
- from fprime.common.models.serialize.type_base import BaseType
8
-
9
- # Import the types this way so they do not need prefixing for execution.
10
- from fprime.common.models.serialize.type_exceptions import (
11
- TypeException,
12
- TypeMismatchException,
13
- )
14
-
15
-
16
- class Channel:
17
- """
18
- Channel class is for deserialize channel telemetry value.
19
- Really this is a container since the type will have it's own deserialize
20
- implementation.
21
- """
22
-
23
- def __init__(
24
- self,
25
- name,
26
- channel_id,
27
- comp_name,
28
- ch_description,
29
- ch_type,
30
- ch_format_string,
31
- low_red,
32
- low_orange,
33
- low_yellow,
34
- high_yellow,
35
- high_orange,
36
- high_red,
37
- ):
38
- """
39
- Constructor
40
- """
41
- #
42
- # Make sure correct types are passed
43
- #
44
- if not isinstance(name, str):
45
- raise TypeMismatchException(str, type(name))
46
-
47
- if not isinstance(channel_id, int):
48
- raise TypeMismatchException(int, type(channel_id))
49
-
50
- if not isinstance(ch_description, str):
51
- raise TypeMismatchException(str, type(ch_description))
52
-
53
- if not isinstance(ch_type, BaseType):
54
- raise TypeMismatchException(BaseType, type(ch_type))
55
-
56
- # Initialize event internal variables
57
- self.__name = name
58
- self.__comp_name = comp_name
59
- self.__id = channel_id
60
- self.__ch_desc = ch_description
61
- self.__ch_type = ch_type
62
- self.__format_string = ch_format_string
63
- self.__low_red = low_red
64
- self.__low_orange = low_orange
65
- self.__low_yellow = low_yellow
66
- self.__high_yellow = high_yellow
67
- self.__high_orange = high_orange
68
- self.__high_red = high_red
69
- #
70
- self.__time_base = None
71
- self.__time_context = None
72
- self.__time_sec = None
73
- self.__time_usec = None
74
- #
75
- self.__changed = False
76
-
77
- def deserialize(self, ser_data, offset):
78
- """
79
- Deserialize event arguments
80
- :param ser_data: Binary input of the channel value.
81
- :param offset: offset in data to deserialize from
82
- :return: value from deserialized channel
83
- """
84
- try:
85
- self.__ch_type.deserialize(ser_data, offset)
86
- val = self.__ch_type.val
87
- except TypeException as e:
88
- print(f"Channel deserialize exception {e.getMsg()}")
89
- val = "ERR"
90
-
91
- #
92
- return val
93
-
94
- def setTime(self, time_base, time_context, time_sec, time_usec):
95
- """
96
- Channel telemetry time updater.
97
- """
98
- self.__time_base = time_base
99
- self.__time_context = time_context
100
- self.__time_sec = time_sec
101
- self.__time_usec = time_usec
102
-
103
- def getTime(self):
104
- """
105
- Return time tuple for UI updater use.
106
- """
107
- return (
108
- self.__time_base,
109
- self.__time_context,
110
- self.__time_sec,
111
- self.__time_usec,
112
- )
113
-
114
- def getName(self):
115
- return self.__name
116
-
117
- def getCompName(self):
118
- return self.__comp_name
119
-
120
- def getId(self):
121
- return self.__id
122
-
123
- def getChDesc(self):
124
- return self.__ch_desc
125
-
126
- def getType(self):
127
- return self.__ch_type
128
-
129
- def getTimeBase(self):
130
- return self.__time_base
131
-
132
- def getTimeContext(self):
133
- return self.__time_context
134
-
135
- def getTimeSec(self):
136
- return self.__time_sec
137
-
138
- def getTimeUsec(self):
139
- return self.__time_usec
140
-
141
- def getFormatString(self):
142
- return self.__format_string
143
-
144
- def getLowRed(self):
145
- return self.__low_red
146
-
147
- def getLowOrange(self):
148
- return self.__low_orange
149
-
150
- def getLowYellow(self):
151
- return self.__low_yellow
152
-
153
- def getHighYellow(self):
154
- return self.__high_yellow
155
-
156
- def getHighOrange(self):
157
- return self.__high_orange
158
-
159
- def getHighRed(self):
160
- return self.__high_red
161
-
162
- @property
163
- def changed(self):
164
- """
165
- change is True if recently updated.
166
- change is False if not changed.
167
- """
168
- return self.__changed
169
-
170
- @changed.setter
171
- def changed(self, ch):
172
- if ch is not False or ch is not True:
173
- ch = True
174
- self.__changed = ch
@@ -1,121 +0,0 @@
1
- """
2
- Created on Feb. 9, 2015
3
-
4
- @author: reder
5
- """
6
-
7
- import traceback
8
- from enum import Enum
9
-
10
- from fprime.common.models.serialize.type_base import BaseType
11
-
12
- # Import the types this way so they do not need prefixing for execution.
13
- from fprime.common.models.serialize.type_exceptions import (
14
- TypeException,
15
- TypeMismatchException,
16
- )
17
-
18
- Severity = Enum(
19
- "Severity", "COMMAND ACTIVITY_LO ACTIVITY_HI WARNING_LO WARNING_HI DIAGNOSTIC FATAL"
20
- )
21
-
22
-
23
- class Event:
24
- """
25
- Event class is for deserializing log event messages.
26
- THis is essentially the equivalent of EVR's in MSL, SMAP, etc.
27
- """
28
-
29
- def __init__(
30
- self, name, event_id, severity, format_string, event_description, arguments
31
- ):
32
- """
33
- Constructor
34
- """
35
-
36
- # Make sure correct types are passed
37
-
38
- if not isinstance(name, str):
39
- raise TypeMismatchException(str, type(name))
40
-
41
- if not isinstance(event_id, int):
42
- raise TypeMismatchException(int, type(event_id))
43
-
44
- if not isinstance(format_string, str):
45
- raise TypeMismatchException(str, type(format_string))
46
-
47
- if not isinstance(event_description, str):
48
- raise TypeMismatchException(str, type(event_description))
49
-
50
- if not isinstance(arguments, list):
51
- raise TypeMismatchException(list, type(arguments))
52
-
53
- for (argname, argdesc, argtype) in arguments:
54
- #
55
- if not isinstance(argname, str):
56
- raise TypeMismatchException(str, type(argname))
57
- #
58
- if not isinstance(argdesc, str):
59
- raise TypeMismatchException(str, type(argdesc))
60
- #
61
- if not isinstance(argtype, BaseType):
62
- raise TypeMismatchException(BaseType, type(argtype))
63
-
64
- # Initialize event internal variables
65
- self.__name = name
66
- self.__id = event_id
67
- self.__severity = severity
68
- self.__format_string = format_string
69
- self.__event_description = event_description
70
- self.__arguments = arguments
71
-
72
- def deserialize(self, ser_data):
73
- """
74
- Deserialize event arguments
75
- @param ser_data: Binary input data of id followed by args
76
- """
77
- vals = []
78
- #
79
- # Next parse the arguments.
80
- #
81
- args = list(self.__arguments)
82
- offset = 0
83
- for arg in args:
84
- arg_obj = arg[2]
85
- try:
86
- # print arg_obj
87
- arg_obj.deserialize(ser_data, offset)
88
- vals.append(arg_obj.val)
89
- except TypeException as e:
90
- print(f"Event deserialize exception {e.getMsg()}")
91
- traceback.print_exc()
92
- vals.append("ERR")
93
- offset = offset + arg_obj.getSize()
94
-
95
- vals = [0] + vals
96
- return vals
97
-
98
- def stringify(self, event_args_list):
99
- """
100
- Return a formatted string of event args.
101
- """
102
- # print event_args_list
103
- return self.__format_string % tuple(event_args_list[1:])
104
-
105
- def getName(self):
106
- return self.__name
107
-
108
- def getId(self):
109
- return self.__id
110
-
111
- def getSeverity(self):
112
- return self.__severity
113
-
114
- def getFormatString(self):
115
- return self.__format_string
116
-
117
- def getEventDescription(self):
118
- return self.__event_description
119
-
120
- def getArgs(self):
121
- return self.__arguments