openc3 5.10.1 → 5.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -2
  3. data/data/config/target.yaml +9 -0
  4. data/ext/openc3/ext/packet/packet.c +3 -0
  5. data/ext/openc3/ext/reducer_microservice/extconf.rb +13 -0
  6. data/ext/openc3/ext/reducer_microservice/reducer_microservice.c +165 -0
  7. data/ext/openc3/ext/structure/structure.c +7 -9
  8. data/lib/openc3/accessors/accessor.rb +53 -3
  9. data/lib/openc3/accessors/binary_accessor.rb +16 -0
  10. data/lib/openc3/accessors/cbor_accessor.rb +3 -3
  11. data/lib/openc3/accessors/form_accessor.rb +78 -0
  12. data/lib/openc3/accessors/http_accessor.rb +145 -0
  13. data/lib/openc3/accessors/json_accessor.rb +19 -3
  14. data/lib/openc3/accessors/xml_accessor.rb +18 -1
  15. data/lib/openc3/accessors.rb +3 -1
  16. data/lib/openc3/config/config_parser.rb +7 -5
  17. data/lib/openc3/config/meta_config_parser.rb +1 -1
  18. data/lib/openc3/core_ext/string.rb +16 -1
  19. data/lib/openc3/interfaces/http_client_interface.rb +202 -0
  20. data/lib/openc3/interfaces/http_server_interface.rb +183 -0
  21. data/lib/openc3/interfaces/interface.rb +86 -16
  22. data/lib/openc3/interfaces/mqtt_interface.rb +6 -5
  23. data/lib/openc3/interfaces/protocols/burst_protocol.rb +11 -11
  24. data/lib/openc3/interfaces/protocols/cobs_protocol.rb +7 -7
  25. data/lib/openc3/interfaces/protocols/crc_protocol.rb +7 -7
  26. data/lib/openc3/interfaces/protocols/length_protocol.rb +6 -6
  27. data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +9 -5
  28. data/lib/openc3/interfaces/protocols/protocol.rb +8 -6
  29. data/lib/openc3/interfaces/protocols/slip_protocol.rb +8 -8
  30. data/lib/openc3/interfaces/protocols/template_protocol.rb +6 -7
  31. data/lib/openc3/interfaces/protocols/terminated_protocol.rb +4 -4
  32. data/lib/openc3/interfaces/simulated_target_interface.rb +2 -0
  33. data/lib/openc3/interfaces/stream_interface.rb +6 -4
  34. data/lib/openc3/interfaces/tcpip_server_interface.rb +2 -0
  35. data/lib/openc3/interfaces/udp_interface.rb +8 -5
  36. data/lib/openc3/interfaces.rb +2 -0
  37. data/lib/openc3/logs/buffered_packet_log_writer.rb +6 -7
  38. data/lib/openc3/logs/log_writer.rb +2 -10
  39. data/lib/openc3/logs/packet_log_constants.rb +13 -3
  40. data/lib/openc3/logs/packet_log_reader.rb +35 -98
  41. data/lib/openc3/logs/packet_log_writer.rb +24 -62
  42. data/lib/openc3/logs/text_log_writer.rb +32 -6
  43. data/lib/openc3/microservices/cleanup_microservice.rb +23 -16
  44. data/lib/openc3/microservices/decom_microservice.rb +8 -20
  45. data/lib/openc3/microservices/log_microservice.rb +3 -1
  46. data/lib/openc3/microservices/reaction_microservice.rb +22 -11
  47. data/lib/openc3/microservices/reducer_microservice.rb +174 -130
  48. data/lib/openc3/{models/notification_model.rb → microservices/scope_cleanup_microservice.rb} +20 -21
  49. data/lib/openc3/microservices/text_log_microservice.rb +2 -5
  50. data/lib/openc3/microservices/timeline_microservice.rb +0 -1
  51. data/lib/openc3/microservices/trigger_group_microservice.rb +0 -1
  52. data/lib/openc3/migrations/20230915000002_no_scope_log_messages.rb +44 -0
  53. data/lib/openc3/models/microservice_model.rb +1 -1
  54. data/lib/openc3/models/scope_model.rb +65 -34
  55. data/lib/openc3/models/target_model.rb +25 -5
  56. data/lib/openc3/models/tool_model.rb +14 -2
  57. data/lib/openc3/models/widget_model.rb +1 -1
  58. data/lib/openc3/packets/json_packet.rb +10 -2
  59. data/lib/openc3/packets/packet.rb +30 -9
  60. data/lib/openc3/packets/packet_config.rb +6 -2
  61. data/lib/openc3/packets/parsers/packet_item_parser.rb +11 -6
  62. data/lib/openc3/packets/structure.rb +19 -12
  63. data/lib/openc3/script/storage.rb +1 -1
  64. data/lib/openc3/script/web_socket_api.rb +17 -14
  65. data/lib/openc3/topics/telemetry_topic.rb +2 -1
  66. data/lib/openc3/utilities/bucket_utilities.rb +2 -0
  67. data/lib/openc3/utilities/cli_generator.rb +1 -1
  68. data/lib/openc3/utilities/logger.rb +62 -47
  69. data/lib/openc3/utilities/metric.rb +19 -1
  70. data/lib/openc3/utilities/sleeper.rb +3 -1
  71. data/lib/openc3/utilities/throttle.rb +76 -0
  72. data/lib/openc3/version.rb +6 -6
  73. data/templates/tool_angular/package.json +20 -20
  74. data/templates/tool_angular/yarn.lock +112 -106
  75. data/templates/tool_react/package.json +16 -18
  76. data/templates/tool_react/yarn.lock +977 -664
  77. data/templates/tool_svelte/.prettierrc.js +5 -0
  78. data/templates/tool_svelte/package.json +18 -18
  79. data/templates/tool_svelte/src/services/cable.js +1 -1
  80. data/templates/tool_svelte/src/services/openc3-api.js +173 -173
  81. data/templates/tool_svelte/yarn.lock +767 -665
  82. data/templates/tool_vue/package.json +10 -10
  83. data/templates/tool_vue/yarn.lock +225 -43
  84. data/templates/widget/package.json +10 -10
  85. data/templates/widget/yarn.lock +223 -46
  86. metadata +41 -4
  87. data/lib/openc3/topics/notifications_topic.rb +0 -31
