openc3 6.9.2 → 6.10.0

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/data/config/command_modifiers.yaml +79 -0
  3. data/data/config/item_modifiers.yaml +5 -0
  4. data/data/config/parameter_modifiers.yaml +5 -0
  5. data/data/config/telemetry_modifiers.yaml +79 -0
  6. data/ext/openc3/ext/packet/packet.c +9 -0
  7. data/lib/openc3/accessors/accessor.rb +27 -3
  8. data/lib/openc3/accessors/binary_accessor.rb +21 -4
  9. data/lib/openc3/accessors/template_accessor.rb +3 -2
  10. data/lib/openc3/api/cmd_api.rb +7 -3
  11. data/lib/openc3/api/tlm_api.rb +17 -7
  12. data/lib/openc3/interfaces/protocols/fixed_protocol.rb +19 -13
  13. data/lib/openc3/io/json_rpc.rb +6 -0
  14. data/lib/openc3/microservices/decom_microservice.rb +97 -17
  15. data/lib/openc3/microservices/interface_decom_common.rb +32 -0
  16. data/lib/openc3/microservices/interface_microservice.rb +3 -75
  17. data/lib/openc3/microservices/queue_microservice.rb +16 -1
  18. data/lib/openc3/migrations/20251022000000_remove_unique_id.rb +23 -0
  19. data/lib/openc3/models/plugin_model.rb +7 -1
  20. data/lib/openc3/models/queue_model.rb +32 -5
  21. data/lib/openc3/models/reaction_model.rb +25 -9
  22. data/lib/openc3/models/target_model.rb +78 -10
  23. data/lib/openc3/packets/commands.rb +33 -7
  24. data/lib/openc3/packets/packet.rb +75 -71
  25. data/lib/openc3/packets/packet_config.rb +78 -29
  26. data/lib/openc3/packets/packet_item.rb +11 -103
  27. data/lib/openc3/packets/parsers/packet_item_parser.rb +177 -34
  28. data/lib/openc3/packets/parsers/xtce_converter.rb +2 -2
  29. data/lib/openc3/packets/structure.rb +29 -21
  30. data/lib/openc3/packets/structure_item.rb +31 -19
  31. data/lib/openc3/packets/telemetry.rb +37 -11
  32. data/lib/openc3/script/suite_results.rb +2 -2
  33. data/lib/openc3/subpacketizers/subpacketizer.rb +18 -0
  34. data/lib/openc3/system/target.rb +3 -32
  35. data/lib/openc3/tools/table_manager/table_config.rb +9 -1
  36. data/lib/openc3/tools/table_manager/table_item_parser.rb +2 -2
  37. data/lib/openc3/top_level.rb +45 -19
  38. data/lib/openc3/topics/decom_interface_topic.rb +31 -0
  39. data/lib/openc3/utilities/env_helper.rb +10 -0
  40. data/lib/openc3/utilities/logger.rb +7 -11
  41. data/lib/openc3/version.rb +6 -6
  42. data/tasks/spec.rake +2 -1
  43. data/templates/tool_angular/package.json +2 -2
  44. data/templates/tool_react/package.json +1 -1
  45. data/templates/tool_svelte/package.json +1 -1
  46. data/templates/tool_vue/package.json +3 -3
  47. data/templates/widget/package.json +2 -2
  48. metadata +4 -1
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2024, OpenC3, Inc.
17
+ # All changes Copyright 2025, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -113,6 +113,12 @@ module OpenC3
113
113
  # @return [Boolean] If this packet is marked as restricted use
114
114
  attr_accessor :restricted
115
115
 
116
+ # @return [Boolean] If this packet is marked as a subpacket
117
+ attr_accessor :subpacket
118
+
119
+ # @return [Subpacketizer] Subpacketizer class (optional)
120
+ attr_accessor :subpacketizer
121
+
116
122
  # Valid format types
117
123
  VALUE_TYPES = [:RAW, :CONVERTED, :FORMATTED, :WITH_UNITS]
118
124
 
@@ -156,7 +162,9 @@ module OpenC3
156
162
  @virtual = false
157
163
  @restricted = false
158
164
  @validator = nil
159
- @obfuscated_items = []
165
+ @subpacket = false
166
+ @subpacketizer = nil
167
+ @obfuscated_items = nil
160
168
  end
