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.
- checksums.yaml +4 -4
- data/data/config/command_modifiers.yaml +79 -0
- data/data/config/item_modifiers.yaml +5 -0
- data/data/config/parameter_modifiers.yaml +5 -0
- data/data/config/telemetry_modifiers.yaml +79 -0
- data/ext/openc3/ext/packet/packet.c +9 -0
- data/lib/openc3/accessors/accessor.rb +27 -3
- data/lib/openc3/accessors/binary_accessor.rb +21 -4
- data/lib/openc3/accessors/template_accessor.rb +3 -2
- data/lib/openc3/api/cmd_api.rb +7 -3
- data/lib/openc3/api/tlm_api.rb +17 -7
- data/lib/openc3/interfaces/protocols/fixed_protocol.rb +19 -13
- data/lib/openc3/io/json_rpc.rb +6 -0
- data/lib/openc3/microservices/decom_microservice.rb +97 -17
- data/lib/openc3/microservices/interface_decom_common.rb +32 -0
- data/lib/openc3/microservices/interface_microservice.rb +3 -75
- data/lib/openc3/microservices/queue_microservice.rb +16 -1
- data/lib/openc3/migrations/20251022000000_remove_unique_id.rb +23 -0
- data/lib/openc3/models/plugin_model.rb +7 -1
- data/lib/openc3/models/queue_model.rb +32 -5
- data/lib/openc3/models/reaction_model.rb +25 -9
- data/lib/openc3/models/target_model.rb +78 -10
- data/lib/openc3/packets/commands.rb +33 -7
- data/lib/openc3/packets/packet.rb +75 -71
- data/lib/openc3/packets/packet_config.rb +78 -29
- data/lib/openc3/packets/packet_item.rb +11 -103
- data/lib/openc3/packets/parsers/packet_item_parser.rb +177 -34
- data/lib/openc3/packets/parsers/xtce_converter.rb +2 -2
- data/lib/openc3/packets/structure.rb +29 -21
- data/lib/openc3/packets/structure_item.rb +31 -19
- data/lib/openc3/packets/telemetry.rb +37 -11
- data/lib/openc3/script/suite_results.rb +2 -2
- data/lib/openc3/subpacketizers/subpacketizer.rb +18 -0
- data/lib/openc3/system/target.rb +3 -32
- data/lib/openc3/tools/table_manager/table_config.rb +9 -1
- data/lib/openc3/tools/table_manager/table_item_parser.rb +2 -2
- data/lib/openc3/top_level.rb +45 -19
- data/lib/openc3/topics/decom_interface_topic.rb +31 -0
- data/lib/openc3/utilities/env_helper.rb +10 -0
- data/lib/openc3/utilities/logger.rb +7 -11
- data/lib/openc3/version.rb +6 -6
- data/tasks/spec.rake +2 -1
- data/templates/tool_angular/package.json +2 -2
- data/templates/tool_react/package.json +1 -1
- data/templates/tool_svelte/package.json +1 -1
- data/templates/tool_vue/package.json +3 -3
- data/templates/widget/package.json +2 -2
- 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
|
|
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
|
-
@
|
|
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
|
-
|
|
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
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
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
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
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
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
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
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
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
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
@
|
|
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
|
|
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}"
|