@@ -23,6 +23,7 @@
23
23
  require 'openc3/api/api'
24
24
  require 'openc3/logs/stream_log_pair'
25
25
  require 'openc3/utilities/secrets'
26
+ require 'rufus-scheduler'
26
27
 
27
28
  module OpenC3
28
29
  # Define a class to allow interfaces and protocols to reject commands without
@@ -140,6 +141,9 @@ module OpenC3
140
141
  # @return [Secrets] Interface secrets manager class
141
142
  attr_accessor :secrets
142
143
 
144
+ # @return [Scheduler] Scheduler used for periodic commanding
145
+ attr_accessor :scheduler
146
+
143
147
  # Initialize default attribute values
144
148
  def initialize
145
149
  @name = self.class.to_s.split("::")[-1] # Remove namespacing if present
@@ -177,12 +181,38 @@ module OpenC3
177
181
  @config_params = []
178
182
  @interfaces = []
179
183
  @secrets = Secrets.getClient
184
+ @scheduler = nil
180
185
  end
181
186
 
182
187
  # Connects the interface to its target(s). Must be implemented by a
183
188
  # subclass.
184
189
  def connect
185
190
  (@read_protocols | @write_protocols).each { |protocol| protocol.connect_reset }
191
+
192
+ periodic_cmds = @options['PERIODIC_CMD']
193
+ if periodic_cmds
194
+ if not @scheduler
195
+ @scheduler = Rufus::Scheduler.new
196
+
197
+ periodic_cmds.each do |log_dont_log, period, cmd_string|
198
+ log_dont_log.upcase!
199
+ period = "#{period.to_f}s"
200
+ @scheduler.every period do
201
+ begin
202
+ if log_dont_log == 'DONT_LOG'
203
+ cmd(cmd_string, log_message: false)
204
+ else
205
+ cmd(cmd_string)
206
+ end
207
+ rescue Exception => err
208
+ Logger.error("Error sending periodic cmd(#{cmd_string}):\n#{err.formatted}")
209
+ end
210
+ end
211
+ end
212
+ else
213
+ @scheduler.resume
214
+ end
215
+ end
186
216
  end