161
169
 
162
170
  # Sets the target name this packet is associated with. Unidentified packets
@@ -581,6 +589,25 @@ module OpenC3
581
589
  packet_define_item(item, format_string, read_conversion, write_conversion, id_value)
582
590
  end
583
591
 
592
+ # @param item [StructureItem] item to make a parent item for a structure
593
+ # @param structure [Structure] structure to associate with the parent item
594
+ def structurize_item(item, structure)
595
+ item.structure = structure
596
+ item.hidden = true
597
+ structure.sorted_items.each do |sorted_item|
598
+ next if RESERVED_ITEM_NAMES.include?(sorted_item.name)
599
+ cloned_item = sorted_item.clone
600
+ cloned_item.key = cloned_item.name
601
+ cloned_item.name = "#{item.name}.#{cloned_item.name}"
602
+ cloned_item.parent_item = item
603
+ cloned_item.bit_offset = item.bit_offset
604
+ if sorted_item.bit_size <= 0
605
+ cloned_item.bit_size = item.bit_size
606
+ end
607
+ define(cloned_item)
608
+ end
609
+ end
610
+
584
611
  # (see Structure#get_item)
585
612
  def get_item(name)
586
613
  return super(name)
@@ -872,7 +899,12 @@ module OpenC3
872
899
  @sorted_items.each do |item|
873
900
  next if RESERVED_ITEM_NAMES.include?(item.name)
874
901
 
875
- unless item.default.nil?
902
+ if item.structure
903
+ unless skip_item_names and upcase_skip_item_names.include?(item.name)
904
+ item.structure.restore_defaults(item.structure.buffer(false), skip_item_names, use_template)
905
+ write_item(item, item.structure.buffer(false), :RAW, buffer)
906
+ end
907
+ elsif not item.default.nil? and not item.parent_item
876
908
  write_item(item, item.default, :CONVERTED, buffer) unless skip_item_names and upcase_skip_item_names.include?(item.name)
877
909
  end
878
910
  end
@@ -1087,6 +1119,9 @@ module OpenC3
1087
1119
  else
1088
1120
  config << "COMMAND #{@target_name.to_s.quote_if_necessary} #{@packet_name.to_s.quote_if_necessary} #{@default_endianness} \"#{@description}\"\n"
1089
1121
  end
1122
+ if @subpacketizer
1123
+ config << " SUBPACKETIZER #{@subpacketizer.class} #{@subpacketizer.args.map { |a| a.to_s.quote_if_necessary }.join(" ")}\n"
1124
+ end
1090
1125
  if @accessor.class.to_s != 'OpenC3::BinaryAccessor'
1091
1126
  config << " ACCESSOR #{@accessor.class} #{@accessor.args.map { |a| a.to_s.quote_if_necessary }.join(" ")}\n"
1092
1127
  end
@@ -1107,6 +1142,9 @@ module OpenC3
1107
1142
  elsif @hidden
1108
1143
  config << " HIDDEN\n"
1109
1144
  end
1145
+ if @subpacket
1146
+ config << " SUBPACKET\n"
1147
+ end
1110
1148
  if @restricted
1111
1149
  config << " RESTRICTED\n"
1112
1150
  end
@@ -1170,6 +1208,8 @@ module OpenC3
1170
1208
  config['disabled'] = true if @disabled
1171
1209
  config['hidden'] = true if @hidden
1172
1210
  config['virtual'] = true if @virtual
1211
+ config['subpacket'] = true if @subpacket
1212
+ config['subpacketizer'] = @subpacketizer.class.to_s if @subpacketizer
1173
1213
  config['restricted'] = true if @restricted
1174
1214
  config['accessor'] = @accessor.class.to_s
1175
1215
  config['accessor_args'] = @accessor.args
@@ -1218,60 +1258,6 @@ module OpenC3
1218
1258
  config
1219
1259
  end
1220
1260
 
