cosmos 3.1.2 → 3.2.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/Gemfile +3 -0
- data/Manifest.txt +17 -1
- data/autohotkey/tools/test_runner2.ahk +1 -0
- data/autohotkey/tools/tlm_grapher.ahk +13 -1
- data/data/crc.txt +39 -30
- data/demo/config/data/crc.txt +3 -3
- data/demo/config/targets/TEMPLATED/lib/templated_interface.rb +3 -1
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +7 -1
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +6 -1
- data/lib/cosmos.rb +2 -2
- data/lib/cosmos/gui/dialogs/about_dialog.rb +18 -5
- data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +0 -7
- data/lib/cosmos/gui/line_graph/overview_graph.rb +12 -2
- data/lib/cosmos/gui/utilities/script_module_gui.rb +11 -3
- data/lib/cosmos/interfaces/interface.rb +12 -0
- data/lib/cosmos/interfaces/stream_interface.rb +1 -21
- data/lib/cosmos/interfaces/tcpip_server_interface.rb +10 -0
- data/lib/cosmos/io/json_drb_object.rb +75 -56
- data/lib/cosmos/io/tcpip_server.rb +1 -11
- data/lib/cosmos/packet_logs.rb +1 -0
- data/lib/cosmos/packet_logs/ccsds_log_reader.rb +103 -0
- data/lib/cosmos/packets/packet.rb +70 -1
- data/lib/cosmos/packets/packet_config.rb +59 -611
- data/lib/cosmos/packets/parsers/format_string_parser.rb +58 -0
- data/lib/cosmos/packets/parsers/limits_parser.rb +146 -0
- data/lib/cosmos/packets/parsers/limits_response_parser.rb +52 -0
- data/lib/cosmos/packets/parsers/macro_parser.rb +116 -0
- data/lib/cosmos/packets/parsers/packet_item_parser.rb +215 -0
- data/lib/cosmos/packets/parsers/packet_parser.rb +123 -0
- data/lib/cosmos/packets/parsers/processor_parser.rb +63 -0
- data/lib/cosmos/packets/parsers/state_parser.rb +116 -0
- data/lib/cosmos/packets/structure.rb +59 -22
- data/lib/cosmos/packets/structure_item.rb +1 -1
- data/lib/cosmos/script/script.rb +4 -5
- data/lib/cosmos/streams/serial_stream.rb +5 -0
- data/lib/cosmos/streams/stream.rb +8 -2
- data/lib/cosmos/streams/stream_protocol.rb +1 -0
- data/lib/cosmos/streams/tcpip_client_stream.rb +37 -7
- data/lib/cosmos/streams/tcpip_socket_stream.rb +9 -6
- data/lib/cosmos/system/target.rb +3 -6
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +57 -48
- data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +7 -3
- data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +1 -1
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +7 -1
- data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +1 -2
- data/lib/cosmos/top_level.rb +22 -11
- data/lib/cosmos/utilities/message_log.rb +14 -9
- data/lib/cosmos/version.rb +5 -5
- data/spec/interfaces/cmd_tlm_server_interface_spec.rb +16 -16
- data/spec/interfaces/linc_interface_spec.rb +3 -0
- data/spec/interfaces/tcpip_client_interface_spec.rb +1 -0
- data/spec/interfaces/tcpip_server_interface_spec.rb +9 -0
- data/spec/io/json_drb_object_spec.rb +1 -1
- data/spec/io/serial_driver_spec.rb +0 -1
- data/spec/packet_logs/packet_log_writer_spec.rb +5 -3
- data/spec/packets/packet_config_spec.rb +22 -837
- data/spec/packets/packet_item_spec.rb +10 -10
- data/spec/packets/packet_spec.rb +239 -1
- data/spec/packets/parsers/format_string_parser_spec.rb +122 -0
- data/spec/packets/parsers/limits_parser_spec.rb +282 -0
- data/spec/packets/parsers/limits_response_parser_spec.rb +149 -0
- data/spec/packets/parsers/macro_parser_spec.rb +184 -0
- data/spec/packets/parsers/packet_item_parser_spec.rb +306 -0
- data/spec/packets/parsers/packet_parser_spec.rb +99 -0
- data/spec/packets/parsers/processor_parser_spec.rb +114 -0
- data/spec/packets/parsers/state_parser_spec.rb +156 -0
- data/spec/packets/structure_item_spec.rb +14 -14
- data/spec/packets/structure_spec.rb +162 -16
- data/spec/streams/fixed_stream_protocol_spec.rb +7 -4
- data/spec/streams/length_stream_protocol_spec.rb +3 -0
- data/spec/streams/preidentified_stream_protocol_spec.rb +3 -0
- data/spec/streams/serial_stream_spec.rb +12 -0
- data/spec/streams/stream_protocol_spec.rb +14 -0
- data/spec/streams/stream_spec.rb +1 -0
- data/spec/streams/tcpip_client_stream_spec.rb +3 -0
- data/spec/streams/tcpip_socket_stream_spec.rb +15 -3
- data/spec/streams/template_stream_protocol_spec.rb +5 -0
- data/spec/streams/terminated_stream_protocol_spec.rb +4 -0
- data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +21 -1
- data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +1 -1
- data/spec/tools/cmd_tlm_server/interfaces_spec.rb +1 -1
- metadata +19 -3
|
@@ -165,6 +165,53 @@ module Cosmos
|
|
|
165
165
|
end
|
|
166
166
|
end
|
|
167
167
|
|
|
168
|
+
# Review bit offset to look for overlapping definitions. This will allow
|
|
169
|
+
# gaps in the packet, but not allow the same bits to be used for multiple
|
|
170
|
+
# variables.
|
|
171
|
+
#
|
|
172
|
+
# @return [Array<String>] Warning messages for big definition overlaps
|
|
173
|
+
def check_bit_offsets
|
|
174
|
+
expected_next_offset = nil
|
|
175
|
+
previous_item = nil
|
|
176
|
+
warnings = []
|
|
177
|
+
@sorted_items.each do |item|
|
|
178
|
+
if expected_next_offset and item.bit_offset < expected_next_offset
|
|
179
|
+
msg = "Bit definition overlap at bit offset #{item.bit_offset} for packet #{@target_name} #{@packet_name} items #{item.name} and #{previous_item.name}"
|
|
180
|
+
Logger.instance.warn(msg)
|
|
181
|
+
warnings << msg
|
|
182
|
+
end
|
|
183
|
+
if item.array_size
|
|
184
|
+
if item.array_size > 0
|
|
185
|
+
expected_next_offset = item.bit_offset + item.array_size
|
|
186
|
+
else
|
|
187
|
+
expected_next_offset = item.array_size
|
|
188
|
+
end
|
|
189
|
+
else
|
|
190
|
+
expected_next_offset = nil
|
|
191
|
+
if item.bit_offset > 0
|
|
192
|
+
# Handle little-endian bit fields
|
|
193
|
+
byte_aligned = ((item.bit_offset % 8) == 0)
|
|
194
|
+
if item.endianness == :LITTLE_ENDIAN and (item.data_type == :INT or item.data_type == :UINT) and !(byte_aligned and (item.bit_size == 8 or item.bit_size == 16 or item.bit_size == 32 or item.bit_size == 64))
|
|
195
|
+
# Bit offset always refers to the most significant bit of a bitfield
|
|
196
|
+
bits_remaining_in_last_byte = 8 - (item.bit_offset % 8)
|
|
197
|
+
if item.bit_size > bits_remaining_in_last_byte
|
|
198
|
+
expected_next_offset = item.bit_offset + bits_remaining_in_last_byte
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
unless expected_next_offset
|
|
203
|
+
if item.bit_size > 0
|
|
204
|
+
expected_next_offset = item.bit_offset + item.bit_size
|
|
205
|
+
else
|
|
206
|
+
expected_next_offset = item.bit_size
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
previous_item = item
|
|
211
|
+
end
|
|
212
|
+
warnings
|
|
213
|
+
end
|
|
214
|
+
|
|
168
215
|
# Id items are used by the identify? method to determine if a raw buffer of
|
|
169
216
|
# data represents this packet.
|
|
170
217
|
# @return [Array<PacketItem>] Packet item identifiers
|
|
@@ -218,11 +265,24 @@ module Cosmos
|
|
|
218
265
|
# @param id_value [Object] Set to something other than nil to indicate that
|
|
219
266
|
# this item should be used to identify a buffer as this packet. The
|
|
220
267
|
# id_value should make sense according to the data_type.
|
|
268
|
+
# @return [PacketItem] The new packet item
|
|
221
269
|
def define_item(name, bit_offset, bit_size, data_type, array_size = nil, endianness = @default_endianness, overflow = :ERROR, format_string = nil, read_conversion = nil, write_conversion = nil, id_value = nil)
|
|
222
270
|
item = super(name, bit_offset, bit_size, data_type, array_size, endianness, overflow)
|
|
223
271
|
packet_define_item(item, format_string, read_conversion, write_conversion, id_value)
|
|
224
272
|
end
|
|
225
273
|
|
|
274
|
+
# Add an item to the packet by adding it to the items hash. It also
|
|
275
|
+
# resizes the buffer to accomodate the new item.
|
|
276
|
+
#
|
|
277
|
+
# @param item [PacketItem] Item to add to the packet
|
|
278
|
+
# @return [PacketItem] The same packet item
|
|
279
|
+
def define(item)
|
|
280
|
+
item = super(item)
|
|
281
|
+
update_id_items(item)
|
|
282
|
+
update_limits_items_cache()
|
|
283
|
+
item
|
|
284
|
+
end
|
|
285
|
+
|
|
226
286
|
# Define an item at the end of the packet. This creates a new instance of the
|
|
227
287
|
# item_class as given in the constructor and adds it to the items hash. It
|
|
228
288
|
# also resizes the buffer to accomodate the new item.
|
|
@@ -237,6 +297,7 @@ module Cosmos
|
|
|
237
297
|
# @param read_conversion (see #define_item)
|
|
238
298
|
# @param write_conversion (see #define_item)
|
|
239
299
|
# @param id_value (see #define_item)
|
|
300
|
+
# @return (see #define_item)
|
|
240
301
|
def append_item(name, bit_size, data_type, array_size = nil, endianness = @default_endianness, overflow = :ERROR, format_string = nil, read_conversion = nil, write_conversion = nil, id_value = nil)
|
|
241
302
|
item = super(name, bit_size, data_type, array_size, endianness, overflow)
|
|
242
303
|
packet_define_item(item, format_string, read_conversion, write_conversion, id_value)
|
|
@@ -569,6 +630,7 @@ module Cosmos
|
|
|
569
630
|
def clone
|
|
570
631
|
packet = super()
|
|
571
632
|
if packet.instance_variable_get("@processors")
|
|
633
|
+
packet.instance_variable_set("@processors", packet.processors.clone)
|
|
572
634
|
packet.processors.each do |processor_name, processor|
|
|
573
635
|
packet.processors[processor_name] = processor.clone
|
|
574
636
|
end
|
|
@@ -703,12 +765,19 @@ module Cosmos
|
|
|
703
765
|
# Change id_value to the correct type
|
|
704
766
|
if id_value
|
|
705
767
|
item.id_value = id_value
|
|
768
|
+
update_id_items(item)
|
|
769
|
+
end
|
|
770
|
+
item
|
|
771
|
+
end
|
|
772
|
+
|
|
773
|
+
def update_id_items(item)
|
|
774
|
+
if item.id_value
|
|
706
775
|
@id_items ||= []
|
|
707
776
|
@id_items << item
|
|
708
777
|
end
|
|
709
|
-
|
|
710
778
|
item
|
|
711
779
|
end
|
|
780
|
+
|
|
712
781
|
end # class Packet
|
|
713
782
|
|
|
714
783
|
end # module Cosmos
|
|
@@ -10,9 +10,16 @@
|
|
|
10
10
|
|
|
11
11
|
require 'cosmos/config/config_parser'
|
|
12
12
|
require 'cosmos/packets/packet'
|
|
13
|
+
require 'cosmos/packets/parsers/packet_parser'
|
|
14
|
+
require 'cosmos/packets/parsers/packet_item_parser'
|
|
15
|
+
require 'cosmos/packets/parsers/macro_parser'
|
|
16
|
+
require 'cosmos/packets/parsers/limits_parser'
|
|
17
|
+
require 'cosmos/packets/parsers/limits_response_parser'
|
|
18
|
+
require 'cosmos/packets/parsers/state_parser'
|
|
19
|
+
require 'cosmos/packets/parsers/format_string_parser'
|
|
20
|
+
require 'cosmos/packets/parsers/processor_parser'
|
|
13
21
|
require 'cosmos/conversions'
|
|
14
22
|
require 'cosmos/processors'
|
|
15
|
-
require 'ostruct'
|
|
16
23
|
|
|
17
24
|
module Cosmos
|
|
18
25
|
|
|
@@ -49,6 +56,9 @@ module Cosmos
|
|
|
49
56
|
# packet is not.
|
|
50
57
|
attr_reader :latest_data
|
|
51
58
|
|
|
59
|
+
COMMAND = "Command"
|
|
60
|
+
TELEMETRY = "Telemetry"
|
|
61
|
+
|
|
52
62
|
def initialize
|
|
53
63
|
@name = nil
|
|
54
64
|
@telemetry = {}
|
|
@@ -69,8 +79,6 @@ module Cosmos
|
|
|
69
79
|
@telemetry['UNKNOWN']['UNKNOWN'] = Packet.new('UNKNOWN', 'UNKNOWN', :BIG_ENDIAN)
|
|
70
80
|
|
|
71
81
|
# Used during packet processing
|
|
72
|
-
@current_target_name = nil
|
|
73
|
-
@current_packet_name = nil
|
|
74
82
|
@current_cmd_or_tlm = nil
|
|
75
83
|
@current_packet = nil
|
|
76
84
|
@current_item = nil
|
|
@@ -86,20 +94,13 @@ module Cosmos
|
|
|
86
94
|
#
|
|
87
95
|
# @param filename [String] The name of the configuration file
|
|
88
96
|
# @param target_name [String] The target name
|
|
89
|
-
def process_file(filename,
|
|
97
|
+
def process_file(filename, process_target_name)
|
|
90
98
|
@converted_type = nil
|
|
91
99
|
@converted_bit_size = nil
|
|
92
100
|
@proc_text = ''
|
|
93
101
|
@building_generic_conversion = false
|
|
94
|
-
@macro_append = OpenStruct.new
|
|
95
|
-
@macro_append.building = false
|
|
96
|
-
@macro_append.list = []
|
|
97
|
-
@macro_append.indices = []
|
|
98
|
-
@macro_append.format = ''
|
|
99
|
-
@macro_append.format_order = ''
|
|
100
|
-
|
|
101
|
-
target_name = target_name.upcase
|
|
102
102
|
|
|
103
|
+
process_target_name = process_target_name.upcase
|
|
103
104
|
parser = ConfigParser.new("https://github.com/BallAerospace/COSMOS/wiki/Command-and-Telemetry-Configuration")
|
|
104
105
|
parser.parse_file(filename) do |keyword, params|
|
|
105
106
|
|
|
@@ -127,28 +128,35 @@ module Cosmos
|
|
|
127
128
|
case keyword
|
|
128
129
|
|
|
129
130
|
# Start a new packet
|
|
130
|
-
when 'COMMAND'
|
|
131
|
-
|
|
131
|
+
when 'COMMAND'
|
|
132
|
+
finish_packet()
|
|
133
|
+
@current_packet = PacketParser.parse_command(parser, process_target_name, @commands, @warnings)
|
|
134
|
+
@current_cmd_or_tlm = COMMAND
|
|
135
|
+
|
|
136
|
+
when 'TELEMETRY'
|
|
137
|
+
finish_packet()
|
|
138
|
+
@current_packet = PacketParser.parse_telemetry(parser, process_target_name, @telemetry, @latest_data, @warnings)
|
|
139
|
+
@current_cmd_or_tlm = TELEMETRY
|
|
132
140
|
|
|
133
141
|
# Select an existing packet for editing
|
|
134
142
|
when 'SELECT_COMMAND', 'SELECT_TELEMETRY'
|
|
135
143
|
usage = "#{keyword} <TARGET NAME> <PACKET NAME>"
|
|
136
144
|
finish_packet()
|
|
137
145
|
parser.verify_num_parameters(2, 2, usage)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
146
|
+
target_name = process_target_name
|
|
147
|
+
target_name = params[0].upcase if target_name == 'SYSTEM'
|
|
148
|
+
packet_name = params[1].upcase
|
|
141
149
|
|
|
142
150
|
@current_packet = nil
|
|
143
151
|
if keyword.include?('COMMAND')
|
|
144
|
-
@current_cmd_or_tlm =
|
|
145
|
-
if @commands[
|
|
146
|
-
@current_packet = @commands[
|
|
152
|
+
@current_cmd_or_tlm = COMMAND
|
|
153
|
+
if @commands[target_name]
|
|
154
|
+
@current_packet = @commands[target_name][packet_name]
|
|
147
155
|
end
|
|
148
156
|
else
|
|
149
|
-
@current_cmd_or_tlm =
|
|
150
|
-
if @telemetry[
|
|
151
|
-
@current_packet = @telemetry[
|
|
157
|
+
@current_cmd_or_tlm = TELEMETRY
|
|
158
|
+
if @telemetry[target_name]
|
|
159
|
+
@current_packet = @telemetry[target_name][packet_name]
|
|
152
160
|
end
|
|
153
161
|
end
|
|
154
162
|
raise parser.error("Packet not found", usage) unless @current_packet
|
|
@@ -199,10 +207,10 @@ module Cosmos
|
|
|
199
207
|
|
|
200
208
|
# Select an item in the current telemetry packet for editing
|
|
201
209
|
when 'SELECT_PARAMETER', 'SELECT_ITEM'
|
|
202
|
-
if (@current_cmd_or_tlm ==
|
|
210
|
+
if (@current_cmd_or_tlm == COMMAND) && (keyword.split('_')[1] == 'ITEM')
|
|
203
211
|
raise parser.error("SELECT_ITEM only applies to telemetry packets")
|
|
204
212
|
end
|
|
205
|
-
if (@current_cmd_or_tlm ==
|
|
213
|
+
if (@current_cmd_or_tlm == TELEMETRY) && (keyword.split('_')[1] == 'PARAMETER')
|
|
206
214
|
raise parser.error("SELECT_PARAMETER only applies to command packets")
|
|
207
215
|
end
|
|
208
216
|
usage = "#{keyword} <#{keyword.split('_')[1]} NAME>"
|
|
@@ -211,22 +219,23 @@ module Cosmos
|
|
|
211
219
|
begin
|
|
212
220
|
@current_item = @current_packet.get_item(params[0])
|
|
213
221
|
rescue # Rescue the default execption to provide a nicer error message
|
|
214
|
-
raise parser.error("#{params[0]} not found in #{@current_cmd_or_tlm.downcase} packet #{@
|
|
222
|
+
raise parser.error("#{params[0]} not found in #{@current_cmd_or_tlm.downcase} packet #{@current_packet.target_name} #{@current_packet.packet_name}", usage)
|
|
215
223
|
end
|
|
216
224
|
|
|
217
225
|
# Start a new telemetry item in the current packet
|
|
218
226
|
when 'ITEM', 'PARAMETER', 'ID_ITEM', 'ID_PARAMETER', 'ARRAY_ITEM', 'ARRAY_PARAMETER', 'APPEND_ITEM', 'APPEND_PARAMETER', 'APPEND_ID_ITEM', 'APPEND_ID_PARAMETER', 'APPEND_ARRAY_ITEM', 'APPEND_ARRAY_PARAMETER'
|
|
219
|
-
start_item(parser
|
|
227
|
+
start_item(parser)
|
|
220
228
|
|
|
221
229
|
# Start the creation of a macro-expanded list of items
|
|
222
230
|
# This simulates an array of structures of multiple items in the packet by repeating
|
|
223
231
|
# each item in the list multiple times with a different "index" added to the name.
|
|
224
232
|
when 'MACRO_APPEND_START'
|
|
225
|
-
|
|
233
|
+
MacroParser.start(parser)
|
|
226
234
|
|
|
227
235
|
# End the creation of a macro-expanded list of items
|
|
228
236
|
when 'MACRO_APPEND_END'
|
|
229
|
-
|
|
237
|
+
finish_item()
|
|
238
|
+
MacroParser.end(parser, @current_packet)
|
|
230
239
|
|
|
231
240
|
# Allow this packet to be received with less data than the defined length
|
|
232
241
|
# without generating a warning.
|
|
@@ -242,7 +251,7 @@ module Cosmos
|
|
|
242
251
|
|
|
243
252
|
# Define a processor class that will be called once when a packet is received
|
|
244
253
|
when 'PROCESSOR'
|
|
245
|
-
|
|
254
|
+
ProcessorParser.parse(parser, @current_packet, @current_cmd_or_tlm)
|
|
246
255
|
|
|
247
256
|
when 'DISABLE_MESSAGES'
|
|
248
257
|
usage = "#{keyword}"
|
|
@@ -285,7 +294,7 @@ module Cosmos
|
|
|
285
294
|
|
|
286
295
|
# Add a state to the current telemety item
|
|
287
296
|
when 'STATE'
|
|
288
|
-
|
|
297
|
+
StateParser.parse(parser, @current_packet, @current_cmd_or_tlm, @current_item, @warnings)
|
|
289
298
|
|
|
290
299
|
# Apply a conversion to the current item after it is read to or
|
|
291
300
|
# written from the packet
|
|
@@ -349,16 +358,17 @@ module Cosmos
|
|
|
349
358
|
|
|
350
359
|
# Define a set of limits for the current telemetry item
|
|
351
360
|
when 'LIMITS'
|
|
352
|
-
|
|
361
|
+
@limits_sets << LimitsParser.parse(parser, @current_packet, @current_cmd_or_tlm, @current_item, @warnings)
|
|
362
|
+
@limits_sets.uniq!
|
|
353
363
|
|
|
354
364
|
# Define a response class that will be called when the limits state of the
|
|
355
365
|
# current item changes.
|
|
356
366
|
when 'LIMITS_RESPONSE'
|
|
357
|
-
|
|
367
|
+
LimitsResponseParser.parse(parser, @current_item, @current_cmd_or_tlm)
|
|
358
368
|
|
|
359
369
|
# Define a printf style formatting string for the current telemetry item
|
|
360
370
|
when 'FORMAT_STRING'
|
|
361
|
-
|
|
371
|
+
FormatStringParser.parse(parser, @current_item)
|
|
362
372
|
|
|
363
373
|
# Define the units of the current telemetry item
|
|
364
374
|
when 'UNITS'
|
|
@@ -378,7 +388,7 @@ module Cosmos
|
|
|
378
388
|
when 'REQUIRED'
|
|
379
389
|
usage = "REQUIRED"
|
|
380
390
|
parser.verify_num_parameters(0, 0, usage)
|
|
381
|
-
if @current_cmd_or_tlm ==
|
|
391
|
+
if @current_cmd_or_tlm == COMMAND
|
|
382
392
|
@current_item.required = true
|
|
383
393
|
else
|
|
384
394
|
raise parser.error("#{keyword} only applies to command parameters")
|
|
@@ -386,7 +396,7 @@ module Cosmos
|
|
|
386
396
|
|
|
387
397
|
# Update the mimimum value for the current command parameter
|
|
388
398
|
when 'MINIMUM_VALUE'
|
|
389
|
-
if @current_cmd_or_tlm ==
|
|
399
|
+
if @current_cmd_or_tlm == TELEMETRY
|
|
390
400
|
raise parser.error("#{keyword} only applies to command parameters")
|
|
391
401
|
end
|
|
392
402
|
usage = "MINIMUM_VALUE <MINIMUM VALUE>"
|
|
@@ -397,7 +407,7 @@ module Cosmos
|
|
|
397
407
|
|
|
398
408
|
# Update the maximum value for the current command parameter
|
|
399
409
|
when 'MAXIMUM_VALUE'
|
|
400
|
-
if @current_cmd_or_tlm ==
|
|
410
|
+
if @current_cmd_or_tlm == TELEMETRY
|
|
401
411
|
raise parser.error("#{keyword} only applies to command parameters")
|
|
402
412
|
end
|
|
403
413
|
usage = "MAXIMUM_VALUE <MAXIMUM VALUE>"
|
|
@@ -408,7 +418,7 @@ module Cosmos
|
|
|
408
418
|
|
|
409
419
|
# Update the default value for the current command parameter
|
|
410
420
|
when 'DEFAULT_VALUE'
|
|
411
|
-
if @current_cmd_or_tlm ==
|
|
421
|
+
if @current_cmd_or_tlm == TELEMETRY
|
|
412
422
|
raise parser.error("#{keyword} only applies to command parameters")
|
|
413
423
|
end
|
|
414
424
|
usage = "DEFAULT_VALUE <DEFAULT VALUE>"
|
|
@@ -430,597 +440,35 @@ module Cosmos
|
|
|
430
440
|
end
|
|
431
441
|
end
|
|
432
442
|
|
|
433
|
-
####################################################
|
|
434
|
-
# The following methods process a particular keyword
|
|
435
|
-
|
|
436
|
-
def process_macro_append_start(parser, keyword, params)
|
|
437
|
-
@macro_append.building = true
|
|
438
|
-
|
|
439
|
-
usage = '#{keyword} <FIRST INDEX> <LAST INDEX> [NAME FORMAT]'
|
|
440
|
-
parser.verify_num_parameters(2, 3, usage)
|
|
441
|
-
|
|
442
|
-
# Store the params
|
|
443
|
-
first_index = params[0].to_i
|
|
444
|
-
last_index = params[1].to_i
|
|
445
|
-
@macro_append.indices = [first_index, last_index].sort
|
|
446
|
-
@macro_append.indices = (@macro_append.indices[0]..@macro_append.indices[1]).to_a
|
|
447
|
-
@macro_append.indices.reverse! if first_index > last_index
|
|
448
|
-
@macro_append.format = params[2] ? params[2] : '%s%d'
|
|
449
|
-
spos = @macro_append.format.index(/%\d*s/)
|
|
450
|
-
dpos = @macro_append.format.index(/%\d*d/)
|
|
451
|
-
raise parser.error("Invalid NAME FORMAT (#{@macro_append.format}) for MACRO_APPEND_START", usage) unless spos and dpos
|
|
452
|
-
if spos < dpos
|
|
453
|
-
@macro_append.format_order = 'sd'
|
|
454
|
-
else
|
|
455
|
-
@macro_append.format_order = 'ds'
|
|
456
|
-
end
|
|
457
|
-
end
|
|
458
|
-
|
|
459
|
-
def process_macro_append_end(parser, keyword)
|
|
460
|
-
update_cache = false
|
|
461
|
-
finish_item()
|
|
462
|
-
parser.verify_num_parameters(0, 0, keyword)
|
|
463
|
-
raise parser.error("Missing MACRO_APPEND_START before this config.line.", keyword) unless @macro_append.building
|
|
464
|
-
raise parser.error("No items appended in MACRO_APPEND list", keyword) unless @macro_append.list.length > 0
|
|
465
|
-
|
|
466
|
-
# Get first index, remove from array
|
|
467
|
-
first = @macro_append.indices.shift
|
|
468
|
-
|
|
469
|
-
# Rename the items in the list using the first index
|
|
470
|
-
items = @current_packet.items
|
|
471
|
-
@macro_append.list.each do |name|
|
|
472
|
-
item = items[name]
|
|
473
|
-
items.delete name
|
|
474
|
-
if @macro_append.format_order == 'sd'
|
|
475
|
-
first_name = sprintf(@macro_append.format, name, first)
|
|
476
|
-
else
|
|
477
|
-
first_name = sprintf(@macro_append.format, first, name)
|
|
478
|
-
end
|
|
479
|
-
item.name = first_name
|
|
480
|
-
items[first_name] = item
|
|
481
|
-
end
|
|
482
|
-
|
|
483
|
-
# Append multiple copies of the items in the list
|
|
484
|
-
@macro_append.indices.each do |index|
|
|
485
|
-
@macro_append.list.each do |name|
|
|
486
|
-
if @macro_append.format_order == 'sd'
|
|
487
|
-
first_name = sprintf(@macro_append.format, name, first)
|
|
488
|
-
this_name = sprintf(@macro_append.format, name, index)
|
|
489
|
-
else
|
|
490
|
-
first_name = sprintf(@macro_append.format, first, name)
|
|
491
|
-
this_name = sprintf(@macro_append.format, index, name)
|
|
492
|
-
end
|
|
493
|
-
first_item = items[first_name]
|
|
494
|
-
format_string = nil
|
|
495
|
-
format_string = first_item.format_string if first_item.format_string
|
|
496
|
-
this_item = @current_packet.append_item(this_name,
|
|
497
|
-
first_item.bit_size,
|
|
498
|
-
first_item.data_type,
|
|
499
|
-
first_item.array_size,
|
|
500
|
-
first_item.endianness,
|
|
501
|
-
first_item.overflow,
|
|
502
|
-
format_string,
|
|
503
|
-
first_item.read_conversion,
|
|
504
|
-
first_item.write_conversion,
|
|
505
|
-
first_item.id_value)
|
|
506
|
-
this_item.states = first_item.states if first_item.states
|
|
507
|
-
this_item.description = first_item.description if first_item.description
|
|
508
|
-
this_item.units_full = first_item.units_full if first_item.units_full
|
|
509
|
-
this_item.units = first_item.units if first_item.units
|
|
510
|
-
this_item.default = first_item.default
|
|
511
|
-
this_item.range = first_item.range if first_item.range
|
|
512
|
-
this_item.required = first_item.required
|
|
513
|
-
this_item.hazardous = first_item.hazardous
|
|
514
|
-
if first_item.state_colors
|
|
515
|
-
this_item.state_colors = first_item.state_colors
|
|
516
|
-
update_cache = true
|
|
517
|
-
end
|
|
518
|
-
if first_item.limits
|
|
519
|
-
this_item.limits = first_item.limits
|
|
520
|
-
update_cache = true
|
|
521
|
-
end
|
|
522
|
-
end
|
|
523
|
-
end
|
|
524
|
-
@current_packet.update_limits_items_cache if update_cache
|
|
525
|
-
|
|
526
|
-
@macro_append.building = false
|
|
527
|
-
@macro_append.indices = []
|
|
528
|
-
@macro_append.list = []
|
|
529
|
-
end
|
|
530
|
-
|
|
531
|
-
def process_state(parser, keyword, params)
|
|
532
|
-
if @current_cmd_or_tlm == 'Command'
|
|
533
|
-
usage = "#{keyword} <STATE NAME> <STATE VALUE> <HAZARDOUS (Optional)> <Hazardous Description (Optional)>"
|
|
534
|
-
parser.verify_num_parameters(2, 4, usage)
|
|
535
|
-
else
|
|
536
|
-
usage = "#{keyword} <STATE NAME> <STATE VALUE> <COLOR: GREEN/YELLOW/RED (Optional)>"
|
|
537
|
-
parser.verify_num_parameters(2, 3, usage)
|
|
538
|
-
end
|
|
539
|
-
@current_item.states ||= {}
|
|
540
|
-
if @current_item.states[params[0].upcase]
|
|
541
|
-
msg = "Duplicate state defined on line #{parser.line_number}: #{parser.line}"
|
|
542
|
-
Logger.instance.warn(msg)
|
|
543
|
-
@warnings << msg
|
|
544
|
-
end
|
|
545
|
-
if @current_item.data_type == :STRING or @current_item.data_type == :BLOCK
|
|
546
|
-
@current_item.states[params[0].upcase] = params[1]
|
|
547
|
-
else
|
|
548
|
-
@current_item.states[params[0].upcase] = params[1].convert_to_value
|
|
549
|
-
end
|
|
550
|
-
if params[2]
|
|
551
|
-
if @current_cmd_or_tlm == 'Command'
|
|
552
|
-
if params[2].upcase == 'HAZARDOUS'
|
|
553
|
-
@current_item.hazardous ||= {}
|
|
554
|
-
if params[3]
|
|
555
|
-
@current_item.hazardous[params[0].upcase] = params[3]
|
|
556
|
-
else
|
|
557
|
-
@current_item.hazardous[params[0].upcase] = ""
|
|
558
|
-
end
|
|
559
|
-
else
|
|
560
|
-
raise parser.error("HAZARDOUS expected as third parameter for this line.", usage)
|
|
561
|
-
end
|
|
562
|
-
else
|
|
563
|
-
if params[2]
|
|
564
|
-
color = params[2].upcase.to_sym
|
|
565
|
-
unless PacketItem::STATE_COLORS.include? color
|
|
566
|
-
raise parser.error("Invalid state color #{color}. Must be one of #{PacketItem::STATE_COLORS.join(' ')}.", usage)
|
|
567
|
-
end
|
|
568
|
-
@current_item.limits ||= Limits.new
|
|
569
|
-
@current_item.limits.enabled = true
|
|
570
|
-
@current_item.state_colors ||= {}
|
|
571
|
-
@current_item.state_colors[params[0].upcase] = color
|
|
572
|
-
@current_packet.update_limits_items_cache
|
|
573
|
-
end
|
|
574
|
-
end
|
|
575
|
-
end
|
|
576
|
-
end
|
|
577
|
-
|
|
578
|
-
def process_limits(parser, keyword, params)
|
|
579
|
-
if @current_cmd_or_tlm == 'Command'
|
|
580
|
-
raise parser.error("#{keyword} only applies to telemetry items")
|
|
581
|
-
end
|
|
582
|
-
usage = "#{keyword} <LIMITS SET> <PERSISTENCE> <ENABLED/DISABLED> <RED LOW LIMIT> <YELLOW LOW LIMIT> <YELLOW HIGH LIMIT> <RED HIGH LIMIT> <GREEN LOW LIMIT (Optional)> <GREEN HIGH LIMIT (Optional)>"
|
|
583
|
-
parser.verify_num_parameters(7, 9, usage)
|
|
584
|
-
|
|
585
|
-
begin
|
|
586
|
-
persistence = Integer(params[1])
|
|
587
|
-
red_low = Float(params[3])
|
|
588
|
-
yellow_low = Float(params[4])
|
|
589
|
-
yellow_high = Float(params[5])
|
|
590
|
-
red_high = Float(params[6])
|
|
591
|
-
rescue
|
|
592
|
-
raise parser.error("Invalid persistence or limits values. Ensure persistence is an integer. Limits can be integers or floats.", usage)
|
|
593
|
-
end
|
|
594
|
-
|
|
595
|
-
enabled = params[2].upcase
|
|
596
|
-
if enabled != 'ENABLED' and enabled != 'DISABLED'
|
|
597
|
-
raise parser.error("Initial state must be ENABLED or DISABLED.", usage)
|
|
598
|
-
end
|
|
599
|
-
|
|
600
|
-
# Verify valid limits are specified
|
|
601
|
-
if (red_low > yellow_low) or (yellow_low >= yellow_high) or (yellow_high > red_high)
|
|
602
|
-
raise parser.error("Invalid limits specified. Ensure yellow limits are within red limits.", usage)
|
|
603
|
-
end
|
|
604
|
-
if params.length != 7
|
|
605
|
-
begin
|
|
606
|
-
green_low = Float(params[7])
|
|
607
|
-
green_high = Float(params[8])
|
|
608
|
-
rescue
|
|
609
|
-
raise parser.error("Invalid green limits values. Limits can be integers or floats.", usage)
|
|
610
|
-
end
|
|
611
|
-
|
|
612
|
-
if (yellow_low > green_low) or (green_low >= green_high) or (green_high > yellow_high)
|
|
613
|
-
raise parser.error("Invalid limits specified. Ensure green limits are within yellow limits.", usage)
|
|
614
|
-
end
|
|
615
|
-
end
|
|
616
|
-
|
|
617
|
-
limits_set = params[0].upcase.to_sym
|
|
618
|
-
@limits_sets << limits_set
|
|
619
|
-
@limits_sets.uniq!
|
|
620
|
-
# Initialize the limits values. Values must be initialized with a :DEFAULT key
|
|
621
|
-
if !@current_item.limits.values
|
|
622
|
-
if limits_set == :DEFAULT
|
|
623
|
-
@current_item.limits.values = {:DEFAULT => []}
|
|
624
|
-
else
|
|
625
|
-
raise parser.error("DEFAULT limits must be defined for #{@current_packet.target_name} #{@current_packet.packet_name} #{@current_item.name} before setting limits set #{limits_set}")
|
|
626
|
-
end
|
|
627
|
-
end
|
|
628
|
-
if limits_set != :DEFAULT
|
|
629
|
-
msg = nil
|
|
630
|
-
if (enabled == 'ENABLED' and @current_item.limits.enabled != true) or (enabled != 'ENABLED' and @current_item.limits.enabled != false)
|
|
631
|
-
msg = "#{@current_cmd_or_tlm} Item #{@current_target_name} #{@current_packet_name} #{@current_item.name} #{limits_set} limits enable setting conflict with DEFAULT"
|
|
632
|
-
end
|
|
633
|
-
if @current_item.limits.persistence_setting != persistence
|
|
634
|
-
msg = "#{@current_cmd_or_tlm} Item #{@current_target_name} #{@current_packet_name} #{@current_item.name} #{limits_set} limits persistence setting conflict with DEFAULT"
|
|
635
|
-
end
|
|
636
|
-
if msg
|
|
637
|
-
Logger.instance.warn msg
|
|
638
|
-
@warnings << msg
|
|
639
|
-
end
|
|
640
|
-
end
|
|
641
|
-
@current_item.limits.enabled = true if enabled == 'ENABLED'
|
|
642
|
-
values = @current_item.limits.values
|
|
643
|
-
if params.length == 7
|
|
644
|
-
values[limits_set] = [red_low, yellow_low, yellow_high, red_high]
|
|
645
|
-
else
|
|
646
|
-
values[limits_set] = [red_low, yellow_low, yellow_high, red_high, green_low, green_high]
|
|
647
|
-
end
|
|
648
|
-
@current_item.limits.values = values
|
|
649
|
-
@current_item.limits.persistence_setting = persistence
|
|
650
|
-
@current_item.limits.persistence_count = 0
|
|
651
|
-
@current_packet.update_limits_items_cache
|
|
652
|
-
end
|
|
653
|
-
|
|
654
|
-
def process_limits_response(parser, keyword, params)
|
|
655
|
-
if @current_cmd_or_tlm == 'Command'
|
|
656
|
-
raise parser.error("#{keyword} only applies to telemetry items")
|
|
657
|
-
end
|
|
658
|
-
usage = "#{keyword} <RESPONSE CLASS FILENAME> <RESPONSE SPECIFIC OPTIONS>"
|
|
659
|
-
parser.verify_num_parameters(1, nil, usage)
|
|
660
|
-
|
|
661
|
-
begin
|
|
662
|
-
# require should be performed in target.txt
|
|
663
|
-
klass = params[0].filename_to_class_name.to_class
|
|
664
|
-
raise parser.error("#{params[0].filename_to_class_name} class not found. Did you require the file in target.txt?", usage) unless klass
|
|
665
|
-
if params[1]
|
|
666
|
-
@current_item.limits.response = klass.new(*params[1..(params.length - 1)])
|
|
667
|
-
else
|
|
668
|
-
@current_item.limits.response = klass.new
|
|
669
|
-
end
|
|
670
|
-
rescue Exception => err
|
|
671
|
-
raise parser.error(err, usage)
|
|
672
|
-
end
|
|
673
|
-
end
|
|
674
|
-
|
|
675
|
-
def process_processor(parser, keyword, params)
|
|
676
|
-
if @current_cmd_or_tlm == 'Command'
|
|
677
|
-
raise parser.error("#{keyword} only applies to telemetry packets")
|
|
678
|
-
end
|
|
679
|
-
usage = "#{keyword} <PROCESSOR NAME> <PROCESSOR CLASS FILENAME> <PROCESSOR SPECIFIC OPTIONS>"
|
|
680
|
-
parser.verify_num_parameters(2, nil, usage)
|
|
681
|
-
|
|
682
|
-
begin
|
|
683
|
-
# require should be performed in target.txt
|
|
684
|
-
klass = params[1].filename_to_class_name.to_class
|
|
685
|
-
raise parser.error("#{params[1].filename_to_class_name} class not found. Did you require the file in target.txt?", usage) unless klass
|
|
686
|
-
if params[2]
|
|
687
|
-
processor = klass.new(*params[2..(params.length - 1)])
|
|
688
|
-
else
|
|
689
|
-
processor = klass.new
|
|
690
|
-
end
|
|
691
|
-
raise ArgumentError, "processor must be a Cosmos::Processor but is a #{processor.class}" unless Cosmos::Processor === processor
|
|
692
|
-
processor.name = params[0]
|
|
693
|
-
@current_packet.processors[params[0].to_s.upcase] = processor
|
|
694
|
-
rescue Exception => err
|
|
695
|
-
raise parser.error(err, usage)
|
|
696
|
-
end
|
|
697
|
-
end
|
|
698
|
-
|
|
699
|
-
def process_format_string(parser, keyword, params)
|
|
700
|
-
usage = "#{keyword} <PRINTF STYLE STRING>"
|
|
701
|
-
parser.verify_num_parameters(1, 1, usage)
|
|
702
|
-
@current_item.format_string = params[0]
|
|
703
|
-
unless @current_item.read_conversion
|
|
704
|
-
# Check format string as long as a read conversion has not been defined
|
|
705
|
-
begin
|
|
706
|
-
case @current_item.data_type
|
|
707
|
-
when :INT, :UINT
|
|
708
|
-
sprintf(@current_item.format_string, 0)
|
|
709
|
-
when :FLOAT
|
|
710
|
-
sprintf(@current_item.format_string, 0.0)
|
|
711
|
-
when :STRING, :BLOCK
|
|
712
|
-
sprintf(@current_item.format_string, 'Hello')
|
|
713
|
-
else
|
|
714
|
-
# Nothing to do
|
|
715
|
-
end
|
|
716
|
-
rescue Exception
|
|
717
|
-
raise parser.error("Invalid #{keyword} specified for type #{@current_item.data_type}: #{params[0]}", usage)
|
|
718
|
-
end
|
|
719
|
-
end
|
|
720
|
-
end
|
|
721
|
-
|
|
722
|
-
def process_packet(parser, keyword, params, target_name)
|
|
723
|
-
finish_packet()
|
|
724
|
-
|
|
725
|
-
usage = "#{keyword} <TARGET NAME> <PACKET NAME> <ENDIANNESS: BIG_ENDIAN/LITTLE_ENDIAN> <DESCRIPTION (Optional)>"
|
|
726
|
-
parser.verify_num_parameters(3, 4, usage)
|
|
727
|
-
target_name = params[0].to_s.upcase if target_name == 'SYSTEM'
|
|
728
|
-
packet_name = params[1].to_s.upcase
|
|
729
|
-
endianness = params[2].to_s.upcase.intern
|
|
730
|
-
description = params[3].to_s
|
|
731
|
-
if endianness != :BIG_ENDIAN and endianness != :LITTLE_ENDIAN
|
|
732
|
-
raise parser.error("Invalid endianness #{params[2]}. Must be BIG_ENDIAN or LITTLE_ENDIAN.", usage)
|
|
733
|
-
end
|
|
734
|
-
|
|
735
|
-
@current_target_name = target_name
|
|
736
|
-
@current_packet_name = packet_name
|
|
737
|
-
@current_cmd_or_tlm = keyword.capitalize
|
|
738
|
-
|
|
739
|
-
# Be sure there is not already a packet by this name
|
|
740
|
-
if @current_cmd_or_tlm == 'Command'
|
|
741
|
-
if @commands[@current_target_name]
|
|
742
|
-
if @commands[@current_target_name][@current_packet_name]
|
|
743
|
-
msg = "#{@current_cmd_or_tlm} Packet #{@current_target_name} #{@current_packet_name} redefined."
|
|
744
|
-
Logger.instance.warn msg
|
|
745
|
-
@warnings << msg
|
|
746
|
-
end
|
|
747
|
-
end
|
|
748
|
-
else
|
|
749
|
-
if @telemetry[@current_target_name]
|
|
750
|
-
if @telemetry[@current_target_name][@current_packet_name]
|
|
751
|
-
msg = "#{@current_cmd_or_tlm} Packet #{@current_target_name} #{@current_packet_name} redefined."
|
|
752
|
-
Logger.instance.warn msg
|
|
753
|
-
@warnings << msg
|
|
754
|
-
end
|
|
755
|
-
end
|
|
756
|
-
end
|
|
757
|
-
|
|
758
|
-
@current_packet = Packet.new(@current_target_name, @current_packet_name, endianness, description)
|
|
759
|
-
|
|
760
|
-
# Add received time packet items
|
|
761
|
-
if @current_cmd_or_tlm == 'Telemetry'
|
|
762
|
-
item = @current_packet.define_item('RECEIVED_TIMESECONDS', 0, 0, :DERIVED, nil, @current_packet.default_endianness, :ERROR, '%0.6f', ReceivedTimeSecondsConversion.new)
|
|
763
|
-
item.description = 'COSMOS Received Time (UTC, Floating point, Unix epoch)'
|
|
764
|
-
item = @current_packet.define_item('RECEIVED_TIMEFORMATTED', 0, 0, :DERIVED, nil, @current_packet.default_endianness, :ERROR, nil, ReceivedTimeFormattedConversion.new)
|
|
765
|
-
item.description = 'COSMOS Received Time (Local time zone, Formatted string)'
|
|
766
|
-
item = @current_packet.define_item('RECEIVED_COUNT', 0, 0, :DERIVED, nil, @current_packet.default_endianness, :ERROR, nil, ReceivedCountConversion.new)
|
|
767
|
-
item.description = 'COSMOS packet received count'
|
|
768
|
-
|
|
769
|
-
unless @telemetry[@current_target_name]
|
|
770
|
-
@telemetry[@current_target_name] = {}
|
|
771
|
-
@latest_data[@current_target_name] = {}
|
|
772
|
-
end
|
|
773
|
-
else
|
|
774
|
-
@commands[@current_target_name] ||= {}
|
|
775
|
-
end
|
|
776
|
-
end
|
|
777
|
-
|
|
778
443
|
# Add current packet into hash if it exists
|
|
779
444
|
def finish_packet
|
|
780
445
|
finish_item()
|
|
781
446
|
if @current_packet
|
|
782
|
-
|
|
783
|
-
# This will allow gaps in the packet, but not allow the same bits to be
|
|
784
|
-
# used for multiple variables.
|
|
785
|
-
expected_next_offset = nil
|
|
786
|
-
previous_item = nil
|
|
787
|
-
@current_packet.sorted_items.each do |item|
|
|
788
|
-
if expected_next_offset and item.bit_offset < expected_next_offset
|
|
789
|
-
msg = "Bit definition overlap at bit offset #{item.bit_offset} for #{@current_cmd_or_tlm} packet #{@current_target_name} #{@current_packet_name} items #{item.name} and #{previous_item.name}"
|
|
790
|
-
Logger.instance.warn(msg)
|
|
791
|
-
@warnings << msg
|
|
792
|
-
end
|
|
793
|
-
if item.array_size
|
|
794
|
-
if item.array_size > 0
|
|
795
|
-
expected_next_offset = item.bit_offset + item.array_size
|
|
796
|
-
else
|
|
797
|
-
expected_next_offset = item.array_size
|
|
798
|
-
end
|
|
799
|
-
else
|
|
800
|
-
expected_next_offset = nil
|
|
801
|
-
if item.bit_offset > 0
|
|
802
|
-
# Handle little-endian bit fields
|
|
803
|
-
byte_aligned = ((item.bit_offset % 8) == 0)
|
|
804
|
-
if item.endianness == :LITTLE_ENDIAN and (item.data_type == :INT or item.data_type == :UINT) and !(byte_aligned and (item.bit_size == 8 or item.bit_size == 16 or item.bit_size == 32 or item.bit_size == 64))
|
|
805
|
-
# Bitoffset always refers to the most significant bit of a bitfield
|
|
806
|
-
bits_remaining_in_last_byte = 8 - (item.bit_offset % 8)
|
|
807
|
-
if item.bit_size > bits_remaining_in_last_byte
|
|
808
|
-
expected_next_offset = item.bit_offset + bits_remaining_in_last_byte
|
|
809
|
-
end
|
|
810
|
-
end
|
|
811
|
-
end
|
|
812
|
-
unless expected_next_offset
|
|
813
|
-
if item.bit_size > 0
|
|
814
|
-
expected_next_offset = item.bit_offset + item.bit_size
|
|
815
|
-
else
|
|
816
|
-
expected_next_offset = item.bit_size
|
|
817
|
-
end
|
|
818
|
-
end
|
|
819
|
-
end
|
|
820
|
-
previous_item = item
|
|
821
|
-
|
|
822
|
-
# Check command default and range data types if no write conversion is present
|
|
823
|
-
item.check_default_and_range_data_types if @current_cmd_or_tlm == 'Command'
|
|
824
|
-
end
|
|
447
|
+
@warnings += @current_packet.check_bit_offsets
|
|
825
448
|
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
@commands[@
|
|
449
|
+
if @current_cmd_or_tlm == COMMAND
|
|
450
|
+
PacketParser.check_item_data_types(@current_packet)
|
|
451
|
+
@commands[@current_packet.target_name][@current_packet.packet_name] = @current_packet
|
|
829
452
|
else
|
|
830
|
-
@telemetry[@
|
|
453
|
+
@telemetry[@current_packet.target_name][@current_packet.packet_name] = @current_packet
|
|
831
454
|
end
|
|
832
455
|
@current_packet = nil
|
|
833
456
|
@current_item = nil
|
|
834
457
|
end
|
|
835
458
|
end
|
|
836
459
|
|
|
837
|
-
|
|
838
|
-
# and parameters to generate the correct usage information.
|
|
839
|
-
def generate_item_usage(keyword, params)
|
|
840
|
-
usage = "#{keyword} <ITEM NAME> "
|
|
841
|
-
usage << "<BIT OFFSET> " unless keyword.include?("APPEND")
|
|
842
|
-
if keyword.include?("ARRAY")
|
|
843
|
-
usage << "<ARRAY ITEM BIT SIZE> "
|
|
844
|
-
else
|
|
845
|
-
usage << "<BIT SIZE> "
|
|
846
|
-
end
|
|
847
|
-
if keyword.include?("PARAMETER")
|
|
848
|
-
if keyword.include?("ARRAY")
|
|
849
|
-
usage << "<TYPE: INT/UINT/FLOAT/STRING/BLOCK> "
|
|
850
|
-
else
|
|
851
|
-
if keyword.include?("APPEND")
|
|
852
|
-
data_type = params[2].upcase.to_sym
|
|
853
|
-
else
|
|
854
|
-
data_type = params[3].upcase.to_sym
|
|
855
|
-
end
|
|
856
|
-
if data_type == :STRING or data_type == :BLOCK
|
|
857
|
-
if keyword.include?("ID")
|
|
858
|
-
usage << "<TYPE: STRING/BLOCK> "
|
|
859
|
-
else
|
|
860
|
-
usage << "<TYPE: STRING/BLOCK> <DEFAULT VALUE>"
|
|
861
|
-
end
|
|
862
|
-
else
|
|
863
|
-
if keyword.include?("ID")
|
|
864
|
-
usage << "<TYPE: INT/UINT/FLOAT> <MIN VALUE> <MAX VALUE> "
|
|
865
|
-
else
|
|
866
|
-
usage << "<TYPE: INT/UINT/FLOAT/DERIVED> <MIN VALUE> <MAX VALUE> <DEFAULT VALUE>"
|
|
867
|
-
end
|
|
868
|
-
end
|
|
869
|
-
end
|
|
870
|
-
else
|
|
871
|
-
usage << "<TYPE: INT/UINT/FLOAT/STRING/BLOCK/DERIVED> "
|
|
872
|
-
end
|
|
873
|
-
usage << "<TOTAL ARRAY BIT SIZE> " if keyword.include?("ARRAY")
|
|
874
|
-
if keyword.include?("ID")
|
|
875
|
-
if keyword.include?("PARAMETER")
|
|
876
|
-
usage << "<DEFAULT AND ID VALUE> "
|
|
877
|
-
else
|
|
878
|
-
usage << "<ID VALUE> "
|
|
879
|
-
end
|
|
880
|
-
end
|
|
881
|
-
usage << "<DESCRIPTION (Optional)> <ENDIANNESS (Optional)>"
|
|
882
|
-
return usage
|
|
883
|
-
end
|
|
884
|
-
|
|
885
|
-
def start_item(parser, keyword, params)
|
|
460
|
+
def start_item(parser)
|
|
886
461
|
finish_item()
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
max_options = usage.count("<")
|
|
890
|
-
parser.verify_num_parameters(max_options-2, max_options, usage)
|
|
891
|
-
begin
|
|
892
|
-
if params[max_options-1]
|
|
893
|
-
endianness = params[max_options-1].to_s.upcase.intern
|
|
894
|
-
if endianness != :BIG_ENDIAN and endianness != :LITTLE_ENDIAN
|
|
895
|
-
raise parser.error("Invalid endianness #{params[2]}. Must be BIG_ENDIAN or LITTLE_ENDIAN.", usage)
|
|
896
|
-
end
|
|
897
|
-
else
|
|
898
|
-
endianness = @current_packet.default_endianness
|
|
899
|
-
end
|
|
900
|
-
|
|
901
|
-
case keyword
|
|
902
|
-
when /ITEM/
|
|
903
|
-
raise parser.error("ITEM types are only valid with TELEMETRY", usage) if @current_cmd_or_tlm == 'Command'
|
|
904
|
-
# If this is an APPEND we don't have a bit offset so the index
|
|
905
|
-
# into the parameters changes
|
|
906
|
-
index = (keyword =~ /APPEND/) ? 3 : 4
|
|
907
|
-
id_value = (keyword =~ /ID_ITEM/) ? params[index] : nil
|
|
908
|
-
array_size = (keyword =~ /ARRAY_ITEM/) ? Integer(params[index]) : nil
|
|
909
|
-
case keyword
|
|
910
|
-
when 'ITEM', 'ID_ITEM', 'ARRAY_ITEM'
|
|
911
|
-
@current_item = @current_packet.define_item(params[0], # name
|
|
912
|
-
Integer(params[1]), # bit offset
|
|
913
|
-
Integer(params[2]), # bit size
|
|
914
|
-
params[3].upcase.to_sym, # data_type
|
|
915
|
-
array_size, # array size
|
|
916
|
-
endianness, # endianness
|
|
917
|
-
:ERROR, # overflow
|
|
918
|
-
nil, # format string
|
|
919
|
-
nil, # read conversion
|
|
920
|
-
nil, # write conversion
|
|
921
|
-
id_value) # id value
|
|
922
|
-
when 'APPEND_ITEM', 'APPEND_ID_ITEM', 'APPEND_ARRAY_ITEM'
|
|
923
|
-
@current_item = @current_packet.append_item(params[0], # name
|
|
924
|
-
Integer(params[1]), # bit size
|
|
925
|
-
params[2].upcase.to_sym, # data_type
|
|
926
|
-
array_size, # array size
|
|
927
|
-
endianness, # endianness
|
|
928
|
-
:ERROR, # overflow
|
|
929
|
-
nil, # format string
|
|
930
|
-
nil, # read conversion
|
|
931
|
-
nil, # write conversion
|
|
932
|
-
id_value) # id value
|
|
933
|
-
end
|
|
934
|
-
when 'PARAMETER', 'ID_PARAMETER', 'ARRAY_PARAMETER'
|
|
935
|
-
raise parser.error("PARAMETER types are only valid with COMMAND", usage) if @current_cmd_or_tlm == 'Telemetry'
|
|
936
|
-
data_type = params[3].upcase.to_sym
|
|
937
|
-
id_value = nil
|
|
938
|
-
if keyword == 'ID_PARAMETER'
|
|
939
|
-
if data_type == :DERIVED
|
|
940
|
-
raise "DERIVED data type not allowed"
|
|
941
|
-
elsif data_type == :STRING or data_type == :BLOCK
|
|
942
|
-
id_value = params[4]
|
|
943
|
-
else
|
|
944
|
-
id_value = params[6]
|
|
945
|
-
end
|
|
946
|
-
end
|
|
947
|
-
array_size = (keyword == 'ARRAY_PARAMETER') ? Integer(params[4]) : nil
|
|
948
|
-
@current_item = @current_packet.define_item(params[0], # name
|
|
949
|
-
Integer(params[1]), # bit offset
|
|
950
|
-
Integer(params[2]), # bit size
|
|
951
|
-
data_type, # data_type
|
|
952
|
-
array_size, # array size
|
|
953
|
-
endianness, # endianness
|
|
954
|
-
:ERROR, # overflow
|
|
955
|
-
nil, # format string
|
|
956
|
-
nil, # read conversion
|
|
957
|
-
nil, # write conversion
|
|
958
|
-
id_value) # id value
|
|
959
|
-
if keyword == 'ARRAY_PARAMETER'
|
|
960
|
-
@current_item.default = []
|
|
961
|
-
else
|
|
962
|
-
if data_type == :STRING or data_type == :BLOCK
|
|
963
|
-
@current_item.default = params[4]
|
|
964
|
-
else
|
|
965
|
-
@current_item.range =
|
|
966
|
-
(ConfigParser.handle_defined_constants(params[4].convert_to_value))..(ConfigParser.handle_defined_constants(params[5].convert_to_value))
|
|
967
|
-
@current_item.default = ConfigParser.handle_defined_constants(params[6].convert_to_value)
|
|
968
|
-
end
|
|
969
|
-
end
|
|
970
|
-
when 'APPEND_PARAMETER', 'APPEND_ID_PARAMETER', 'APPEND_ARRAY_PARAMETER'
|
|
971
|
-
raise parser.error("PARAMETER types are only valid with COMMAND", usage) if @current_cmd_or_tlm == 'Telemetry'
|
|
972
|
-
data_type = params[2].upcase.to_sym
|
|
973
|
-
id_value = nil
|
|
974
|
-
if keyword == 'APPEND_ID_PARAMETER'
|
|
975
|
-
if data_type == :DERIVED
|
|
976
|
-
raise "DERIVED data type not allowed"
|
|
977
|
-
elsif data_type == :STRING or data_type == :BLOCK
|
|
978
|
-
id_value = params[3]
|
|
979
|
-
else
|
|
980
|
-
id_value = params[5]
|
|
981
|
-
end
|
|
982
|
-
end
|
|
983
|
-
array_size = (keyword == 'APPEND_ARRAY_PARAMETER') ? Integer(params[3]) : nil
|
|
984
|
-
@current_item = @current_packet.append_item(params[0], # name
|
|
985
|
-
Integer(params[1]), # bit size
|
|
986
|
-
data_type, # data_type
|
|
987
|
-
array_size, # array size
|
|
988
|
-
endianness, # endianness
|
|
989
|
-
:ERROR, # overflow
|
|
990
|
-
nil, # format string
|
|
991
|
-
nil, # read conversion
|
|
992
|
-
nil, # write conversion
|
|
993
|
-
id_value) # id value
|
|
994
|
-
if keyword == 'APPEND_ARRAY_PARAMETER'
|
|
995
|
-
@current_item.default = []
|
|
996
|
-
else
|
|
997
|
-
if data_type == :STRING or data_type == :BLOCK
|
|
998
|
-
@current_item.default = params[3]
|
|
999
|
-
else
|
|
1000
|
-
@current_item.range =
|
|
1001
|
-
(ConfigParser.handle_defined_constants(params[3].convert_to_value))..(ConfigParser.handle_defined_constants(params[4].convert_to_value))
|
|
1002
|
-
@current_item.default = ConfigParser.handle_defined_constants(params[5].convert_to_value)
|
|
1003
|
-
end
|
|
1004
|
-
end
|
|
1005
|
-
end
|
|
1006
|
-
@current_item.description = params[max_options-2] if params[max_options-2]
|
|
1007
|
-
|
|
1008
|
-
if keyword.include?('APPEND') && @macro_append.building
|
|
1009
|
-
@macro_append.list << params[0].upcase
|
|
1010
|
-
end
|
|
1011
|
-
|
|
1012
|
-
# Rescue the item processing since they could also throw configuration errors
|
|
1013
|
-
rescue => err
|
|
1014
|
-
raise parser.error(err, usage)
|
|
1015
|
-
end
|
|
462
|
+
@current_item = PacketItemParser.parse(parser, @current_packet, @current_cmd_or_tlm)
|
|
463
|
+
MacroParser.new_item()
|
|
1016
464
|
end
|
|
1017
465
|
|
|
1018
|
-
# Finish updating item
|
|
466
|
+
# Finish updating packet item
|
|
1019
467
|
def finish_item
|
|
1020
468
|
if @current_item
|
|
1021
469
|
@current_packet.set_item(@current_item)
|
|
1022
|
-
if @current_cmd_or_tlm ==
|
|
1023
|
-
target_latest_data = @latest_data[@
|
|
470
|
+
if @current_cmd_or_tlm == TELEMETRY
|
|
471
|
+
target_latest_data = @latest_data[@current_packet.target_name]
|
|
1024
472
|
target_latest_data[@current_item.name] ||= []
|
|
1025
473
|
latest_data_packets = target_latest_data[@current_item.name]
|
|
1026
474
|
latest_data_packets << @current_packet unless latest_data_packets.include?(@current_packet)
|