rccn-gen 1.0.2__py3-none-any.whl → 1.1.0__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.
rccn_gen/__init__.py CHANGED
@@ -1,6 +1,5 @@
1
1
  from .systems import *
2
2
  from .utils import *
3
- from .telemetry import *
4
3
 
5
4
  __version__ = "0.1.0"
6
5
 
rccn_gen/systems.py CHANGED
@@ -1,12 +1,10 @@
1
- from yamcs.pymdb import System, Subsystem, Command
1
+ from yamcs.pymdb import System, Subsystem, Command, Container, AndExpression, EqExpression
2
2
  import shutil
3
3
  import difflib
4
4
  import datetime
5
5
  from caseconverter import *
6
6
  from importlib.resources import files
7
7
  from .utils import *
8
- from .telemetry import *
9
-
10
8
 
11
9
  class Application(Subsystem):
12
10
  """
@@ -191,7 +189,7 @@ class Service(Subsystem):
191
189
  def __init__(
192
190
  self,
193
191
  name: str,
194
- service_id: int = None,
192
+ service_id: int,
195
193
  *args,
196
194
  **kwargs
197
195
  ):
@@ -258,7 +256,7 @@ class Service(Subsystem):
258
256
  return paths
259
257
 
260
258
  def rccn_commands(self):
261
- return [command for command in self.commands if isinstance(command, RCCNCommand)]
259
+ return [command for command in self.commands if isinstance(command, RCCNCommand) and command.name != 'base']
262
260
 
263
261
  def find_and_replace_keywords(self, text, text_modules_path):
264
262
  # Find and replace service module keywords
@@ -274,23 +272,20 @@ class Service(Subsystem):
274
272
  replacement_text = (self.find_and_replace_keywords(module_text, text_modules_path) + '\n')
275
273
  text = insert_before_with_indentation(text, service_module_keyword, replacement_text)
276
274
 
277
- # Call keyword replacement for all associated commands (Later, there needs to be checking to account for user changes to the generated files)
278
- if len(self.rccn_commands()) == 0:
279
- print('RCCN-Gen: Service '+self.name+' does not have any commands associated with it.')
280
275
  for command in self.rccn_commands():
281
276
  text = command.find_and_replace_keywords(text, text_modules_path)
282
277
 
283
278
  # Find and replace service variable keywords
284
279
  var_keywords = get_var_keywords(text)
285
280
  service_var_translation = {
286
- '<<VAR_SERVICE_NAME>>': self.name,
287
- '<<VAR_SERVICE_ID>>': str(self.service_id),
288
- '<<VAR_SERVICE_NAME_UCASE>>': pascalcase(self.name),
289
- '<<VAR_SERVICE_TELEMETRY>>': self.generate_rust_telemetry_definition(),
281
+ '<<VAR_SERVICE_NAME>>': lambda: snakecase(self.name),
282
+ '<<VAR_SERVICE_ID>>': lambda: str(self.service_id),
283
+ '<<VAR_SERVICE_NAME_UCASE>>': lambda: pascalcase(self.name),
284
+ '<<VAR_SERVICE_TELEMETRY>>': lambda: self.generate_rust_telemetry_definition(),
290
285
  }
291
286
  for var_keyword in var_keywords:
292
287
  if var_keyword in service_var_translation.keys():
293
- text = replace_with_indentation(text, var_keyword, service_var_translation[var_keyword])
288
+ text = replace_with_indentation(text, var_keyword, service_var_translation[var_keyword]())
294
289
 
295
290
  # Delete all command module keywords
296
291
  text = delete_all_command_module_keywords(text)
@@ -327,7 +322,7 @@ class Service(Subsystem):
327
322
  self.generate_snapshot('command', 'command_user_snapshot')
328
323
  # Generate command.rs file
329
324
  if len(self.rccn_commands()) == 0:
330
- print('RCCN-Gen: Service '+self.name+' has no implemented commands. Generation of command.rs file will be skipped.')
325
+ print('RCCN-Information: Service \''+self.name+'\' has no commands other than base command. Generation of command.rs file will be skipped.')
331
326
  return
332
327
  command_file_path = self.file_paths()['command_template']
333
328
  with open(command_file_path, 'r') as file:
@@ -385,7 +380,8 @@ class Service(Subsystem):
385
380
  def generate_rust_telemetry_definition(self):
386
381
  telemetry_definition_text = ''
387
382
  for container in self.containers:
388
- container.__class__ = RCCNContainer
383
+ if not isinstance(container, RCCNContainer):
384
+ container.__class__ = RCCNContainer
389
385
  telemetry_definition_text += container.generate_rccn_telemetry()
390
386
  return telemetry_definition_text
391
387
 
@@ -396,22 +392,28 @@ class RCCNCommand(Command):
396
392
  self.init_kwargs = kwargs
397
393
  if 'system' in kwargs and isinstance(kwargs['system'], Service):
398
394
  self.add_to_service(kwargs['system'])
395
+ elif 'base' in kwargs and (isinstance(kwargs['base'], Command) or isinstance(kwargs['base'], RCCNCommand)):
396
+ self.add_to_service(kwargs['base'].system)
399
397
 
400
398
  def add_to_service(self, service):
401
- if not any(command.name == 'base' for command in service.commands):
402
- base_command = Command(
399
+ if not 'base' in self.init_kwargs and not any(command.name == 'base' for command in service.commands):
400
+ print("RCCN-Information: Command \'"+self.init_kwargs['name']+"\' doesn\'t have a base argument and no base command was found in service \'"+service.name+"\'.\nStandard base command will be used with system = \'"+service.name+"\' and type = "+str(service.service_id)+".")
401
+ self.init_kwargs['base'] = Command(
403
402
  system=service,
404
403
  name='base',
405
404
  abstract=True,
406
405
  base='/PUS/pus-tc',
407
406
  assignments={'type': service.service_id}
408
407
  )
409
- self.init_kwargs['base'] = base_command
408
+ elif not 'base' in self.init_kwargs and any(command.name == 'base' for command in service.commands):
409
+ print("RCCN-Information: Command \'"+self.init_kwargs['name']+"\' doesn\'t have a \'base\' argument. Existing base command for service \'"+service.name+"\' will be used.")
410
+ self.init_kwargs['base'] = next(command for command in service.commands if command.name == 'base')
410
411
  if 'system' in self.init_kwargs and isinstance(self.init_kwargs['system'], Service):
411
412
  super().__init__(*self.init_args, **self.init_kwargs)
412
413
  else:
413
414
  super().__init__(system=service, *self.init_args, **self.init_kwargs)
414
415
  self.assignments['apid'] = self.system.system.apid
416
+ self.struct_name = self.name + 'Args'
415
417
 
416
418
 
417
419
  def find_and_replace_keywords(self, text, text_modules_path):
@@ -431,14 +433,16 @@ class RCCNCommand(Command):
431
433
  # Find and replace command variable keywords
432
434
  command_var_keywords = get_var_keywords(text)
433
435
  command_var_translation = {
434
- '<<VAR_COMMAND_NAME_UCASE>>': pascalcase(self.name),
435
- '<<VAR_COMMAND_NAME>>': self.name,
436
- '<<VAR_COMMAND_SUBTYPE>>': str(self.assignments['subtype']),
437
- '<<VAR_COMMAND_STRUCT>>': self.struct_definition()
436
+ '<<VAR_COMMAND_NAME_UCASE>>': lambda: pascalcase(self.name),
437
+ '<<VAR_COMMAND_NAME>>': lambda: self.name,
438
+ '<<VAR_COMMAND_STRUCT_NAME>>': lambda: self.struct_name,
439
+ '<<VAR_COMMAND_SUBTYPE>>': lambda: str(self.assignments['subtype']),
440
+ '<<VAR_COMMAND_STRUCT>>': lambda: self.struct_definition(),
441
+ '<<VAR_SHORT_DESCRIPTION>>': lambda: "\n/// " + self.short_description if self.short_description is not None else "",
438
442
  }
439
443
  for command_var_keyword in command_var_keywords:
440
444
  if command_var_keyword in command_var_translation.keys():
441
- text = replace_with_indentation(text, command_var_keyword, command_var_translation[command_var_keyword])
445
+ text = replace_with_indentation(text, command_var_keyword, command_var_translation[command_var_keyword]())
442
446
  return text
443
447
 
444
448
  def check_user_input(self):
@@ -449,37 +453,78 @@ class RCCNCommand(Command):
449
453
  return os.path.join(self.snapshot_file_path, 'user', datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S"))
450
454
 
451
455
  def struct_definition(self):
456
+ struct_definition_text = ""
452
457
  if len(self.arguments) == 0:
453
458
  return ''
454
- struct_definition_text = "#[derive(BitStruct, Debug, PartialEq)]\npub struct "+pascalcase(self.name)+" {\n"
459
+ if hasattr(self, 'long_description') and self.long_description is not None:
460
+ struct_definition_text += "/// "+str(self.long_description)+"\n"
461
+ struct_definition_text += "#[derive(BitStruct, Debug, PartialEq)]\npub struct "+pascalcase(self.struct_name)+" {\n"
462
+ ins = ""
463
+ append = ""
455
464
  for argument in self.arguments:
456
- struct_definition_text += rust_type_definition(argument)[0]
465
+ arg_def = rust_type_definition(argument)
466
+ ins += arg_def[0]
467
+ append += arg_def[1]
468
+ struct_definition_text += ins
457
469
  struct_definition_text += "}\n"
458
- for argument in self.arguments:
459
- struct_definition_text += rust_type_definition(argument)[1]
470
+ struct_definition_text += append
460
471
  return struct_definition_text
461
472
 
462
473
  class RCCNContainer(Container):
463
- def __init__(self, base="/PUS/pus-tm", *args, **kwargs):
474
+ def __init__(self, base="/PUS/pus-tm", subtype = None, *args, **kwargs):
464
475
  self.base = base
476
+ self.subtype = subtype
465
477
  self.init_args = args
466
478
  self.init_kwargs = kwargs
479
+ self.init_kwargs['base'] = base
480
+ self.name = kwargs['name']
467
481
  if 'system' in kwargs and isinstance(kwargs['system'], Service):
468
482
  self.add_to_service(kwargs['system'])
469
483
 
470
484
  def add_to_service(self, service):
485
+ self.type = service.service_id
486
+ condition_type = None
487
+ condition_subtype = None
488
+ if 'condition' in self.init_kwargs:
489
+ for eq_expression in self.init_kwargs['condition'].expressions:
490
+ if eq_expression.ref == self.base+'/type':
491
+ condition_type = eq_expression.value
492
+ if eq_expression.ref == self.base+'/subtype':
493
+ condition_subtype = eq_expression.value
494
+ if condition_type is not None and condition_type != self.type:
495
+ print('RCCN-Warning: Container '+self.name+' has a user-defined type of '+str(eq_expression.value)+', which does\'nt match the service ID. User-defined type will be used.')
496
+ self.type = condition_type
497
+ if condition_subtype is not None and self.subtype is not None and condition_subtype != self.subtype:
498
+ print('RCCN-Warning: Container '+self.name+' has an ambiguous user-defined subtype. \'subtype\' argument should match the \'condition\' argument.')
499
+ elif condition_subtype is not None:
500
+ self.subtype = condition_subtype
501
+ elif self.subtype is not None and not 'condition' in self.init_kwargs:
502
+ self.init_kwargs['condition'] = AndExpression(
503
+ EqExpression(self.base+'/type', self.type),
504
+ EqExpression(self.base+'/subtype', self.subtype)
505
+ )
506
+ else:
507
+ raise ValueError('RCCN-Error: Container '+self.name+' has no \'condition\' argument and condition could not be created due to a missing \'subtype\' argument.')
508
+
471
509
  if 'system' in self.init_kwargs and isinstance(self.init_kwargs['system'], Service):
472
510
  super().__init__(*self.init_args, **self.init_kwargs)
473
511
  else:
474
512
  super().__init__(system=service, *self.init_args, **self.init_kwargs)
475
513
 
476
514
  def generate_rccn_telemetry(self):
477
- rccn_telemetry_text = "pub struct " + self.name + " {\n"
478
- for parameter_entry in self.entries:
479
- rccn_telemetry_text += rust_type_definition(parameter_entry.parameter)[0]
480
- #rccn_telemetry_text += parameter_entry.generate_rccn_telemetry()[0]
481
- rccn_telemetry_text += "}\n"
515
+ rccn_telemetry_text = ""
516
+ if hasattr(self, 'short_description') and self.short_description is not None:
517
+ rccn_telemetry_text += "/// "+str(self.short_description)+"\n"
518
+ rccn_telemetry_text += "#[derive(ServiceTelemetry, BitStruct, Debug)]\n"
519
+ if hasattr(self, 'subtype') and self.subtype is not None:
520
+ rccn_telemetry_text += "#[subtype("+str(self.subtype)+")]\n"
521
+ rccn_telemetry_text += "pub struct " + self.name + " {\n"
522
+ insert, append = ["",""]
482
523
  for parameter_entry in self.entries:
483
- rccn_telemetry_text += rust_type_definition(parameter_entry.parameter)[1]
484
-
524
+ par_def = rust_type_definition(parameter_entry.parameter)
525
+ insert += par_def[0]
526
+ append += par_def[1]
527
+ rccn_telemetry_text += insert
528
+ rccn_telemetry_text += "}\n\n"
529
+ rccn_telemetry_text += append
485
530
  return rccn_telemetry_text
@@ -11,4 +11,7 @@ futures = "0.3.31"
11
11
  rccn_usr = { version = "0.1.0", path = "../rccn_usr" }
12
12
  satrs = "0.2.1"
13
13
  spacepackets = "0.12.0"
14
- tokio = "1.41.1"
14
+ tokio = "1.41.1"
15
+ env_logger = { version = "0.11.7", default-features = false, features = ["color", "humantime"] }
16
+ num-derive = "0.4"
17
+ num-traits = "0.2"
@@ -1,2 +1,3 @@
1
+ <<VAR_SHORT_DESCRIPTION>>
1
2
  #[subservice(<<VAR_COMMAND_SUBTYPE>>)]
2
- <<VAR_COMMAND_NAME_UCASE>>(<<VAR_COMMAND_NAME>>::Args),
3
+ <<VAR_COMMAND_NAME_UCASE>>(<<VAR_COMMAND_STRUCT_NAME>>),
@@ -1,3 +1,4 @@
1
+ use anyhow::Result;
1
2
  <<SERVICE_MODULE_IMPORT_SERVICE>>
2
3
  use rccn_usr::pus::app::PusApp;
3
4
  use rccn_usr::zenoh::key_expr::OwnedKeyExpr;
@@ -1 +1 @@
1
- use picture_service::service::<<VAR_SERVICE_NAME_UCASE>>;
1
+ use <<VAR_SERVICE_NAME>>::service::<<VAR_SERVICE_NAME_UCASE>>;
@@ -21,7 +21,7 @@ impl <<VAR_SERVICE_NAME_UCASE>> {
21
21
  impl PusService for <<VAR_SERVICE_NAME_UCASE>> {
22
22
  type CommandT = command::Command;
23
23
 
24
- fn handle_tc(&mut self, tc: AcceptedTc, cmd: Self::CommandT) -> AcceptanceResult {
24
+ fn handle_tc(&mut self, mut tc: AcceptedTc, cmd: Self::CommandT) -> AcceptanceResult {
25
25
  println!("PUS-Service: Command received.");
26
26
  match cmd {
27
27
  <<COMMAND_MODULE_MATCH_CMD>>
rccn_gen/utils.py CHANGED
@@ -133,7 +133,9 @@ def rust_type_definition(pymdb_data_instance, parent_name="MyStruct"):
133
133
  pymdb_data_instance.name = singular_name
134
134
  print("RCCN-Gen: Information: An unnamed "+base_type+" has been named \""+pascalcase(pymdb_data_instance.name)+"\" in the generated RCCN code.")
135
135
  sc_instance_name = snakecase(pymdb_data_instance.name)
136
-
136
+ definition_text = ["",""]
137
+ if pymdb_data_instance.short_description is not None:
138
+ definition_text[0] += ("\n\t/// "+str(pymdb_data_instance.short_description)+"\n")
137
139
  if data_type == 'IntegerDataType':
138
140
  if pymdb_data_instance.encoding is None or pymdb_data_instance.encoding.bits is None:
139
141
  raw_bit_number = 8
@@ -143,41 +145,51 @@ def rust_type_definition(pymdb_data_instance, parent_name="MyStruct"):
143
145
  raw_bit_number_str = str(raw_bit_number)
144
146
  eng_bit_number = engineering_bit_number(raw_bit_number)
145
147
  eng_bit_number_str = str(eng_bit_number)
146
- definition_text = ["\t#[bits("+raw_bit_number_str+")]\n"]
148
+ definition_text[0] += "\t#[bits("+raw_bit_number_str+")]\n"
147
149
  if pymdb_data_instance.signed:
148
150
  definition_text[0] += ("\tpub "+sc_instance_name+": i"+eng_bit_number_str+",\n")
149
151
  else:
150
152
  definition_text[0] += ("\tpub "+sc_instance_name+": u"+eng_bit_number_str+",\n")
151
- definition_text.append("")
152
153
 
153
154
  elif data_type == 'BooleanDataType':
154
- definition_text = ["\t#[bits(1)]\n\tpub "+sc_instance_name+": bool,\n"]
155
- definition_text.append("")
155
+ definition_text[0] += ("\t#[bits(1)]\n\tpub "+sc_instance_name+": bool,\n")
156
156
 
157
157
  elif data_type == 'StringDataType':
158
- definition_text = ["\t#[null_terminated]\n\tpub "+sc_instance_name+": String,\n", ""]
158
+ definition_text[0] += "\t#[null_terminated]\n\tpub "+sc_instance_name+": String,\n"
159
159
 
160
160
  elif data_type == 'ArrayDataType':
161
161
  definition_text = rust_type_definition(pymdb_data_instance.data_type, parent_name=pymdb_data_instance.name)
162
162
  definition_text[0] = definition_text[0].replace(': ', ': Vec<').replace(',\n', '>,\n')
163
+ if pymdb_data_instance.short_description is not None:
164
+ definition_text[0] = "\n\t/// "+pymdb_data_instance.short_description+"\n"+definition_text[0]
165
+ if pymdb_data_instance.long_description is not None:
166
+ definition_text[1] = "/// "+pymdb_data_instance.long_description+"\n" + definition_text[1]
163
167
 
164
168
  elif data_type == 'EnumeratedDataType':
165
- definition_text = ["\tpub "+pymdb_data_instance.name+": "+pascalcase(pymdb_data_instance.name)+",\n"]
166
- definition_text.append("pub enum "+pascalcase(pymdb_data_instance.name)+" {\n")
169
+ definition_text[0] += "\t#[bits("+str(pymdb_data_instance.encoding.bits)+")]\n"
170
+ definition_text[0] += "\tpub "+pymdb_data_instance.name+": "+pascalcase(pymdb_data_instance.name)+",\n"
171
+ definition_text[1] += ("#[derive(FromPrimative, ToPrimative, Debug)]\npub enum "+pascalcase(pymdb_data_instance.name)+" {\n")
167
172
  for choice in pymdb_data_instance.choices:
168
173
  definition_text[1] += "\t"+str(choice[1])+" = "+str(choice[0])+",\n"
169
- definition_text[1] += "}\n"
174
+ definition_text[1] += "}\n\n"
175
+ if pymdb_data_instance.long_description is not None:
176
+ definition_text[1] = "/// "+pymdb_data_instance.long_description+"\n" + definition_text[1]
170
177
 
171
178
  elif data_type == 'AggregateDataType':
172
179
  struct_name = pascalcase(pymdb_data_instance.name)
173
- definition_text = ["\tpub "+sc_instance_name+": "+struct_name+",\n"]
174
- definition_text.append("pub struct "+struct_name+" {\n")
175
- for member in pymdb_data_instance.members:
176
- definition_text[1] += rust_type_definition(member, parent_name=pymdb_data_instance.name)[0]
177
- definition_text[1] += "}\n"
180
+ definition_text[0] += "\tpub "+sc_instance_name+": "+struct_name+",\n"
181
+ if pymdb_data_instance.long_description is not None:
182
+ definition_text[1] += "\t/// "+pymdb_data_instance.long_description+"\n"
183
+ definition_text[1] += ("#[derive(FromPrimative, ToPrimative, Debug)]\n")
184
+ definition_text[1] += ("pub struct "+struct_name+" {\n")
185
+ insert, append = ["",""]
178
186
  for member in pymdb_data_instance.members:
179
- definition_text[1] += rust_type_definition(member, parent_name=pymdb_data_instance.name)[1]
180
-
187
+ mem_def = rust_type_definition(member, parent_name=pymdb_data_instance.name)
188
+ insert += mem_def[0]
189
+ append += mem_def[1]
190
+ definition_text[1] += insert
191
+ definition_text[1] += "}\n\n"
192
+ definition_text[1] += append
181
193
  else:
182
194
  definition_text = ["\t// Please implement datatype "+data_type+" here.\n", ""]
183
195
  return definition_text
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rccn_gen
3
- Version: 1.0.2
3
+ Version: 1.1.0
4
4
  Summary: A python based generator for RACCOON OS source files in Rust from yamcs-pymdb config files.
5
5
  Project-URL: Homepage, https://gitlab.com/rccn/pymdb_code_generation
6
6
  Project-URL: Issues, https://gitlab.com/rccn/pymdb_code_generation/issues
@@ -16,19 +16,18 @@ Description-Content-Type: text/markdown
16
16
 
17
17
  # RCCN Code Generator
18
18
  This generator is used to generate Rust files to deploy on the RACCOON OS satellite based on the pymdb config files used to generate the ground station XTCE files.
19
+
20
+ To see whats new, see the [CHANGELOG](CHANGELOG.md).
19
21
  ## Setup
20
- - Pull the repo
21
22
  - Set up a virtual python environment with `python3` and activate:
22
23
  ```zsh
23
24
  python -m venv .venv
24
25
  source .venv/bin/activate
25
26
  ```
26
- - Install pymdb with `pip install yamcs-pymdb`
27
+ - Install with `pip install rccn-gen`
27
28
 
28
29
  ## Using the Generator
29
30
  The generator is based on [`pymdb`](https://github.com/yamcs/pymdb) and uses the same structure. Where `pymdb` gives the user freedom in defining systems, subsystems and their respective relations, the definitions for rust code generation is more restricted. For the rust generation, the user is bound to the following classes:
30
- - Application,
31
- - Service, and
32
31
  - `Application`,
33
32
  - `Service`, and
34
33
  - `RCCNCommand`.
@@ -53,7 +52,13 @@ A service may be defined with the following command.
53
52
  ```python
54
53
  service = Service(name="ExampleService", system=app, service_id = 131)
55
54
  ```
56
- It has the obligatory arguments **name** and **system**. The system corresponds to the application where the service is associated to. Note that each service has one associated app. A service cannot be associated to more than one apps. You may think of the Application-Service-Command structure as a mathematical tree, where merging branches are not allowed. However, you can create multiple instances of the same service and associate them to different applications, or create multiple identical command instances and associate them to different services.
55
+ Or like this:
56
+ ```python
57
+ service = Service(name="ExampleService", service_id = 131)
58
+ app.add_service(service)
59
+ ```
60
+
61
+ It has the obligatory arguments **name** and **system**. The system corresponds to the application where the service is associated to. Note that each service has one associated app. A service cannot be associated to more than one app. You may think of the Application-Service-Command structure as a mathematical tree, where merging branches are not allowed. However, you can create multiple instances of the same service and associate them to different applications, or create multiple identical command instances and associate them to different services.
57
62
 
58
63
  ### RCCNCommand
59
64
  An RCCNCommand can be defined with the following statement.
@@ -65,7 +70,33 @@ RCCNCommand(
65
70
  arguments=[StringArgument("name", encoding=StringEncoding())],
66
71
  )
67
72
  ```
68
- Obligatory arguments are **system**, **base**, **name** and **arguments**. The latter can be an empty list. The definition must contain a subtype definition in the assignment property, like shown in the example.
73
+
74
+ Or like this:
75
+ ```python
76
+ my_command = RCCNCommand(
77
+ assignments={"subtype": 2},
78
+ name="StopProcess",
79
+ arguments=[StringArgument("name", encoding=StringEncoding())],
80
+ )
81
+ service.add_command(my_command)
82
+ ```
83
+
84
+ The only obligatory arguments are **name** and a **subtype assignment**, like shown in the example. The connection to a service can also be achieved with base commands, where every base command must be unique to a service. For example:
85
+
86
+ ```python
87
+ base_cmd = RCCNCommand(
88
+ system=service,
89
+ assignments={"type": service.service_id},
90
+ name="base",
91
+ base="/PUS/pus-tc"
92
+ )
93
+ my_command = RCCNCommand(
94
+ base=base_cmd,
95
+ assignments={"subtype": 2},
96
+ name="StopProcess",
97
+ arguments=[StringArgument("name", encoding=StringEncoding())],
98
+ )
99
+ ```
69
100
 
70
101
  ## Output
71
102
  From the python configuration, the `main.rs`, `service.rs`, `command.rs`, `mod.rs`, `Cargo.toml` and `telemetry.rs` files are generated and are structured accordingly:
@@ -0,0 +1,19 @@
1
+ rccn_gen/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
2
+ rccn_gen/__init__.py,sha256=rBnqIw3uQk-uBbRh9VnungoTRSr2V0Bqos32xFZ44Eo,168
3
+ rccn_gen/systems.py,sha256=a_ylpOnHQL-RSL16HSjPZgonf4wGXiakNsvZcnq-5P8,30079
4
+ rccn_gen/utils.py,sha256=VKnTC2hrgMyLdneksAifnqEgXO27zLQJ9x5igaF35rE,8269
5
+ rccn_gen/text_modules/cargo_toml/cargo.txt,sha256=AYjSo3WJE7lhOcJaiNgXP9Y-DXHDIFIt6p42rDTVNVE,427
6
+ rccn_gen/text_modules/command/command.txt,sha256=8Y-uJilhFLoinftIbn7uKfia9LLMZno2LkoDJ-4Y-9M,345
7
+ rccn_gen/text_modules/command/command_module_enum.txt,sha256=35sBlAV_CzQw95Uf2dNynrYOxVD2tT2XWfEvS4Zx_KY,121
8
+ rccn_gen/text_modules/command/command_module_struct.txt,sha256=FT7Ke0uOVxWYpGC_oj9zafr1ahrH-nf0nSxQje6kToY,22
9
+ rccn_gen/text_modules/main/main.txt,sha256=t8lAYNCgxY8XHHGt8lVeZC103O1YLEY82UoTZ2U7S2I,446
10
+ rccn_gen/text_modules/main/service_module_import_service.txt,sha256=BYPvt2VrTV4yjt7SSAPYKzvQOBIqeDQsMzgzTQ8XmZY,62
11
+ rccn_gen/text_modules/main/service_module_mod_service.txt,sha256=guvXFdV_-YezhTD_PWA-Z0tL8ReSZc0rh3RuWraJnQE,25
12
+ rccn_gen/text_modules/main/service_module_register_service.txt,sha256=4EIsgaxDLh51u0WjXfy7Xgo-6UFTdb4Nh2O4J7uFjS0,115
13
+ rccn_gen/text_modules/mod/mod.txt,sha256=BF8LablBE4ddutdl5m0prvpvLdBRejueVOujkyrLe7I,52
14
+ rccn_gen/text_modules/service/command_module_match_cmd.txt,sha256=eVGo6ltuerG37rVxpXtL-JYuLyLW4c0i6NXb5g1_U-A,89
15
+ rccn_gen/text_modules/service/service.txt,sha256=qTxoOD5i7wH4yFiDn13rOJW9hIZyACA8W3m6UABe22U,695
16
+ rccn_gen/text_modules/telemetry/telemetry.txt,sha256=Re1d3BfpyXT_CEe7jJzLF3MARik0-J-K98K85iPOE40,193
17
+ rccn_gen-1.1.0.dist-info/METADATA,sha256=O6tvxJsBHrtdX0kxFW9j7MU_oSFGW0CAVD_9Mi_WCnk,8924
18
+ rccn_gen-1.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
19
+ rccn_gen-1.1.0.dist-info/RECORD,,
rccn_gen/application.py DELETED
File without changes
rccn_gen/service.py DELETED
File without changes
rccn_gen/telemetry.py DELETED
@@ -1,83 +0,0 @@
1
- from yamcs.pymdb import Container, ParameterEntry, AggregateParameter, ArrayParameter, BinaryParameter, StringParameter, BooleanParameter, FloatParameter, IntegerParameter, StringMember, EnumeratedMember
2
- from .utils import *
3
-
4
-
5
- def generate_rccn_parameter_telemetry(parameter):
6
- sc_parameter_name = to_snake_case(parameter.name)
7
-
8
- if isinstance(parameter, ArrayParameter):
9
- struct_name = to_upper_camel_case(parameter.name)
10
- telemetry = ["\tpub "+sc_parameter_name+": Vec<"+struct_name+">,\n"]
11
- telemetry.append("pub struct "+struct_name+" {\n")
12
- for member in parameter.data_type.members:
13
- telemetry[1] += generate_rccn_member_telementry(member)[0]
14
- telemetry[1] += "}\n"
15
- for member in parameter.data_type.members:
16
- telemetry[1] += generate_rccn_member_telementry(member)[1]
17
-
18
- elif isinstance(parameter, BooleanParameter):
19
- telemetry = ["\t#[bits(1)]\n\tpub "+sc_parameter_name+": bool,\n"]
20
- telemetry.append("")
21
-
22
- elif isinstance(parameter, IntegerParameter):
23
- if parameter.encoding is None or parameter.encoding.bits is None:
24
- raw_bit_number_str = '8'
25
- print("Warning: No encoding for parameter "+parameter.name+" found. Using 8 as default for raw bit number.")
26
- else:
27
- raw_bit_number = parameter.encoding.bits
28
- raw_bit_number_str = str(raw_bit_number)
29
- eng_bit_number = engineering_bit_number(raw_bit_number)
30
- eng_bit_number_str = str(eng_bit_number)
31
- telemetry = ["\t#[bits("+raw_bit_number_str+")]\n"]
32
- if parameter.signed:
33
- telemetry[0] += ("\tpub "+sc_parameter_name+": i"+eng_bit_number_str+",\n")
34
- else:
35
- telemetry += ("\tpub "+sc_parameter_name+": u"+eng_bit_number_str+",\n")
36
- telemetry.append("")
37
-
38
- elif isinstance(parameter, StringParameter):
39
- telemetry = ["#[null_terminated]\npub "+sc_parameter_name+": String,\n"]
40
- telemetry.append("")
41
-
42
- else:
43
- telemetry = ["\t// Please implement datatype "+type(parameter).__name__+" here.\n", ""]
44
- return telemetry
45
-
46
- def generate_rccn_member_telementry(member):
47
- sc_member_name = to_snake_case(member.name)
48
-
49
- if isinstance(member, StringMember):
50
- member_telemetry = ["#[null_terminated]\n\tpub "+member.name+": String,\n"]
51
- member_telemetry.append("")
52
-
53
- elif isinstance(member, EnumeratedMember):
54
- member_telemetry = ["\tpub "+member.name+": "+to_upper_camel_case(member.name)+",\n"]
55
- member_telemetry.append("pub enum "+to_upper_camel_case(member.name)+" {\n")
56
- for choice in member.choices:
57
- member_telemetry[1] += "\t"+str(choice[1])+" = "+str(choice[0])+",\n"
58
- member_telemetry[1] += "}\n"
59
-
60
- elif isinstance(member, BooleanParameter):
61
- telemetry = ["pub "+sc_member_name+": bool,\n"]
62
- telemetry.append("")
63
-
64
- elif isinstance(member, IntegerParameter):
65
- if member.encoding is None or member.encoding.bits is None:
66
- raw_bit_number = 8
67
- print("Warning: No encoding for member "+member.name+" found. Using 8 as default for raw bit number.")
68
- else:
69
- raw_bit_number = member.encoding.bits
70
- raw_bit_number_str = str(raw_bit_number)
71
- eng_bit_number = engineering_bit_number(raw_bit_number)
72
- eng_bit_number_str = str(eng_bit_number)
73
- telemetry = ["\t#[bits("+raw_bit_number_str+")]\n"]
74
- if member.signed:
75
- telemetry[0] += ("\tpub "+sc_member_name+": i"+eng_bit_number_str+",\n")
76
- else:
77
- telemetry += ("\tpub "+sc_member_name+": u"+eng_bit_number_str+",\n")
78
- telemetry.append("")
79
-
80
- else:
81
- member_telemetry[0] += "\t// Please implement datatype "+type(member).__name__+" here.\n"
82
- member_telemetry.append("")
83
- return member_telemetry
@@ -1,22 +0,0 @@
1
- rccn_gen/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
2
- rccn_gen/__init__.py,sha256=XVvKYcWw9K1P3J1BTbzbODY71Nc1FApCc0wf7ezd4Gc,193
3
- rccn_gen/application.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- rccn_gen/service.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- rccn_gen/systems.py,sha256=ibpegtBKPF-w6hmiWC_-TgJII6uvWP8wRSDpwEq8rjY,26755
6
- rccn_gen/telemetry.py,sha256=huVcqGs95IXlpETWdlIyR9lK4ctZUsq7czgJwvTYtBk,3855
7
- rccn_gen/utils.py,sha256=HF79aMpovRdqLdVjL1w0iEPTEvOl7VSPrf_9QifUyoc,7290
8
- rccn_gen/text_modules/cargo_toml/cargo.txt,sha256=2e6xKomkml6-onfQ0QHNqvKnhGLYMUl8zYgbykmm83Y,292
9
- rccn_gen/text_modules/command/command.txt,sha256=8Y-uJilhFLoinftIbn7uKfia9LLMZno2LkoDJ-4Y-9M,345
10
- rccn_gen/text_modules/command/command_module_enum.txt,sha256=ApzRDQIs-BHJHtFA4ysfpYuWElGntXakkzZkgy57b74,94
11
- rccn_gen/text_modules/command/command_module_struct.txt,sha256=FT7Ke0uOVxWYpGC_oj9zafr1ahrH-nf0nSxQje6kToY,22
12
- rccn_gen/text_modules/main/main.txt,sha256=UQ0oHbzH7H3G4mxfeiTh5UeQ-X4C0Fw7IrCyZNH2clQ,426
13
- rccn_gen/text_modules/main/service_module_import_service.txt,sha256=qPrU4fLs7Y65X5KJ868ut-izV5pHq7hU2nVRLxPnFCE,57
14
- rccn_gen/text_modules/main/service_module_mod_service.txt,sha256=guvXFdV_-YezhTD_PWA-Z0tL8ReSZc0rh3RuWraJnQE,25
15
- rccn_gen/text_modules/main/service_module_register_service.txt,sha256=4EIsgaxDLh51u0WjXfy7Xgo-6UFTdb4Nh2O4J7uFjS0,115
16
- rccn_gen/text_modules/mod/mod.txt,sha256=BF8LablBE4ddutdl5m0prvpvLdBRejueVOujkyrLe7I,52
17
- rccn_gen/text_modules/service/command_module_match_cmd.txt,sha256=eVGo6ltuerG37rVxpXtL-JYuLyLW4c0i6NXb5g1_U-A,89
18
- rccn_gen/text_modules/service/service.txt,sha256=0KwwrfrjXuY4e3VNpCdTTzgW8bmYRQ21i-Lvhkz3hVA,691
19
- rccn_gen/text_modules/telemetry/telemetry.txt,sha256=Re1d3BfpyXT_CEe7jJzLF3MARik0-J-K98K85iPOE40,193
20
- rccn_gen-1.0.2.dist-info/METADATA,sha256=SmSD9_-46j9ZXvYAhuVPr2hINx0_xHOihSPJ31vfwVc,8260
21
- rccn_gen-1.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
22
- rccn_gen-1.0.2.dist-info/RECORD,,