1221
- def self.from_json(hash)
1222
- endianness = hash['endianness'] ? hash['endianness'].intern : nil # Convert to symbol
1223
- packet = Packet.new(hash['target_name'], hash['packet_name'], endianness, hash['description'])
1224
- packet.short_buffer_allowed = hash['short_buffer_allowed']
1225
- packet.hazardous = hash['hazardous']
1226
- packet.hazardous_description = hash['hazardous_description']
1227
- packet.messages_disabled = hash['messages_disabled']
1228
- packet.disabled = hash['disabled']
1229
- packet.hidden = hash['hidden']
1230
- packet.virtual = hash['virtual']
1231
- packet.restricted = hash['restricted']
1232
- if hash['accessor']
1233
- begin
1234
- accessor = OpenC3::const_get(hash['accessor'])
1235
- if hash['accessor_args'] and hash['accessor_args'].length > 0
1236
- packet.accessor = accessor.new(packet, *hash['accessor_args'])
1237
- else
1238
- packet.accessor = accessor.new(packet)
1239
- end
1240
- rescue => e
1241
- Logger.instance.error "#{packet.target_name} #{packet.packet_name} accessor of #{hash['accessor']} could not be found due to #{e}"
1242
- end
1243
- end
1244
- if hash['validator']
1245
- begin
1246
- validator = OpenC3::const_get(hash['validator'])
1247
- packet.validator = validator.new(packet)
1248
- rescue => e
1249
- Logger.instance.error "#{packet.target_name} #{packet.packet_name} validator of #{hash['validator']} could not be found due to #{e}"
1250
- end
1251
- end
1252
- packet.template = Base64.decode64(hash['template']) if hash['template']
1253
- packet.meta = hash['meta']
1254
- # Can't convert processors
1255
- hash['items'].each do |item|
1256
- packet.define(PacketItem.from_json(item))
1257
- end
1258
- if hash['response']
1259
- packet.response = hash['response']
1260
- end
1261
- if hash['error_response']
1262
- packet.error_response = hash['error_response']
1263
- end
1264
- if hash['screen']
1265
- packet.screen = hash['screen']
1266
- end
1267
- if hash['related_items']
1268
- packet.related_items = hash['related_items']
1269
- end
1270
- packet.ignore_overlap = hash['ignore_overlap']
1271
-
1272
- packet
1273
- end
1274
-
1275
1261
  def decom
1276
1262
  # Read all the RAW at once because this could be optimized by the accessor
1277
1263
  json_hash = read_items(@sorted_items)
@@ -1285,12 +1271,16 @@ module OpenC3
1285
1271
 
1286
1272
  # Now read all other value types - no accessor required
1287
1273
  @sorted_items.each do |item|
1288
- given_raw = json_hash[item.name]
1289
- json_hash["#{item.name}__C"] = read_item(item, :CONVERTED, @buffer, given_raw) if item.states or (item.read_conversion and item.data_type != :DERIVED)
1290
- json_hash["#{item.name}__F"] = read_item(item, :FORMATTED, @buffer, given_raw) if item.format_string
1291
- json_hash["#{item.name}__U"] = read_item(item, :WITH_UNITS, @buffer, given_raw) if item.units
1292
- limits_state = item.limits.state
1293
- json_hash["#{item.name}__L"] = limits_state if limits_state
1274
+ if item.hidden
1275
+ json_hash.delete(item.name)
1276
+ else
1277
+ given_raw = json_hash[item.name]
1278
+ json_hash["#{item.name}__C"] = read_item(item, :CONVERTED, @buffer, given_raw) if item.states or (item.read_conversion and item.data_type != :DERIVED)
1279
+ json_hash["#{item.name}__F"] = read_item(item, :FORMATTED, @buffer, given_raw) if item.format_string
1280
+ json_hash["#{item.name}__U"] = read_item(item, :WITH_UNITS, @buffer, given_raw) if item.units
1281
+ limits_state = item.limits.state
1282
+ json_hash["#{item.name}__L"] = limits_state if limits_state
1283
+ end
1294
1284
  end
1295
1285
 
1296
1286
  json_hash
@@ -1306,6 +1296,14 @@ module OpenC3
1306
1296
  end
1307
1297
  end
1308
1298
 
1299
+ def subpacketize
1300
+ if @subpacketizer
1301
+ return @subpacketizer.call(self)
1302
+ else
1303
+ return [self]
1304
+ end
1305
+ end
1306
+
1309
1307
  def obfuscate()
1310
1308
  return unless @buffer
1311
1309
  return unless @obfuscated_items
@@ -1317,17 +1315,21 @@ module OpenC3
1317
1315
  current_value = read(item.name, :RAW)
1318
1316
 