187
217
 
188
218
  # Indicates if the interface is connected to its target(s) or not. Must be
@@ -194,6 +224,11 @@ module OpenC3
194
224
  # Disconnects the interface from its target(s). Must be implemented by a
195
225
  # subclass.
196
226
  def disconnect
227
+ periodic_cmds = @options['PERIODIC_CMD']
228
+ if periodic_cmds and @scheduler
229
+ @scheduler.pause
230
+ end
231
+
197
232
  (@read_protocols | @write_protocols).each { |protocol| protocol.disconnect_reset }
198
233
  end
199
234
 
@@ -201,7 +236,7 @@ module OpenC3
201
236
  raise "read_interface not defined by Interface"
202
237
  end
203
238
 
204
- def write_interface
239
+ def write_interface(data, extra = nil)
205
240
  raise "write_interface not defined by Interface"
206
241
  end
207
242
 
@@ -217,9 +252,10 @@ module OpenC3
217
252
  # Protocols may have cached data for a packet, so initially just inject a blank string
218
253
  # Otherwise we can hold off outputing other packets where all the data has already
219
254
  # been received
255
+ extra = nil
220
256
  if !first or @read_protocols.length <= 0
221
257
  # Read data for a packet
222
- data = read_interface()
258
+ data, extra = read_interface()
223
259
  unless data
224
260
  Logger.info("#{@name}: read_interface requested disconnect")
225
261
  return nil
@@ -230,7 +266,12 @@ module OpenC3
230
266
  end
231
267
 
232
268
  @read_protocols.each do |protocol|
233
- data = protocol.read_data(data)
269
+ # Extra check is for backwards compatibility
270
+ if extra
271
+ data, extra = protocol.read_data(data, extra)
272
+ else
273
+ data, extra = protocol.read_data(data)
274
+ end
234
275
  if data == :DISCONNECT
235
276
  Logger.info("#{@name}: Protocol #{protocol.class} read_data requested disconnect")
236
277
  return nil
@@ -239,7 +280,12 @@ module OpenC3
239
280
  end
240
281
  next if data == :STOP
241
282
 
242
- packet = convert_data_to_packet(data)
283
+ # Extra check is for backwards compatibility
284
+ if extra
285
+ packet = convert_data_to_packet(data, extra)
286
+ else
287
+ packet = convert_data_to_packet(data)
288
+ end
243
289
 
244
290
  # Potentially modify packet
245
291
  @read_protocols.each do |protocol|
@@ -283,11 +329,16 @@ module OpenC3
283
329
  return if packet == :STOP
284
330
  end
285
331
 
286
- data = convert_packet_to_data(packet)
332
+ data, extra = convert_packet_to_data(packet)
287
333
 
288
334
  # Potentially modify packet data
289
335
  @write_protocols.each do |protocol|
290
- data = protocol.write_data(data)
336
+ # Extra check is for backwards compatibility
337
+ if extra
338
+ data, extra = protocol.write_data(data, extra)
339
+ else
340
+ data, extra = protocol.write_data(data)
341
+ end
291
342
  if data == :DISCONNECT
292
343
  Logger.info("#{@name}: Protocol #{protocol.class} write_data requested disconnect")
293
344
  disconnect()
@@ -297,11 +348,20 @@ module OpenC3
297
348
  end
298
349
 
299
350
  # Actually write out data if not handled by protocol
