openc3 5.0.8 → 5.0.10
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of openc3 might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bin/openc3cli +128 -95
- data/data/config/_id_items.yaml +2 -1
- data/data/config/_id_params.yaml +2 -1
- data/data/config/_items.yaml +2 -1
- data/data/config/_params.yaml +2 -1
- data/data/config/command_modifiers.yaml +30 -0
- data/data/config/item_modifiers.yaml +10 -0
- data/data/config/microservice.yaml +12 -0
- data/data/config/param_item_modifiers.yaml +10 -0
- data/data/config/plugins.yaml +0 -9
- data/data/config/telemetry_modifiers.yaml +10 -0
- data/data/config/widgets.yaml +49 -73
- data/ext/openc3/ext/packet/packet.c +20 -2
- data/ext/openc3/ext/structure/structure.c +12 -17
- data/lib/openc3/accessors/accessor.rb +71 -0
- data/lib/openc3/accessors/binary_accessor.rb +1226 -0
- data/lib/openc3/accessors/cbor_accessor.rb +83 -0
- data/lib/openc3/accessors/html_accessor.rb +28 -0
- data/lib/openc3/accessors/json_accessor.rb +131 -0
- data/lib/openc3/accessors/xml_accessor.rb +67 -0
- data/lib/openc3/accessors.rb +23 -0
- data/lib/openc3/api/cmd_api.rb +5 -2
- data/lib/openc3/api/interface_api.rb +15 -0
- data/lib/openc3/api/limits_api.rb +3 -3
- data/lib/openc3/config/config_parser.rb +10 -4
- data/lib/openc3/core_ext/file.rb +5 -0
- data/lib/openc3/core_ext/tempfile.rb +20 -0
- data/lib/openc3/io/json_rpc.rb +3 -3
- data/lib/openc3/microservices/cleanup_microservice.rb +7 -5
- data/lib/openc3/models/cvt_model.rb +1 -10
- data/lib/openc3/models/interface_model.rb +41 -0
- data/lib/openc3/models/microservice_model.rb +33 -1
- data/lib/openc3/models/plugin_model.rb +1 -1
- data/lib/openc3/models/target_model.rb +85 -68
- data/lib/openc3/packets/binary_accessor.rb +2 -1207
- data/lib/openc3/packets/packet.rb +106 -6
- data/lib/openc3/packets/packet_config.rb +30 -7
- data/lib/openc3/packets/parsers/limits_response_parser.rb +1 -3
- data/lib/openc3/packets/parsers/processor_parser.rb +1 -2
- data/lib/openc3/packets/parsers/xtce_parser.rb +68 -3
- data/lib/openc3/packets/structure.rb +39 -14
- data/lib/openc3/packets/structure_item.rb +15 -1
- data/lib/openc3/script/storage.rb +19 -1
- data/lib/openc3/utilities/local_mode.rb +521 -0
- data/lib/openc3/utilities/simulated_target.rb +3 -2
- data/lib/openc3/utilities/target_file.rb +146 -0
- data/lib/openc3/version.rb +5 -5
- data/lib/openc3.rb +1 -0
- metadata +45 -7
@@ -21,6 +21,7 @@ require 'digest'
|
|
21
21
|
require 'openc3/packets/structure'
|
22
22
|
require 'openc3/packets/packet_item'
|
23
23
|
require 'openc3/ext/packet' if RUBY_ENGINE == 'ruby' and !ENV['OPENC3_NO_EXT']
|
24
|
+
require 'base64'
|
24
25
|
|
25
26
|
module OpenC3
|
26
27
|
# Adds features common to all OpenC3 packets of data to the Structure class.
|
@@ -85,6 +86,9 @@ module OpenC3
|
|
85
86
|
# @return [Symbol] :CMD or :TLM
|
86
87
|
attr_accessor :cmd_or_tlm
|
87
88
|
|
89
|
+
# @return [String] Base data for building packet
|
90
|
+
attr_reader :template
|
91
|
+
|
88
92
|
# Valid format types
|
89
93
|
VALUE_TYPES = [:RAW, :CONVERTED, :FORMATTED, :WITH_UNITS]
|
90
94
|
|
@@ -98,7 +102,7 @@ module OpenC3
|
|
98
102
|
# @param buffer [String] String buffer to hold the packet data
|
99
103
|
# @param item_class [Class] Class used to instantiate items (Must be a
|
100
104
|
# subclass of PacketItem)
|
101
|
-
def initialize(target_name, packet_name, default_endianness = :BIG_ENDIAN, description = nil, buffer = nil, item_class = PacketItem)
|
105
|
+
def initialize(target_name = nil, packet_name = nil, default_endianness = :BIG_ENDIAN, description = nil, buffer = nil, item_class = PacketItem)
|
102
106
|
super(default_endianness, buffer, item_class)
|
103
107
|
# Explictly call the defined setter methods
|
104
108
|
self.target_name = target_name
|
@@ -123,6 +127,7 @@ module OpenC3
|
|
123
127
|
@stored = false
|
124
128
|
@extra = nil
|
125
129
|
@cmd_or_tlm = nil
|
130
|
+
@template = nil
|
126
131
|
end
|
127
132
|
|
128
133
|
# Sets the target name this packet is associated with. Unidentified packets
|
@@ -290,7 +295,9 @@ module OpenC3
|
|
290
295
|
begin
|
291
296
|
internal_buffer_equals(buffer)
|
292
297
|
rescue RuntimeError
|
293
|
-
|
298
|
+
if BinaryAccessor == @accessor
|
299
|
+
Logger.instance.error "#{@target_name} #{@packet_name} received with actual packet length of #{buffer.length} but defined length of #{@defined_length}"
|
300
|
+
end
|
294
301
|
end
|
295
302
|
@read_conversion_cache.clear if @read_conversion_cache
|
296
303
|
process()
|
@@ -353,6 +360,20 @@ module OpenC3
|
|
353
360
|
end
|
354
361
|
end
|
355
362
|
|
363
|
+
# Sets the template data for the packet
|
364
|
+
# Template data is used as the default buffer contents if provided
|
365
|
+
#
|
366
|
+
# @param hazardous_description [String] Hazardous description of the packet
|
367
|
+
def template=(template)
|
368
|
+
if template
|
369
|
+
raise ArgumentError, "template must be a String but is a #{template.class}" unless String === template
|
370
|
+
|
371
|
+
@template = template.freeze
|
372
|
+
else
|
373
|
+
@template = nil
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
356
377
|
# Review bit offset to look for overlapping definitions. This will allow
|
357
378
|
# gaps in the packet, but not allow the same bits to be used for multiple
|
358
379
|
# variables.
|
@@ -531,11 +552,16 @@ module OpenC3
|
|
531
552
|
# @param value_type [Symbol] How to convert the item before returning it.
|
532
553
|
# Must be one of {VALUE_TYPES}
|
533
554
|
# @param buffer (see Structure#read_item)
|
555
|
+
# @param given_raw Given raw value to optimize
|
534
556
|
# @return The value. :FORMATTED and :WITH_UNITS values are always returned
|
535
557
|
# as Strings. :RAW values will match their data_type. :CONVERTED values
|
536
558
|
# can be any type.
|
537
|
-
def read_item(item, value_type = :CONVERTED, buffer = @buffer)
|
538
|
-
|
559
|
+
def read_item(item, value_type = :CONVERTED, buffer = @buffer, given_raw = nil)
|
560
|
+
if given_raw
|
561
|
+
value = given_raw
|
562
|
+
else
|
563
|
+
value = super(item, :RAW, buffer)
|
564
|
+
end
|
539
565
|
derived_raw = false
|
540
566
|
if item.data_type == :DERIVED && value_type == :RAW
|
541
567
|
value_type = :CONVERTED
|
@@ -632,6 +658,31 @@ module OpenC3
|
|
632
658
|
return value
|
633
659
|
end
|
634
660
|
|
661
|
+
# Read a list of items in the structure
|
662
|
+
#
|
663
|
+
# @param items [StructureItem] Array of PacketItem or one of its subclasses
|
664
|
+
# @param value_type [Symbol] Value type to read for every item
|
665
|
+
# @param buffer [String] The binary buffer to read the items from
|
666
|
+
# @return Hash of read names and values
|
667
|
+
def read_items(items, value_type = :RAW, buffer = @buffer, raw_value = nil)
|
668
|
+
buffer = allocate_buffer_if_needed() unless buffer
|
669
|
+
if value_type == :RAW
|
670
|
+
result = super(items, value_type, buffer)
|
671
|
+
# Must handle DERIVED special
|
672
|
+
items.each do |item|
|
673
|
+
if item.data_type == :DERIVED
|
674
|
+
result[item.name] = read_item(item, value_type, buffer)
|
675
|
+
end
|
676
|
+
end
|
677
|
+
else
|
678
|
+
result = {}
|
679
|
+
items.each do |item|
|
680
|
+
result[item.name] = read_item(item, value_type, buffer)
|
681
|
+
end
|
682
|
+
end
|
683
|
+
return result
|
684
|
+
end
|
685
|
+
|
635
686
|
# Write an item in the packet
|
636
687
|
#
|
637
688
|
# @param item [PacketItem] Instance of PacketItem or one of its subclasses
|
@@ -674,6 +725,24 @@ module OpenC3
|
|
674
725
|
end
|
675
726
|
end
|
676
727
|
|
728
|
+
# Write values to the buffer based on the item definitions
|
729
|
+
#
|
730
|
+
# @param items [StructureItem] Array of StructureItem or one of its subclasses
|
731
|
+
# @param value [Object] Array of values based on the item definitions.
|
732
|
+
# @param value_type [Symbol] Value type of each item to write
|
733
|
+
# @param buffer [String] The binary buffer to write the values to
|
734
|
+
def write_items(items, values, value_type = :RAW, buffer = @buffer)
|
735
|
+
buffer = allocate_buffer_if_needed() unless buffer
|
736
|
+
if value_type == :RAW
|
737
|
+
return super(items, values, value_type, buffer)
|
738
|
+
else
|
739
|
+
items.each_with_index do |item, index|
|
740
|
+
write_item(item, values[index], value_type, buffer)
|
741
|
+
end
|
742
|
+
end
|
743
|
+
return buffer
|
744
|
+
end
|
745
|
+
|
677
746
|
# Read an item in the packet by name
|
678
747
|
#
|
679
748
|
# @param name [String] Name of the item to read
|
@@ -738,12 +807,17 @@ module OpenC3
|
|
738
807
|
#
|
739
808
|
# @param buffer [String] Raw buffer of binary data
|
740
809
|
# @param skip_item_names [Array] Array of item names to skip
|
741
|
-
|
810
|
+
# @param use_templase [Boolean] Apply template before setting defaults (or not)
|
811
|
+
def restore_defaults(buffer = @buffer, skip_item_names = nil, use_template = true)
|
812
|
+
buffer = allocate_buffer_if_needed() unless buffer
|
742
813
|
upcase_skip_item_names = skip_item_names.map(&:upcase) if skip_item_names
|
814
|
+
buffer.replace(@template) if @template and use_template
|
743
815
|
@sorted_items.each do |item|
|
744
816
|
next if RESERVED_ITEM_NAMES.include?(item.name)
|
745
817
|
|
746
|
-
|
818
|
+
unless item.default.nil?
|
819
|
+
write_item(item, item.default, :CONVERTED, buffer) unless skip_item_names and upcase_skip_item_names.include?(item.name)
|
820
|
+
end
|
747
821
|
end
|
748
822
|
end
|
749
823
|
|
@@ -986,6 +1060,8 @@ module OpenC3
|
|
986
1060
|
config['disabled'] = true if @disabled
|
987
1061
|
config['hidden'] = true if @hidden
|
988
1062
|
config['stale'] = true if @stale
|
1063
|
+
config['accessor'] = @accessor.to_s
|
1064
|
+
config['template'] = Base64.encode64(@template) if @template
|
989
1065
|
|
990
1066
|
if @processors
|
991
1067
|
processors = []
|
@@ -1024,6 +1100,14 @@ module OpenC3
|
|
1024
1100
|
packet.disabled = hash['disabled']
|
1025
1101
|
packet.hidden = hash['hidden']
|
1026
1102
|
# packet.stale is read only
|
1103
|
+
if hash['accessor']
|
1104
|
+
begin
|
1105
|
+
packet.accessor = OpenC3::const_get(hash['accessor'])
|
1106
|
+
rescue => error
|
1107
|
+
Logger.instance.error "#{packet.target_name} #{packet.packet_name} accessor of #{hash['accessor']} could not be found due to #{error}"
|
1108
|
+
end
|
1109
|
+
end
|
1110
|
+
packet.template = Base64.decode64(hash['template']) if hash['template']
|
1027
1111
|
packet.meta = hash['meta']
|
1028
1112
|
# Can't convert processors
|
1029
1113
|
hash['items'].each do |item|
|
@@ -1032,6 +1116,22 @@ module OpenC3
|
|
1032
1116
|
packet
|
1033
1117
|
end
|
1034
1118
|
|
1119
|
+
def decom
|
1120
|
+
# Read all the RAW at once because this could be optimized by the accessor
|
1121
|
+
json_hash = read_items(@sorted_items)
|
1122
|
+
|
1123
|
+
# Now read all other value types - no accessor required
|
1124
|
+
@sorted_items.each do |item|
|
1125
|
+
given_raw = json_hash[item.name]
|
1126
|
+
json_hash["#{item.name}__C"] = read_item(item, :CONVERTED, @buffer, given_raw) if item.states or (item.read_conversion and item.data_type != :DERIVED)
|
1127
|
+
json_hash["#{item.name}__F"] = read_item(item, :FORMATTED, @buffer, given_raw) if item.format_string
|
1128
|
+
json_hash["#{item.name}__U"] = read_item(item, :WITH_UNITS, @buffer, given_raw) if item.units
|
1129
|
+
limits_state = item.limits.state
|
1130
|
+
json_hash["#{item.name}__L"] = limits_state if limits_state
|
1131
|
+
end
|
1132
|
+
json_hash
|
1133
|
+
end
|
1134
|
+
|
1035
1135
|
protected
|
1036
1136
|
|
1037
1137
|
# Performs packet specific processing on the packet.
|
@@ -209,7 +209,7 @@ module OpenC3
|
|
209
209
|
'PARAMETER', 'ID_ITEM', 'ID_PARAMETER', 'ARRAY_ITEM', 'ARRAY_PARAMETER', 'APPEND_ITEM',\
|
210
210
|
'APPEND_PARAMETER', 'APPEND_ID_ITEM', 'APPEND_ID_PARAMETER', 'APPEND_ARRAY_ITEM',\
|
211
211
|
'APPEND_ARRAY_PARAMETER', 'ALLOW_SHORT', 'HAZARDOUS', 'PROCESSOR', 'META',\
|
212
|
-
'DISABLE_MESSAGES', 'HIDDEN', 'DISABLED'
|
212
|
+
'DISABLE_MESSAGES', 'HIDDEN', 'DISABLED', 'ACCESSOR', 'TEMPLATE', 'TEMPLATE_FILE'
|
213
213
|
raise parser.error("No current packet for #{keyword}") unless @current_packet
|
214
214
|
|
215
215
|
process_current_packet(parser, keyword, params)
|
@@ -221,7 +221,7 @@ module OpenC3
|
|
221
221
|
'POLY_WRITE_CONVERSION', 'SEG_POLY_READ_CONVERSION', 'SEG_POLY_WRITE_CONVERSION',\
|
222
222
|
'GENERIC_READ_CONVERSION_START', 'GENERIC_WRITE_CONVERSION_START', 'REQUIRED',\
|
223
223
|
'LIMITS', 'LIMITS_RESPONSE', 'UNITS', 'FORMAT_STRING', 'DESCRIPTION',\
|
224
|
-
'MINIMUM_VALUE', 'MAXIMUM_VALUE', 'DEFAULT_VALUE', 'OVERFLOW', 'OVERLAP'
|
224
|
+
'MINIMUM_VALUE', 'MAXIMUM_VALUE', 'DEFAULT_VALUE', 'OVERFLOW', 'OVERLAP', 'KEY'
|
225
225
|
raise parser.error("No current item for #{keyword}") unless @current_item
|
226
226
|
|
227
227
|
process_current_item(parser, keyword, params)
|
@@ -427,7 +427,30 @@ module OpenC3
|
|
427
427
|
parser.verify_num_parameters(0, 0, usage)
|
428
428
|
@current_packet.hidden = true
|
429
429
|
@current_packet.disabled = true
|
430
|
+
when 'ACCESSOR'
|
431
|
+
usage = "#{keyword} <Accessor class name>"
|
432
|
+
parser.verify_num_parameters(1, 1, usage)
|
433
|
+
begin
|
434
|
+
klass = OpenC3.require_class(params[0])
|
435
|
+
@current_packet.accessor = klass
|
436
|
+
rescue Exception => err
|
437
|
+
raise parser.error(err)
|
438
|
+
end
|
439
|
+
|
440
|
+
when 'TEMPLATE'
|
441
|
+
usage = "#{keyword} <Template string>"
|
442
|
+
parser.verify_num_parameters(1, 1, usage)
|
443
|
+
@current_packet.template = params[0]
|
430
444
|
|
445
|
+
when 'TEMPLATE_FILE'
|
446
|
+
usage = "#{keyword} <Template file path>"
|
447
|
+
parser.verify_num_parameters(1, 1, usage)
|
448
|
+
|
449
|
+
begin
|
450
|
+
@current_packet.template = parser.read_file(params[0])
|
451
|
+
rescue Exception => err
|
452
|
+
raise parser.error(err)
|
453
|
+
end
|
431
454
|
end
|
432
455
|
end
|
433
456
|
|
@@ -444,14 +467,11 @@ module OpenC3
|
|
444
467
|
usage = "#{keyword} <conversion class filename> <custom parameters> ..."
|
445
468
|
parser.verify_num_parameters(1, nil, usage)
|
446
469
|
begin
|
447
|
-
|
448
|
-
klass = params[0].filename_to_class_name.to_class
|
449
|
-
raise parser.error("#{params[0].filename_to_class_name} class not found. Did you require the file in target.txt?", usage) unless klass
|
450
|
-
|
470
|
+
klass = OpenC3.require_class(params[0])
|
451
471
|
conversion = klass.new(*params[1..(params.length - 1)])
|
452
472
|
@current_item.public_send("#{keyword.downcase}=".to_sym, conversion)
|
453
473
|
if klass != ProcessorConversion and (conversion.converted_type.nil? or conversion.converted_bit_size.nil?)
|
454
|
-
msg = "Read Conversion #{params[0]
|
474
|
+
msg = "Read Conversion #{params[0]} on item #{@current_item.name} does not specify converted type or bit size"
|
455
475
|
@warnings << msg
|
456
476
|
Logger.instance.warn @warnings[-1]
|
457
477
|
end
|
@@ -600,6 +620,9 @@ module OpenC3
|
|
600
620
|
parser.verify_num_parameters(0, 0, 'OVERLAP')
|
601
621
|
@current_item.overlap = true
|
602
622
|
|
623
|
+
when 'KEY'
|
624
|
+
parser.verify_num_parameters(1, 1, 'KEY <key or path into data>')
|
625
|
+
@current_item.key = params[0]
|
603
626
|
end
|
604
627
|
end
|
605
628
|
|
@@ -45,9 +45,7 @@ module OpenC3
|
|
45
45
|
|
46
46
|
# @param item [PacketItem] The item the limits response should be added to
|
47
47
|
def create_limits_response(item)
|
48
|
-
|
49
|
-
klass = @parser.parameters[0].filename_to_class_name.to_class
|
50
|
-
raise @parser.error("#{@parser.parameters[0].filename_to_class_name} class not found. Did you require the file in target.txt?", @usage) unless klass
|
48
|
+
klass = OpenC3.require_class(@parser.parameters[0])
|
51
49
|
|
52
50
|
if @parser.parameters[1]
|
53
51
|
item.limits.response = klass.new(*@parser.parameters[1..(@parser.parameters.length - 1)])
|
@@ -48,8 +48,7 @@ module OpenC3
|
|
48
48
|
# @param packet [Packet] The packet the processor should be added to
|
49
49
|
def create_processor(packet)
|
50
50
|
# require should be performed in target.txt
|
51
|
-
klass = @parser.parameters[1]
|
52
|
-
raise @parser.error("#{@parser.parameters[1].filename_to_class_name} class not found. Did you require the file in target.txt?", @usage) unless klass
|
51
|
+
klass = OpenC3.require_class(@parser.parameters[1])
|
53
52
|
|
54
53
|
if @parser.parameters[2]
|
55
54
|
processor = klass.new(*@parser.parameters[2..(@parser.parameters.length - 1)])
|
@@ -178,14 +178,40 @@ module OpenC3
|
|
178
178
|
when 'ParameterTypeSet', 'EnumerationList', 'ParameterSet', 'ContainerSet',
|
179
179
|
'EntryList', 'DefaultCalibrator', 'DefaultAlarm', 'RestrictionCriteria',
|
180
180
|
'ComparisonList', 'MetaCommandSet', 'ArgumentTypeSet', 'ArgumentList',
|
181
|
-
'ArgumentAssignmentList', 'LocationInContainerInBits'
|
181
|
+
'ArgumentAssignmentList', 'LocationInContainerInBits', 'ReferenceTime'
|
182
182
|
# Do Nothing
|
183
183
|
|
184
|
+
when 'ErrorDetectCorrect'
|
185
|
+
# TODO: Setup an algorithm to calculate the CRC
|
186
|
+
exponents = []
|
187
|
+
xtce_recurse_element(element) do |crc_element|
|
188
|
+
if crc_element.name == 'CRC'
|
189
|
+
xtce_recurse_element(crc_element) do |poly_element|
|
190
|
+
if poly_element['Polynomial']
|
191
|
+
xtce_recurse_element(poly_element) do |term_element|
|
192
|
+
if term_element['Term']
|
193
|
+
exponents << term_element['exponent'].to_i
|
194
|
+
end
|
195
|
+
true
|
196
|
+
end
|
197
|
+
end
|
198
|
+
true
|
199
|
+
end
|
200
|
+
end
|
201
|
+
true
|
202
|
+
end
|
203
|
+
@current_type.xtce_encoding = 'IntegerDataEncoding'
|
204
|
+
@current_type.signed = 'false'
|
205
|
+
return false # Already recursed
|
206
|
+
|
184
207
|
when 'EnumeratedParameterType', 'EnumeratedArgumentType',
|
185
208
|
'IntegerParameterType', 'IntegerArgumentType',
|
186
209
|
'FloatParameterType', 'FloatArgumentType',
|
187
210
|
'StringParameterType', 'StringArgumentType',
|
188
|
-
'BinaryParameterType', 'BinaryArgumentType'
|
211
|
+
'BinaryParameterType', 'BinaryArgumentType',
|
212
|
+
'BooleanParameterType', 'BooleanArgumentType',
|
213
|
+
'AbsoluteTimeParameterType', 'AbsoluteTimeArgumentType',
|
214
|
+
'RelativeTimeParameterType', 'RelativeTimeArgumentType'
|
189
215
|
@current_type = create_new_type(element)
|
190
216
|
@current_type.endianness = :BIG_ENDIAN
|
191
217
|
|
@@ -204,6 +230,20 @@ module OpenC3
|
|
204
230
|
when 'BinaryParameterType', 'BinaryArgumentType'
|
205
231
|
@current_type.xtce_encoding = 'BinaryDataEncoding'
|
206
232
|
@current_type.sizeInBits = 8 # This is undocumented but appears to be the design
|
233
|
+
when 'BooleanParameterType', 'BooleanArgumentType'
|
234
|
+
@current_type.xtce_encoding = 'StringDataEncoding'
|
235
|
+
@current_type.sizeInBits = 8 # This is undocumented but appears to be the design
|
236
|
+
@current_type.states ||= {}
|
237
|
+
if element.attributes['zeroStringValue'] && element.attributes['oneStringValue']
|
238
|
+
@current_type.states[element.attributes['zeroStringValue'].value] = 0
|
239
|
+
@current_type.states[element.attributes['oneStringValue'].value] = 1
|
240
|
+
else
|
241
|
+
@current_type.states['FALSE'] = 0
|
242
|
+
@current_type.states['TRUE'] = 1
|
243
|
+
end
|
244
|
+
# No defaults for the time types
|
245
|
+
# when 'AbsoluteTimeParameterType', 'AbsoluteTimeArgumentType',
|
246
|
+
# when'RelativeTimeParameterType', 'RelativeTimeArgumentType'
|
207
247
|
end
|
208
248
|
|
209
249
|
when 'ArrayParameterType', 'ArrayArgumentType'
|
@@ -251,7 +291,7 @@ module OpenC3
|
|
251
291
|
|
252
292
|
return false # Already recursed
|
253
293
|
|
254
|
-
when
|
294
|
+
when 'SizeInBits'
|
255
295
|
xtce_recurse_element(element) do |block_element|
|
256
296
|
if block_element.name == 'FixedValue'
|
257
297
|
@current_type.sizeInBits = Integer(block_element.text)
|
@@ -326,6 +366,26 @@ module OpenC3
|
|
326
366
|
@current_type.states ||= {}
|
327
367
|
@current_type.states[element['label']] = Integer(element['value'])
|
328
368
|
|
369
|
+
when 'Encoding'
|
370
|
+
if element.attributes['units']
|
371
|
+
@current_type.units_full = element.attributes['units'].value
|
372
|
+
# Could do a better job mapping units to abbreviations
|
373
|
+
@current_type.units = element.attributes['units'].value[0]
|
374
|
+
end
|
375
|
+
# TODO: Not sure if this is correct
|
376
|
+
# if @current_type.attributes['scale'] || @current_type.attributes['offset']
|
377
|
+
# @current_type.conversion ||= PolynomialConversion.new()
|
378
|
+
# if @current_type.attributes['offset']
|
379
|
+
# @current_type.conversion.coeffs[0] = @current_type.attributes['offset']
|
380
|
+
# end
|
381
|
+
# if @current_type.attributes['scale']
|
382
|
+
# @current_type.conversion.coeffs[1] = @current_type.attributes['scale']
|
383
|
+
# end
|
384
|
+
# end
|
385
|
+
|
386
|
+
when 'Epoch'
|
387
|
+
# TODO: How to handle this ... it affects the conversion applied
|
388
|
+
|
329
389
|
when 'IntegerDataEncoding', 'FloatDataEncoding', 'StringDataEncoding', 'BinaryDataEncoding'
|
330
390
|
@current_type.xtce_encoding = element.name
|
331
391
|
element.attributes.each do |att_name, att|
|
@@ -340,6 +400,11 @@ module OpenC3
|
|
340
400
|
@current_type.endianness = :LITTLE_ENDIAN
|
341
401
|
end
|
342
402
|
|
403
|
+
# Ensure if the encoding is a string we convert state values to strings
|
404
|
+
if @current_type.xtce_encoding == 'StringDataEncoding' && @current_type.states
|
405
|
+
@current_type.states.transform_values!(&:to_s)
|
406
|
+
end
|
407
|
+
|
343
408
|
when 'Parameter'
|
344
409
|
@current_parameter = OpenStruct.new
|
345
410
|
element.attributes.each do |att_name, att|
|
@@ -51,6 +51,9 @@ module OpenC3
|
|
51
51
|
# required data size is allowed.
|
52
52
|
attr_accessor :short_buffer_allowed
|
53
53
|
|
54
|
+
# @return [Accessor] Class used to access raw data of structure from buffer
|
55
|
+
attr_reader :accessor
|
56
|
+
|
54
57
|
if RUBY_ENGINE != 'ruby' or ENV['OPENC3_NO_EXT']
|
55
58
|
# Used to force encoding
|
56
59
|
ASCII_8BIT_STRING = "ASCII-8BIT".freeze
|
@@ -86,6 +89,7 @@ module OpenC3
|
|
86
89
|
@fixed_size = true
|
87
90
|
@short_buffer_allowed = false
|
88
91
|
@mutex = nil
|
92
|
+
@accessor = BinaryAccessor
|
89
93
|
else
|
90
94
|
raise(ArgumentError, "Unknown endianness '#{default_endianness}', must be :BIG_ENDIAN or :LITTLE_ENDIAN")
|
91
95
|
end
|
@@ -103,11 +107,7 @@ module OpenC3
|
|
103
107
|
return nil if item.data_type == :DERIVED
|
104
108
|
|
105
109
|
buffer = allocate_buffer_if_needed() unless buffer
|
106
|
-
|
107
|
-
return BinaryAccessor.read_array(item.bit_offset, item.bit_size, item.data_type, item.array_size, buffer, item.endianness)
|
108
|
-
else
|
109
|
-
return BinaryAccessor.read(item.bit_offset, item.bit_size, item.data_type, buffer, item.endianness)
|
110
|
-
end
|
110
|
+
return @accessor.read_item(item, buffer)
|
111
111
|
end
|
112
112
|
|
113
113
|
# Get the length of the buffer used by the structure
|
@@ -133,6 +133,26 @@ module OpenC3
|
|
133
133
|
end
|
134
134
|
end
|
135
135
|
|
136
|
+
# Configure the accessor for this packet
|
137
|
+
#
|
138
|
+
# @param accessor [Accessor] The class to use as an accessor
|
139
|
+
def accessor=(accessor)
|
140
|
+
@accessor = accessor
|
141
|
+
@short_buffer_allowed = true if @accessor != BinaryAccessor
|
142
|
+
end
|
143
|
+
|
144
|
+
# Read a list of items in the structure
|
145
|
+
#
|
146
|
+
# @param items [StructureItem] Array of StructureItem or one of its subclasses
|
147
|
+
# @param value_type [Symbol] Not used. Subclasses should overload this
|
148
|
+
# parameter to check whether to perform conversions on the item.
|
149
|
+
# @param buffer [String] The binary buffer to read the item from
|
150
|
+
# @return Hash of read names and values
|
151
|
+
def read_items(items, value_type = :RAW, buffer = @buffer)
|
152
|
+
buffer = allocate_buffer_if_needed() unless buffer
|
153
|
+
return @accessor.read_items(items, buffer)
|
154
|
+
end
|
155
|
+
|
136
156
|
# Allocate a buffer if not available
|
137
157
|
def allocate_buffer_if_needed
|
138
158
|
unless @buffer
|
@@ -180,11 +200,8 @@ module OpenC3
|
|
180
200
|
# dependant on the item_class but by default see StructureItem.
|
181
201
|
# @return [StrutureItem] The struture item defined
|
182
202
|
def define_item(name, bit_offset, bit_size, data_type, array_size = nil, endianness = @default_endianness, overflow = :ERROR)
|
183
|
-
# Handle case-insensitive naming
|
184
|
-
name_upcase = name.upcase
|
185
|
-
|
186
203
|
# Create the item
|
187
|
-
item = @item_class.new(
|
204
|
+
item = @item_class.new(name, bit_offset, bit_size, data_type, endianness, array_size, overflow)
|
188
205
|
define(item)
|
189
206
|
end
|
190
207
|
|
@@ -348,11 +365,19 @@ module OpenC3
|
|
348
365
|
# @param buffer [String] The binary buffer to write the value to
|
349
366
|
def write_item(item, value, value_type = :RAW, buffer = @buffer)
|
350
367
|
buffer = allocate_buffer_if_needed() unless buffer
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
368
|
+
return @accessor.write_item(item, value, buffer)
|
369
|
+
end
|
370
|
+
|
371
|
+
# Write values to the buffer based on the item definitions
|
372
|
+
#
|
373
|
+
# @param items [StructureItem] Array of StructureItem or one of its subclasses
|
374
|
+
# @param value [Object] Array of values based on the item definitions.
|
375
|
+
# @param value_type [Symbol] Not used. Subclasses should overload this
|
376
|
+
# parameter to check whether to perform conversions on the item.
|
377
|
+
# @param buffer [String] The binary buffer to write the values to
|
378
|
+
def write_items(items, values, value_type = :RAW, buffer = @buffer)
|
379
|
+
buffer = allocate_buffer_if_needed() unless buffer
|
380
|
+
return @accessor.write_items(items, values, buffer)
|
356
381
|
end
|
357
382
|
|
358
383
|
# Read an item in the structure by name
|
@@ -34,6 +34,9 @@ module OpenC3
|
|
34
34
|
# @return [String] Name of the item
|
35
35
|
attr_reader :name
|
36
36
|
|
37
|
+
# Key is used to access into nested structures during decom if applicable
|
38
|
+
attr_reader :key
|
39
|
+
|
37
40
|
# Indicates where in the binary buffer the StructureItem exists.
|
38
41
|
# @return [Integer] 0 based bit offset
|
39
42
|
attr_reader :bit_offset
|
@@ -89,6 +92,7 @@ module OpenC3
|
|
89
92
|
@structure_item_constructed = false
|
90
93
|
# Assignment order matters due to verifications!
|
91
94
|
self.name = name
|
95
|
+
self.key = name # Key defaults to name as given (not upcased)
|
92
96
|
self.endianness = endianness
|
93
97
|
self.data_type = data_type
|
94
98
|
self.bit_offset = bit_offset
|
@@ -110,6 +114,13 @@ module OpenC3
|
|
110
114
|
verify_overall() if @structure_item_constructed
|
111
115
|
end
|
112
116
|
|
117
|
+
def key=(key)
|
118
|
+
raise ArgumentError, "key must be a String but is a #{name.class}" unless String === key
|
119
|
+
raise ArgumentError, "key must contain at least one character" if key.empty?
|
120
|
+
|
121
|
+
@key = key
|
122
|
+
end
|
123
|
+
|
113
124
|
def endianness=(endianness)
|
114
125
|
raise ArgumentError, "#{@name}: endianness must be a Symbol" unless Symbol === endianness
|
115
126
|
unless BinaryAccessor::ENDIANNESS.include? endianness
|
@@ -297,13 +308,16 @@ module OpenC3
|
|
297
308
|
endianness = hash['endianness'] ? hash['endianness'].intern : nil
|
298
309
|
data_type = hash['data_type'] ? hash['data_type'].intern : nil
|
299
310
|
overflow = hash['overflow'] ? hash['overflow'].intern : nil
|
300
|
-
StructureItem.new(hash['name'], hash['bit_offset'], hash['bit_size'], data_type,
|
311
|
+
si = StructureItem.new(hash['name'], hash['bit_offset'], hash['bit_size'], data_type,
|
301
312
|
endianness, hash['array_size'], overflow)
|
313
|
+
si.key = hash['key'] || hash['name']
|
314
|
+
si
|
302
315
|
end
|
303
316
|
|
304
317
|
def as_json(*a)
|
305
318
|
hash = {}
|
306
319
|
hash['name'] = self.name
|
320
|
+
hash['key'] = self.key
|
307
321
|
hash['bit_offset'] = self.bit_offset
|
308
322
|
hash['bit_size'] = self.bit_size
|
309
323
|
hash['data_type'] = self.data_type
|
@@ -17,6 +17,7 @@
|
|
17
17
|
# All changes Copyright 2022, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
|
20
|
+
require 'tempfile'
|
20
21
|
require 'net/http'
|
21
22
|
|
22
23
|
module OpenC3
|
@@ -34,7 +35,7 @@ module OpenC3
|
|
34
35
|
OpenC3::Logger.info "Deleting #{delete_path}"
|
35
36
|
response = $api_server.request('delete', endpoint, query: {bucket: 'config'}, scope: scope)
|
36
37
|
if response.nil? || response.code != 200
|
37
|
-
raise "Failed to delete #{delete_path}
|
38
|
+
raise "Failed to delete #{delete_path}"
|
38
39
|
end
|
39
40
|
rescue => error
|
40
41
|
raise "Failed deleting #{path} due to #{error.message}"
|
@@ -48,7 +49,13 @@ module OpenC3
|
|
48
49
|
# @param io_or_string [Io or String] IO object
|
49
50
|
def put_target_file(path, io_or_string, scope: $openc3_scope)
|
50
51
|
raise "Disallowed path modifier '..' found in #{path}" if path.include?('..')
|
52
|
+
|
51
53
|
upload_path = "#{scope}/targets_modified/#{path}"
|
54
|
+
|
55
|
+
if ENV['OPENC3_LOCAL_MODE'] and $openc3_in_cluster
|
56
|
+
OpenC3::LocalMode.put_target_file(upload_path, io_or_string, scope: scope)
|
57
|
+
end
|
58
|
+
|
52
59
|
endpoint = "/openc3-api/storage/upload/#{upload_path}"
|
53
60
|
OpenC3::Logger.info "Writing #{upload_path}"
|
54
61
|
result = _get_presigned_request(endpoint, scope: scope)
|
@@ -86,6 +93,17 @@ module OpenC3
|
|
86
93
|
# Loop to allow redo when switching from modified to original
|
87
94
|
loop do
|
88
95
|
begin
|
96
|
+
if part == "targets_modified" and ENV['OPENC3_LOCAL_MODE']
|
97
|
+
local_file = OpenC3::LocalMode.open_local_file(path, scope: scope)
|
98
|
+
if local_file
|
99
|
+
file = Tempfile.new('target', binmode: true)
|
100
|
+
file.write(local_file.read)
|
101
|
+
local_file.close
|
102
|
+
file.rewind
|
103
|
+
return file if local_file
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
89
107
|
return _get_storage_file("#{part}/#{path}", scope: scope)
|
90
108
|
rescue => error
|
91
109
|
if part == "targets_modified"
|