1319
1317
  case current_value
1318
+ when Hash
1319
+ obfuscated_value = {}
1320
1320
  when Array
1321
1321
  # For arrays, create a new array of zeros with the same size
1322
1322
  case item.data_type
1323
- when :INT, :UINT
1324
- obfuscated_value = Array.new(current_value.size, 0)
1325
- when :FLOAT
1326
- obfuscated_value = Array.new(current_value.size, 0.0)
1327
- when :STRING, :BLOCK
1328
- obfuscated_value = Array.new(current_value.size) { |i|
1329
- "\x00" * current_value[i].length if current_value[i]
1330
- }
1323
+ when :INT, :UINT
1324
+ obfuscated_value = Array.new(current_value.size, 0)
1325
+ when :FLOAT
1326
+ obfuscated_value = Array.new(current_value.size, 0.0)
1327
+ when :STRING, :BLOCK
1328
+ obfuscated_value = Array.new(current_value.size) { |i|
1329
+ "\x00" * current_value[i].length if current_value[i]
1330
+ }
1331
+ when :BOOL, :ARRAY, :OBJECT, :ANY
1332
+ obfuscated_value = []
1331
1333
  else
1332
1334
  obfuscated_value = Array.new(current_value.size, 0)
1333
1335
  end
@@ -1340,6 +1342,8 @@ module OpenC3
1340
1342
  obfuscated_value = 0
1341
1343
  when :FLOAT
1342
1344
  obfuscated_value = 0.0
1345
+ when :BOOL
1346
+ obfuscated_value = false
1343
1347
  else
1344
1348
  obfuscated_value = 0
1345
1349
  end
@@ -79,17 +79,29 @@ module OpenC3
79
79
  # that returns a hash keyed by an array of id values. The id values resolve to the packet
80
80
  # defined by that identification. Command version
81
81
  attr_reader :cmd_id_value_hash
82
+ attr_reader :cmd_subpacket_id_value_hash
83
+ attr_reader :cmd_id_signature
84
+ attr_reader :cmd_subpacket_id_signature
85
+ attr_reader :cmd_unique_id_mode
86
+ attr_reader :cmd_subpacket_unique_id_mode
82
87
 
83
88
  # @return [Hash<String>=>Hash<Array>=>Packet] Hash keyed by target name
84
89
  # that returns a hash keyed by an array of id values. The id values resolve to the packet
85
90
  # defined by that identification. Telemetry version
86
91
  attr_reader :tlm_id_value_hash
92
+ attr_reader :tlm_subpacket_id_value_hash
93
+ attr_reader :tlm_id_signature
94
+ attr_reader :tlm_subpacket_id_signature
95
+ attr_reader :tlm_unique_id_mode
96
+ attr_reader :tlm_subpacket_unique_id_mode
87
97
 
88
98
  # @return [String] Language of current target (ruby or python)
89
99
  attr_reader :language
90
100
 
91
101
  COMMAND = "Command"
92
102
  TELEMETRY = "Telemetry"
103
+ # Note: DERIVED is not a valid converted type. Also TIME is currently only a converted type
104
+ CONVERTED_DATA_TYPES = [:INT, :UINT, :FLOAT, :STRING, :BLOCK, :BOOL, :OBJECT, :ARRAY, :ANY, :TIME]
93
105
 
94
106
  def initialize
95
107
  @name = nil
@@ -102,7 +114,17 @@ module OpenC3
102
114
  @latest_data = {}
103
115
  @warnings = []
104
116
  @cmd_id_value_hash = {}
117
+ @cmd_subpacket_id_value_hash = {}
118
+ @cmd_id_signature = {}
119
+ @cmd_subpacket_id_signature = {}
120
+ @cmd_unique_id_mode = {}
121
+ @cmd_subpacket_unique_id_mode = {}
105
122
  @tlm_id_value_hash = {}
123
+ @tlm_subpacket_id_value_hash = {}
124
+ @tlm_id_signature = {}
125
+ @tlm_subpacket_id_signature = {}
126
+ @tlm_unique_id_mode = {}
127
+ @tlm_subpacket_unique_id_mode = {}
106
128
 
107
129
  # Create unknown packets
108
130
  @commands['UNKNOWN'] = {}