300
- write_interface(data)
351
+ # Extra check is for backwards compatibility
352
+ if extra
353
+ write_interface(data, extra)
354
+ else
355
+ write_interface(data)
356
+ end
301
357
 
302
358
  # Potentially block and wait for response
303
359
  @write_protocols.each do |protocol|
304
- packet, data = protocol.post_write_interface(packet, data)
360
+ if extra
361
+ packet, data, extra = protocol.post_write_interface(packet, data, extra)
362
+ else
363
+ packet, data, extra = protocol.post_write_interface(packet, data)
364
+ end
305
365
  if packet == :DISCONNECT
306
366
  Logger.info("#{@name}: Protocol #{protocol.class} post_write_packet requested disconnect")
307
367
  disconnect()
@@ -317,12 +377,12 @@ module OpenC3
317
377
  # Writes preformatted data onto the interface. Malformed data may cause
318
378
  # problems.
319
379
  # @param data [String] The raw data to send out the interface
320
- def write_raw(data)
380
+ def write_raw(data, extra = nil)
321
381
  raise "Interface not connected for write_raw: #{@name}" unless connected?
322
382
  raise "Interface not write-rawable: #{@name}" unless write_raw_allowed?
323
383
 
324
384
  _write do
325
- write_interface(data)
385
+ write_interface(data, extra)
326
386
  end
327
387
  end
328
388
 
@@ -429,15 +489,25 @@ module OpenC3
429
489
  # @param option_name name of the option
430
490
  # @param option_values array of option values
431
491
  def set_option(option_name, option_values)
432
- @options[option_name.upcase] = option_values.clone
492
+ option_name_upcase = option_name.upcase
493
+
494
+ if option_name_upcase == 'PERIODIC_CMD'
495
+ # OPTION PERIODIC_CMD LOG/DONT_LOG 1.0 "INST COLLECT with TYPE NORMAL"
496
+ @options[option_name_upcase] ||= []
497
+ @options[option_name_upcase] << option_values.clone
498
+ else
499
+ @options[option_name_upcase] = option_values.clone
500
+ end
433
501
  end
434
502
 
435
503
  # Called to convert the read data into a OpenC3 Packet object
436
504
  #
437
505
  # @param data [String] Raw packet data
438
506
  # @return [Packet] OpenC3 Packet with buffer filled with data
439
- def convert_data_to_packet(data)
440
- Packet.new(nil, nil, :BIG_ENDIAN, nil, data)
507
+ def convert_data_to_packet(data, extra = nil)
508
+ packet = Packet.new(nil, nil, :BIG_ENDIAN, nil, data)
509
+ packet.extra = extra
510
+ return packet
441
511
  end
442
512
 
443
513
  # Called to convert a packet into the data to send
@@ -445,7 +515,7 @@ module OpenC3
445
515
  # @param packet [Packet] Packet to extract data from
446
516
  # @return data
447
517
  def convert_packet_to_data(packet)
448
- packet.buffer(true) # Copy buffer so logged command isn't modified
518
+ return packet.buffer(true), packet.extra # Copy buffer so logged command isn't modified
449
519
  end
450
520
 
451
521
  # Called to read data and manipulate it until enough data is
@@ -456,7 +526,7 @@ module OpenC3
456
526
  # method is called. Subclasses must implement this method.
457
527
  #
458
528
  # @return [String] Raw packet data
459
- def read_interface_base(data)
529
+ def read_interface_base(data, extra = nil)
460
530
  @read_raw_data_time = Time.now
461
531
  @read_raw_data = data.clone
462
532
  @bytes_read += data.length
@@ -469,7 +539,7 @@ module OpenC3
469
539
  #
470
540
  # @param data [String] Raw packet data
471
541
  # @return [String] The exact data written
472
- def write_interface_base(data)
542
+ def write_interface_base(data, extra = nil)
473
543
  @written_raw_data_time = Time.now
474
544
  @written_raw_data = data.clone
475
545
  @bytes_written += data.length
@@ -196,19 +196,20 @@ module OpenC3
196
196
  return nil