@@ -222,7 +244,8 @@ module OpenC3
222
244
  'APPEND_PARAMETER', 'APPEND_ID_ITEM', 'APPEND_ID_PARAMETER', 'APPEND_ARRAY_ITEM',\
223
245
  'APPEND_ARRAY_PARAMETER', 'ALLOW_SHORT', 'HAZARDOUS', 'PROCESSOR', 'META',\
224
246
  'DISABLE_MESSAGES', 'HIDDEN', 'DISABLED', 'VIRTUAL', 'RESTRICTED', 'ACCESSOR', 'TEMPLATE', 'TEMPLATE_FILE',\
225
- 'RESPONSE', 'ERROR_RESPONSE', 'SCREEN', 'RELATED_ITEM', 'IGNORE_OVERLAP', 'VALIDATOR'
247
+ 'RESPONSE', 'ERROR_RESPONSE', 'SCREEN', 'RELATED_ITEM', 'IGNORE_OVERLAP', 'VALIDATOR', 'SUBPACKET', 'SUBPACKETIZER',\
248
+ 'STRUCTURE', 'APPEND_STRUCTURE'
226
249
  raise parser.error("No current packet for #{keyword}") unless @current_packet
227
250
 
228
251
  process_current_packet(parser, keyword, params)
@@ -321,18 +344,20 @@ module OpenC3
321
344
  PacketParser.check_item_data_types(@current_packet)
322
345
  @commands[@current_packet.target_name][@current_packet.packet_name] = @current_packet
323
346
  unless @current_packet.virtual
324
- hash = @cmd_id_value_hash[@current_packet.target_name]
325
- hash = {} unless hash
326
- @cmd_id_value_hash[@current_packet.target_name] = hash
327
- update_id_value_hash(@current_packet, hash)
347
+ if @current_packet.subpacket
348
+ build_id_metadata(@current_packet, @cmd_subpacket_id_value_hash, @cmd_subpacket_id_signature, @cmd_subpacket_unique_id_mode)
349
+ else
350
+ build_id_metadata(@current_packet, @cmd_id_value_hash, @cmd_id_signature, @cmd_unique_id_mode)
351
+ end
328
352
  end
329
353
  else
330
354
  @telemetry[@current_packet.target_name][@current_packet.packet_name] = @current_packet
331
355
  unless @current_packet.virtual
332
- hash = @tlm_id_value_hash[@current_packet.target_name]
333
- hash = {} unless hash
334
- @tlm_id_value_hash[@current_packet.target_name] = hash
335
- update_id_value_hash(@current_packet, hash)
356
+ if @current_packet.subpacket
357
+ build_id_metadata(@current_packet, @tlm_subpacket_id_value_hash, @tlm_subpacket_id_signature, @tlm_subpacket_unique_id_mode)
358
+ else
359
+ build_id_metadata(@current_packet, @tlm_id_value_hash, @tlm_id_signature, @tlm_unique_id_mode)
360
+ end
336
361
  end
337
362
  end
338
363
  @current_packet = nil
@@ -345,10 +370,11 @@ module OpenC3
345
370
  @commands[packet.target_name][packet.packet_name] = packet
346
371
 
347
372
  if affect_ids and not packet.virtual
348
- hash = @cmd_id_value_hash[packet.target_name]
349
- hash = {} unless hash
350
- @cmd_id_value_hash[packet.target_name] = hash
351
- update_id_value_hash(packet, hash)
373
+ if packet.subpacket
374
+ build_id_metadata(packet, @cmd_subpacket_id_value_hash, @cmd_subpacket_id_signature, @cmd_subpacket_unique_id_mode)
375
+ else
376
+ build_id_metadata(packet, @cmd_id_value_hash, @cmd_id_signature, @cmd_unique_id_mode)
377
+ end
352
378
  end
353
379
  else
354
380
  @telemetry[packet.target_name][packet.packet_name] = packet
@@ -362,10 +388,11 @@ module OpenC3
362
388
  end
363
389
 
364
390
  if affect_ids and not packet.virtual
365
- hash = @tlm_id_value_hash[packet.target_name]
366
- hash = {} unless hash
367
- @tlm_id_value_hash[packet.target_name] = hash
368
- update_id_value_hash(packet, hash)
391
+ if packet.subpacket
392
+ build_id_metadata(packet, @tlm_subpacket_id_value_hash, @tlm_subpacket_id_signature, @tlm_subpacket_unique_id_mode)
393
+ else
394
+ build_id_metadata(packet, @tlm_id_value_hash, @tlm_id_signature, @tlm_unique_id_mode)
395
+ end
369
396
  end