197
197
  end
198
198
  @read_topics << topic
199
- read_interface_base(data)
200
- return data
199
+ extra = nil
200
+ read_interface_base(data, extra)
201
+ return data, extra
201
202
  rescue IOError # Disconnected
202
203
  return nil
203
204
  end
204
205
 
205
206
  # Writes to the socket
206
207
  # @param data [String] Raw packet data
207
- def write_interface(data)
208
- write_interface_base(data)
208
+ def write_interface(data, extra = nil)
209
+ write_interface_base(data, extra)
209
210
  topic = @write_topics.shift
210
211
  @client.publish(topic, data)
211
- data
212
+ return data, extra
212
213
  end
213
214
 
214
215
  # Supported Options
@@ -61,15 +61,16 @@ module OpenC3
61
61
  # protocols giving them the same opportunity.
62
62
  #
63
63
  # @return [String|nil] Data for a packet consisting of the bytes read
64
- def read_data(data)
64
+ def read_data(data, extra = nil)
65
65
  @data << data
66
+ @extra = extra
66
67
 
67
68
  while true
68
69
  control = handle_sync_pattern()
69
70
  return control if control and data.length > 0 # Only return here if not blank string test
70
71
 
71
72
  # Reduce the data to a single packet
72
- packet_data = reduce_to_single_packet()
73
+ packet_data, extra = reduce_to_single_packet()
73
74
  if packet_data == :RESYNC
74
75
  @sync_state = :SEARCHING
75
76
  next if data.length > 0 # Only immediately resync if not blank string test
@@ -81,9 +82,9 @@ module OpenC3
81
82
  # On blank string test, return blank string (unless we had a packet or need disconnect)
82
83
  # The base class handles the special case of returning STOP if on the last protocol in the
83
84
  # chain
84
- return super(data)
85
+ return super(data, extra)
85
86
  else
86
- return packet_data # Return any control code if not on blank string test
87
+ return packet_data, extra # Return any control code if not on blank string test
87
88
  end
88
89
  end
89
90
 
@@ -91,7 +92,7 @@ module OpenC3
91
92
 
92
93
  # Discard leading bytes if necessary
93
94
  packet_data.replace(packet_data[@discard_leading_bytes..-1]) if @discard_leading_bytes > 0
94
- return packet_data
95
+ return packet_data, extra
95
96
  end
96
97
  end
97
98
 
@@ -115,7 +116,7 @@ module OpenC3
115
116
  #
116
117
  # @param data [String] Raw packet data
117
118
  # @return [String] Potentially modified packet data
118
- def write_data(data)
119
+ def write_data(data, extra = nil)
119
120
  # If we're filling the sync pattern and discarding the leading bytes
120
121
  # during a read then we need to put them back during a write.
121
122
  # If we're discarding the bytes then by definition they can't be part
@@ -127,7 +128,7 @@ module OpenC3
127
128
  data, :BIG_ENDIAN, :ERROR)
128
129
  end
129
130
  end
130
- super(data)
131
+ return super(data, extra)
131
132
  end
132
133
 
133
134
  # @return [Boolean] control code (nil, :STOP)
@@ -156,8 +157,7 @@ module OpenC3
156
157
 
157
158
  if found
158
159
  if sync_index != 0
159
- discard_length = @data[0..(sync_index - 1)].length
160
- log_discard(discard_length, true)
160
+ log_discard(sync_index, true)
161
161
  # Delete Data Before Sync Pattern
162
162
  @data.replace(@data[sync_index..-1])
163
163
  end
@@ -165,7 +165,7 @@ module OpenC3
165
165
  return nil
166
166
 
167
167
  else # not found
168
- log_discard(@data[0..sync_index].length, false)
168
+ log_discard(sync_index + 1, false)
169
169
  # Delete Data Before and including first character of suspected sync Pattern
170
170
  @data.replace(@data[(sync_index + 1)..-1])
171
171
  next
@@ -203,7 +203,7 @@ module OpenC3
203
203
  # Reduce to packet data and clear data for next packet