370
397
  end
371
398
  end
@@ -398,15 +425,32 @@ module OpenC3
398
425
 
399
426
  protected
400
427
 
401
- def update_id_value_hash(packet, hash)
428
+ def build_id_metadata(packet, id_value_hash, id_signature_hash, unique_id_mode_hash)
429
+ target_id_value_hash = id_value_hash[packet.target_name]
430
+ target_id_value_hash = {} unless target_id_value_hash
431
+ id_value_hash[packet.target_name] = target_id_value_hash
432
+ update_id_value_hash(packet, target_id_value_hash, id_signature_hash, unique_id_mode_hash)
433
+ end
434
+
435
+ def update_id_value_hash(packet, target_id_value_hash, id_signature_hash, unique_id_mode_hash)
402
436
  if packet.id_items.length > 0
403
437
  key = []
438
+ id_signature = ""
404
439
  packet.id_items.each do |item|
405
440
  key << item.id_value
441
+ id_signature << "__#{item.key}__#{item.bit_offset}__#{item.bit_size}__#{item.data_type}"
442
+ end
443
+ target_id_value_hash[key] = packet
444
+ target_id_signature = id_signature_hash[packet.target_name]
445
+ if target_id_signature
446
+ if id_signature != target_id_signature
447
+ unique_id_mode_hash[packet.target_name] = true
448
+ end
449
+ else
450
+ id_signature_hash[packet.target_name] = id_signature
406
451
  end
407
- hash[key] = packet
408
452
  else
409
- hash['CATCHALL'.freeze] = packet
453
+ target_id_value_hash['CATCHALL'.freeze] = packet
410
454
  end
411
455
  end
412
456
 
@@ -445,7 +489,7 @@ module OpenC3
445
489
  # Start a new telemetry item in the current packet
446
490
  when 'ITEM', 'PARAMETER', 'ID_ITEM', 'ID_PARAMETER', 'ARRAY_ITEM', 'ARRAY_PARAMETER',\
447
491
  'APPEND_ITEM', 'APPEND_PARAMETER', 'APPEND_ID_ITEM', 'APPEND_ID_PARAMETER',\
448
- 'APPEND_ARRAY_ITEM', 'APPEND_ARRAY_PARAMETER'
492
+ 'APPEND_ARRAY_ITEM', 'APPEND_ARRAY_PARAMETER', 'STRUCTURE', 'APPEND_STRUCTURE'
449
493
  start_item(parser)
450
494
 
451
495
  # Allow this packet to be received with less data than the defined length
@@ -494,7 +538,11 @@ module OpenC3
494
538
  when 'HIDDEN'
495
539
  usage = "#{keyword}"
496
540
  parser.verify_num_parameters(0, 0, usage)
497
- @current_packet.hidden = true
541
+ if @current_item
542
+ @current_item.hidden = true
543
+ else
544
+ @current_packet.hidden = true
545
+ end
498
546
 
499
547
  when 'DISABLED'
500
548
  usage = "#{keyword}"
@@ -509,12 +557,17 @@ module OpenC3
509
557
  @current_packet.disabled = true
510
558
  @current_packet.virtual = true
511
559
 
560
+ when 'SUBPACKET'
561
+ usage = "#{keyword}"
562
+ parser.verify_num_parameters(0, 0, usage)
563
+ @current_packet.subpacket = true
564
+
512
565
  when 'RESTRICTED'
513
566
  usage = "#{keyword}"
514
567
  parser.verify_num_parameters(0, 0, usage)
515
568
  @current_packet.restricted = true
516
569
 
517
- when 'ACCESSOR', 'VALIDATOR'
570
+ when 'ACCESSOR', 'VALIDATOR', 'SUBPACKETIZER'
518
571
  usage = "#{keyword} <Class name> <Optional parameters> ..."
519
572
  parser.verify_num_parameters(1, nil, usage)
520
573
  begin
@@ -663,7 +716,7 @@ module OpenC3
663
716
  @converted_bit_size = nil
664
717
  if params[0]
665
718
  @converted_type = params[0].upcase.intern
666
- raise parser.error("Invalid converted_type: #{@converted_type}.") unless [:INT, :UINT, :FLOAT, :STRING, :BLOCK, :TIME].include? @converted_type
719
+ raise parser.error("Invalid converted_type: #{@converted_type}.") unless CONVERTED_DATA_TYPES.include? @converted_type
667
720
  end
668
721
  @converted_bit_size = Integer(params[1]) if params[1]
669
722
  if @converted_type.nil? or @converted_bit_size.nil?
@@ -745,10 +798,6 @@ module OpenC3
745
798
 
746
799
  # Update the default value for the current command parameter
747
800
  when 'DEFAULT_VALUE'
748
- if @current_cmd_or_tlm == TELEMETRY
749
- raise parser.error("#{keyword} only applies to command parameters")
750
- end
751
-
752
801
  usage = "DEFAULT_VALUE <DEFAULT VALUE>"
753
802
  parser.verify_num_parameters(1, 1, usage)
754
803
  if (@current_item.data_type == :STRING) ||
@@ -788,7 +837,7 @@ module OpenC3
788
837
 
789
838
  def start_item(parser)
790
839
  finish_item()
791
- @current_item = PacketItemParser.parse(parser, @current_packet, @current_cmd_or_tlm, @warnings)
840
+ @current_item = PacketItemParser.parse(parser, self, @current_packet, @current_cmd_or_tlm, @warnings)
792
841
  end
793
842
 
794
843
  # Finish updating packet item
@@ -233,6 +233,12 @@ module OpenC3
233
233
  raise ArgumentError, "#{@name}: default must be a String but is a #{@default.class}" unless String === @default
234
234
 
235
235
  @default = @default.clone.freeze
236
+ when :ARRAY
237
+ raise ArgumentError, "#{@name}: default must be an Array but is a #{@default.class}" unless Array === @default
238
+ when :OBJECT
239
+ raise ArgumentError, "#{@name}: default must be an Hash but is a #{@default.class}" unless Hash === @default
240
+ when :BOOL
241
+ raise ArgumentError, "#{@name}: default must be true/false but is a #{@default.class}" unless TrueClass === @default or FalseClass === @default
236
242
  end
237
243
  end
238
244
  end
@@ -323,37 +329,6 @@ module OpenC3
323
329
  end
324
330
  alias dup clone
325
331
 
326
- def to_hash
327
- hash = super()
328
- hash['format_string'] = self.format_string
329
- if self.read_conversion
330
- hash['read_conversion'] = self.read_conversion.to_s
331
- else
332
- hash['read_conversion'] = nil
333
- end
334
- if self.write_conversion
335
- hash['write_conversion'] = self.write_conversion.to_s
336
- else
337
- hash['write_conversion'] = nil
338
- end
339
- hash['id_value'] = self.id_value
340
- hash['states'] = self.states
341
- hash['description'] = self.description
342
- hash['units_full'] = self.units_full
343
- hash['units'] = self.units
344
- hash['default'] = self.default
345
- hash['range'] = self.range
346
- hash['required'] = self.required
347
- hash['hazardous'] = self.hazardous
348
- hash['messages_disabled'] = self.messages_disabled
349
- hash['state_colors'] = self.state_colors
350
- hash['limits'] = self.limits.to_hash
351
- hash['meta'] = nil
352
- hash['meta'] = @meta if @meta
353
- hash['obfuscate'] = self.obfuscate
354
- hash
355
- end
356
-
357
332
  def calculate_range
358
333
  first = range.first
359
334
  last = range.last
@@ -453,12 +428,7 @@ module OpenC3
453
428
  end
454
429
 
455
430
  def as_json(*a)
456
- config = {}
457
- config['name'] = self.name
458
- config['bit_offset'] = self.bit_offset
459
- config['bit_size'] = self.bit_size
460
- config['data_type'] = self.data_type.to_s
461
- config['array_size'] = self.array_size if self.array_size
431
+ config = super(*a)
462
432
  config['description'] = self.description
463
433
  config['id_value'] = self.id_value.as_json(*a) if self.id_value
464
434
  if @default
@@ -468,14 +438,12 @@ module OpenC3
468
438
  config['minimum'] = self.range.first.as_json(*a)
469
439
  config['maximum'] = self.range.last.as_json(*a)