204
204
  packet_data = @data.clone
205
205
  @data.replace('')
206
- packet_data
206
+ return packet_data, @extra
207
207
  end
208
208
  end
209
209
  end
@@ -53,9 +53,9 @@ module OpenC3
53
53
  )
54
54
  end
55
55
 
56
- def read_data(data)
57
- data = super(data)
58
- return data if data.length <= 0 or Symbol === data
56
+ def read_data(data, extra = nil)
57
+ data, extra = super(data, extra)
58
+ return data, extra if data.length <= 0 or Symbol === data
59
59
 
60
60
  result_data = ''
61
61
  while data.length > 1
@@ -75,10 +75,10 @@ module OpenC3
75
75
  end
76
76
  end
77
77
 
78
- return result_data
78
+ return result_data, extra
79
79
  end
80
80
 
81
- def write_data(data)
81
+ def write_data(data, extra = nil)
82
82
  # Intentionally not calling super()
83
83
 
84
84
  need_insert = false
@@ -90,7 +90,7 @@ module OpenC3
90
90
  result_data << data[0..253]
91
91
  data = data[254..-1]
92
92
  need_insert = false
93
- else # index <= 254 or (index.nil? and data.length < 254)
93
+ else # index <= 253 or (index.nil? and data.length < 254)
94
94
  if index
95
95
  result_data << [index + 1].pack('C')
96
96
  if index >= 1
@@ -113,7 +113,7 @@ module OpenC3
113
113
  # Terminate message with 0x00
114
114
  result_data << "\x00"
115
115
 
116
- return result_data
116
+ return result_data, extra
117
117
  end
118
118
  end
119
119
 
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/config/config_parser'
@@ -147,8 +147,8 @@ module OpenC3
147
147
  end
148
148
  end
149
149
 
150
- def read_data(data)
151
- return super(data) if data.length <= 0
150
+ def read_data(data, extra = nil)
151
+ return super(data, extra) if data.length <= 0
152
152
 
153
153
  crc = BinaryAccessor.read(@bit_offset, @bit_size, :UINT, data, @endianness)
154
154
  calculated_crc = @crc.calc(data[0...(@bit_offset / 8)])
@@ -163,9 +163,9 @@ module OpenC3
163
163
  new_data = new_data[0...(@bit_offset / 8)]
164
164
  end_range = (@bit_offset + @bit_size) / 8
165
165
  new_data << data[end_range..-1] if end_range != 0
166
- return new_data
166
+ return new_data, extra
167
167
  end
168
- return data
168
+ return data, extra
169
169
  end
170
170
 
171
171
  def write_packet(packet)
@@ -177,7 +177,7 @@ module OpenC3
177
177
  packet
178
178
  end
179
179
 
180
- def write_data(data)
180
+ def write_data(data, extra = nil)
181
181
  unless @write_item_name
182
182
  if @bit_size == 64
183
183
  crc = @crc.calc(data)
@@ -190,7 +190,7 @@ module OpenC3
190
190
  BinaryAccessor.write(crc, -@bit_size, @bit_size, :UINT, data, @endianness, :ERROR)
191
191
  end
192
192
  end
193
- data
193
+ return data, extra
194
194
  end
195
195
  end
196
196
  end
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/packets/binary_accessor'
@@ -96,7 +96,7 @@ module OpenC3
96
96
  # If the start of the length field is past what we discard, then the
97
97
  # length field is inside the packet
98
98
  if @length_bit_offset >= (@discard_leading_bytes * 8)
99
- length = calculate_length(packet.buffer.length + @discard_leading_bytes)
99
+ length = calculate_length(packet.buffer(false).length + @discard_leading_bytes)
100
100
  # Subtract off the discarded bytes since they haven't been added yet
101
101
  # Adding bytes happens in the write_data method
102
102
  offset = @length_bit_offset - (@discard_leading_bytes * 8)
@@ -112,8 +112,8 @@ module OpenC3
112
112
  #
113
113
  # @param data [String] Raw packet data
114
114
  # @return [String] Potentially modified packet data
115
- def write_data(data)
116
- data = super(data)
115
+ def write_data(data, extra = nil)
116
+ data, extra = super(data, extra)
117
117
  if @fill_fields
118
118
  # If the start of the length field is before what we discard, then the
119
119
  # length field is outside the packet
@@ -122,7 +122,7 @@ module OpenC3
122
122
  data, @length_endianness, :ERROR)
123
123
  end
124
124
  end
125
- return data
125
+ return data, extra
126
126
  end
127
127
 
128
128
  protected
@@ -162,7 +162,7 @@ module OpenC3
162
162
  packet_data = @data[0..(packet_length - 1)]
163
163
  @data.replace(@data[packet_length..-1])
164
164
 
165
- return packet_data
165
+ return packet_data, @extra
166
166
  end
167
167
  end
168
168
  end
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/interfaces/protocols/burst_protocol'
@@ -49,7 +49,11 @@ module OpenC3
49
49
  packet.packet_name = @read_packet_name
50
50
  if @mode == 4 # COSMOS4.3+ Protocol
51
51
  packet.stored = @read_stored
52
- packet.extra = @read_extra
52
+ if packet.extra and @read_extra
53
+ packet.extra.merge(@read_extra)
54
+ else
55
+ packet.extra = @read_extra
56
+ end
53
57
  end
54
58
  return packet
55
59
  end
@@ -75,7 +79,7 @@ module OpenC3
75
79
  return packet
76
80
  end
77
81
 
78
- def write_data(data)
82
+ def write_data(data, extra = nil)
79
83
  data_length = [data.length].pack('N') # UINT32
80
84
  data_to_send = ''
81
85
  data_to_send << @sync_pattern if @sync_pattern
@@ -94,7 +98,7 @@ module OpenC3
94
98
  data_to_send << @write_packet_name
95
99
  data_to_send << data_length
96
100
  data_to_send << data
97
- return data_to_send
101
+ return data_to_send, extra
98
102
  end
99
103
 
100
104
  protected
@@ -200,7 +204,7 @@ module OpenC3
200
204
  return :STOP if packet_data == :STOP
201
205
 
202
206
  @reduction_state = :START
203
- return packet_data
207
+ return packet_data, @extra
204
208
  end
205
209
 
206
210
  raise "Error should never reach end of method #{@reduction_state}"
@@ -29,6 +29,7 @@ module OpenC3
29
29
  class Protocol
30
30
  attr_accessor :interface
31
31
  attr_accessor :allow_empty_data
32
+ attr_accessor :extra
32
33
 
33
34
  # @param allow_empty_data [true/false/nil] Whether or not this protocol will allow an empty string
34
35
  # to be passed down to later Protocols (instead of returning :STOP). Can be true, false, or nil, where
@@ -40,6 +41,7 @@ module OpenC3
40
41
  end
41
42
 
42
43
  def reset
44
+ @extra = nil
43
45
  end
44
46
 
45
47
  def connect_reset
@@ -51,7 +53,7 @@ module OpenC3
51
53
  end
52
54
 
53
55
  # Ensure we have some data in case this is the only protocol
54
- def read_data(data)
56
+ def read_data(data, extra = nil)
55
57
  if data.length <= 0
56
58
  if @allow_empty_data.nil?
57
59
  if @interface and @interface.read_protocols[-1] == self
@@ -63,7 +65,7 @@ module OpenC3
63
65
  return :STOP
64
66
  end
65
67
  end
66
- data
68
+ return data, extra
67
69
  end
68
70
 
69
71
  def read_packet(packet)
@@ -74,12 +76,12 @@ module OpenC3
74
76
  return packet
75
77
  end
76
78
 
77
- def write_data(data)
78
- return data
79
+ def write_data(data, extra = nil)
80
+ return data, extra
79
81
  end
80
82
 