470
440
  end
471
- config['endianness'] = self.endianness.to_s
472
441
  config['required'] = self.required
473
442
  config['format_string'] = self.format_string if self.format_string
474
443
  if self.units
475
444
  config['units'] = self.units
476
445
  config['units_full'] = self.units_full
477
446
  end
478
- config['overflow'] = self.overflow.to_s
479
447
  if @states
480
448
  states = {}
481
449
  config['states'] = states
@@ -518,74 +486,10 @@ module OpenC3
518
486
  end
519
487
 
520
488
  config['meta'] = @meta if @meta
521
- config['variable_bit_size'] = @variable_bit_size if @variable_bit_size
522
489
  config['obfuscate'] = self.obfuscate
523
490
  config
524
491
  end
525
492
 
526
- def self.from_json(hash)
527
- # Convert strings to symbols
528
- endianness = hash['endianness'] ? hash['endianness'].intern : nil
529
- data_type = hash['data_type'] ? hash['data_type'].intern : nil
530
- overflow = hash['overflow'] ? hash['overflow'].intern : nil
531
- item = PacketItem.new(hash['name'], hash['bit_offset'], hash['bit_size'],
532
- data_type, endianness, hash['array_size'], overflow)
533
- item.description = hash['description']
534
- item.id_value = hash['id_value']
535
- item.default = hash['default']
536
- item.range = (hash['minimum']..hash['maximum']) if hash['minimum'] && hash['maximum']
537
- item.required = hash['required']
538
- item.format_string = hash['format_string']
539
- item.units = hash['units']
540
- item.units_full = hash['units_full']
541
- if hash['states']
542
- item.states = {}
543
- item.hazardous = {}
544
- item.messages_disabled = {}
545
- item.state_colors = {}
546
- hash['states'].each do |state_name, state|
547
- item.states[state_name] = state['value']
548
- item.hazardous[state_name] = state['hazardous']
549
- item.messages_disabled[state_name] = state['messages_disabled']
550
- item.state_colors[state_name] = state['color'].to_sym if state['color']
551
- end
552
- end
553
- # Recreate OpenC3 built-in conversions
554
- if hash['read_conversion']
555
- begin
556
- item.read_conversion = OpenC3::const_get(hash['read_conversion']['class']).new(*hash['read_conversion']['params'])
557
- rescue => error
558
- Logger.instance.error "#{item.name} read_conversion of #{hash['read_conversion']} could not be instantiated due to #{error}"
559
- end
560
- end
561
- if hash['write_conversion']
562
- begin
563
- item.write_conversion = OpenC3::const_get(hash['write_conversion']['class']).new(*hash['write_conversion']['params'])
564
- rescue => error
565
- Logger.instance.error "#{item.name} write_conversion of #{hash['write_conversion']} could not be instantiated due to #{error}"
566
- end
567
- end
568
-
569
- item.limits = PacketItemLimits.new
570
- if hash['limits']
571
- # Delete the keys so the only ones left are limits sets
572
- persistence_setting = hash['limits'].delete('persistence_setting')
573
- item.limits.persistence_setting = persistence_setting if persistence_setting
574
- hash['limits'].delete('response') # Can't round trip response
575
- item.limits.enabled = true if hash['limits'].delete('enabled')
576
- values = {}
577
- hash['limits'].each do |set, items|
578
- values[set.to_sym] = [items['red_low'], items['yellow_low'], items['yellow_high'], items['red_high']]
579
- values[set.to_sym].concat([items['green_low'], items['green_high']]) if items['green_low'] && items['green_high']
580
- end
581
- item.limits.values = values if values.length > 0
582
- end
583
- item.meta = hash['meta']
584
- item.obfuscate = hash['obfuscate']
585
- item.variable_bit_size = hash['variable_bit_size']
586
- item
587
- end
588
-
589
493
  protected
590
494
 
591
495
  def parameter_config
@@ -621,6 +525,10 @@ module OpenC3
621
525
  Float(value)
622
526
  when :STRING, :BLOCK
623
527
  value.to_s.freeze
528
+ when :BOOL
529
+ ConfigParser.handle_true_false(value)
530
+ else
531
+ return value
624
532
  end
625
533
  rescue
626
534
  raise ArgumentError, "#{@name}: Invalid value: #{value} for data type: #{data_type}"