81
- def post_write_interface(packet, data)
82
- return packet, data
83
+ def post_write_interface(packet, data, extra = nil)
84
+ return packet, data, extra
83
85
  end
84
86
 
85
87
  def protocol_cmd(cmd_name, *cmd_args)
@@ -55,7 +55,7 @@ module OpenC3
55
55
  allow_empty_data = nil)
56
56
 
57
57
  @start_char = ConfigParser.handle_nil(start_char)
58
- @start_char = [Integer(end_char)].pack('C') if @start_char
58
+ @start_char = [Integer(start_char)].pack('C') if @start_char
59
59
  @end_char = [Integer(end_char)].pack('C')
60
60
  @esc_char = [Integer(esc_char)].pack('C')
61
61
  @esc_end_char = [Integer(esc_end_char)].pack('C')
@@ -89,9 +89,9 @@ module OpenC3
89
89
  )
90
90
  end
91
91
 
92
- def read_data(data)
93
- data = super(data)
94
- return data if data.length <= 0 or Symbol === data
92
+ def read_data(data, extra = nil)
93
+ data, extra = super(data, extra)
94
+ return data, extra if data.length <= 0 or Symbol === data
95
95
 
96
96
  if @read_strip_characters
97
97
  if @start_char
@@ -104,10 +104,10 @@ module OpenC3
104
104
  data = data.gsub(@replace_end, @end_char).gsub(@replace_esc, @esc_char)
105
105
  end
106
106
 
107
- return data
107
+ return data, extra
108
108
  end
109
109
 
110
- def write_data(data)
110
+ def write_data(data, extra = nil)
111
111
  # Intentionally not calling super()
112
112
 
113
113
  if @write_enable_escaping
@@ -120,7 +120,7 @@ module OpenC3
120
120
 
121
121
  data << @end_char
122
122
 
123
- return data
123
+ return data, extra
124
124
  end
125
125
 
126
126
  def reduce_to_single_packet
@@ -140,7 +140,7 @@ module OpenC3
140
140
  packet_data = @data[0..(@read_termination_characters.length - 1)]
141
141
  end
142
142
  @data.replace(@data[(index + @read_termination_characters.length)..-1])
143
- return packet_data
143
+ return packet_data, @extra
144
144
  else
145
145
  return :STOP
146
146
  end
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/config/config_parser'
@@ -108,8 +108,8 @@ module OpenC3
108
108
  @write_block_queue << nil # Unblock the write block queue
109
109
  end
110
110
 
111
- def read_data(data)
112
- return super(data) if data.length <= 0
111
+ def read_data(data, extra = nil)
112
+ return super(data, extra) if data.length <= 0
113
113
 
114
114
  # Drop all data until the initial_read_delay is complete.
115
115
  # This gets rid of unused welcome messages,
@@ -119,7 +119,7 @@ module OpenC3
119
119
 
120
120
  @initial_read_delay_needed = false
121
121
  end
122
- super(data)
122
+ return super(data, extra)
123
123
  end
124
124
 
125
125
  def read_packet(packet)
@@ -165,7 +165,6 @@ module OpenC3
165
165
  result_packet.write(response_item_names[i], value)
166
166
  rescue => error
167
167
  handle_error("#{@interface ? @interface.name : ""}: Could not write value #{value} due to #{error.message}")
168
- break
169
168
  end
170
169
  end
171
170
 
@@ -230,7 +229,7 @@ module OpenC3
230
229
  return raw_packet
231
230
  end
232
231
 
233
- def post_write_interface(packet, data)
232
+ def post_write_interface(packet, data, extra = nil)
234
233
  if @response_template && @response_packet
235
234
  if @response_timeout
236
235
  response_timeout_time = Time.now + @response_timeout
@@ -253,7 +252,7 @@ module OpenC3
253
252
  @response_target_name = nil
254
253
  @response_packets.clear
255
254
  end
256
- return super(packet, data)
255
+ return super(packet, data, extra)
257
256
  end
258
257
 
259
258
  def handle_error(msg)