openc3 6.2.1 → 6.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -3
  3. data/bin/openc3cli +13 -14
  4. data/data/config/interface_modifiers.yaml +1 -1
  5. data/data/config/microservice.yaml +1 -1
  6. data/data/config/plugins.yaml +1 -1
  7. data/data/config/tool.yaml +1 -1
  8. data/data/config/widgets.yaml +3 -0
  9. data/ext/openc3/ext/burst_protocol/burst_protocol.c +5 -1
  10. data/lib/openc3/api/api.rb +7 -1
  11. data/lib/openc3/api/cmd_api.rb +5 -8
  12. data/lib/openc3/api/interface_api.rb +8 -4
  13. data/lib/openc3/api/tlm_api.rb +23 -8
  14. data/lib/openc3/interfaces/file_interface.rb +36 -7
  15. data/lib/openc3/interfaces/protocols/burst_protocol.rb +3 -3
  16. data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +20 -26
  17. data/lib/openc3/interfaces.rb +4 -3
  18. data/lib/openc3/io/json_api_object.rb +1 -1
  19. data/lib/openc3/io/json_drb_object.rb +1 -1
  20. data/lib/openc3/logs/log_writer.rb +11 -8
  21. data/lib/openc3/logs/packet_log_reader.rb +2 -2
  22. data/lib/openc3/logs/packet_log_writer.rb +1 -1
  23. data/lib/openc3/microservices/interface_decom_common.rb +4 -1
  24. data/lib/openc3/microservices/interface_microservice.rb +69 -6
  25. data/lib/openc3/microservices/microservice.rb +3 -1
  26. data/lib/openc3/microservices/multi_microservice.rb +1 -1
  27. data/lib/openc3/migrations/20250402000000_periodic_only_default.rb +24 -0
  28. data/lib/openc3/models/model.rb +6 -2
  29. data/lib/openc3/models/offline_access_model.rb +7 -6
  30. data/lib/openc3/models/scope_model.rb +5 -2
  31. data/lib/openc3/models/script_status_model.rb +242 -0
  32. data/lib/openc3/models/target_model.rb +150 -15
  33. data/lib/openc3/packets/commands.rb +10 -3
  34. data/lib/openc3/script/api_shared.rb +4 -0
  35. data/lib/openc3/script/commands.rb +1 -1
  36. data/lib/openc3/script/script.rb +14 -0
  37. data/lib/openc3/script/script_runner.rb +22 -7
  38. data/lib/openc3/utilities/authentication.rb +6 -6
  39. data/lib/openc3/utilities/cosmos_rails_formatter.rb +1 -1
  40. data/lib/openc3/utilities/local_mode.rb +5 -2
  41. data/lib/openc3/utilities/message_log.rb +2 -0
  42. data/lib/openc3/utilities/metric.rb +1 -1
  43. data/lib/openc3/utilities/ruby_lex_utils.rb +114 -279
  44. data/lib/openc3/utilities/target_file.rb +6 -2
  45. data/lib/openc3/version.rb +6 -6
  46. data/templates/tool_angular/package.json +2 -2
  47. data/templates/tool_react/package.json +1 -1
  48. data/templates/tool_svelte/package.json +1 -1
  49. data/templates/tool_vue/eslint.config.mjs +17 -41
  50. data/templates/tool_vue/package.json +3 -3
  51. data/templates/widget/package.json +2 -2
  52. metadata +21 -23
  53. data/ext/mkrf_conf.rb +0 -52
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d2295b17b1ccf8843872f9bc809c460eee9a5e1c8ddf193f7169afaed5e4e561
4
- data.tar.gz: 1f2fbbdeb1d81708df2ba9046ac1958ba3d254b7bb7560b5142dd2404e954e05
3
+ metadata.gz: c408df49ec8cf1fbcf88e8c05207ac1c65274d56dbee94986c4f56308bc52b23
4
+ data.tar.gz: 8e8897d618e69898470fcd8a201ba968688fbe598c4ecb46d1a375da14282490
5
5
  SHA512:
6
- metadata.gz: 8004c092a51faa75b6a3336affc5939fe0f45da6fb4827ef3fb729249f96cb95a8bcb54cfff606b6952dd25d2404a6f97758e3429f279b3536324408c13c06f5
7
- data.tar.gz: cb6d29d2bfde3f76d4963d0b86d96aaada4d0814f71a968e05e2e59aa469e04c6ba8ab6544ad03c7eab2972267f689af17a8f03a84d889d6f38dec234d8fb437
6
+ metadata.gz: c37180a0814a4ceb79b6503d52a83e10cba964351f07841db692e44bdb5a619f95b7a955283982f73218dc5f6670bef113654b917fc92ed99a9c71ff8e000e36
7
+ data.tar.gz: fa11395f5c24e207e6e6eb6f74b2b8f53c882222572f39cf7d6a6e95668dd99c5ad24015e832df937fb5f12800c92e3c7f55319716a46fc6a07cdbb99abc2e52
data/Gemfile CHANGED
@@ -2,12 +2,11 @@
2
2
 
3
3
  source ENV['RUBYGEMS_URL'] || "https://rubygems.org"
4
4
 
5
- gem 'ruby-termios', '>= 0.9' if RbConfig::CONFIG['target_os'] !~ /mswin|mingw|cygwin/i and RUBY_ENGINE == 'ruby'
6
-
7
5
  gemspec :name => 'openc3'
8
6
 
9
7
  # Include the rails gems for the convenience of custom microservice plugins
10
8
  gem 'bootsnap', '>= 1.9.3', require: false
11
9
  gem 'rack-cors', '~> 2.0'
12
- gem 'rails', '~> 7.1.0'
10
+ gem 'rails', '~> 7.2.0'
13
11
  gem 'tzinfo-data'
12
+ gem 'ruby-termios', '>= 1.0'
data/bin/openc3cli CHANGED
@@ -50,7 +50,7 @@ $redis_url = "redis://#{ENV['OPENC3_REDIS_HOSTNAME']}:#{ENV['OPENC3_REDIS_PORT']
50
50
 
51
51
  ERROR_CODE = 1
52
52
 
53
- CLI_SCRIPT_ACTIONS = %w(help list run spawn)
53
+ CLI_SCRIPT_ACTIONS = %w(help list run spawn init)
54
54
  $script_interrupt_text = ''
55
55
  trap('INT') do
56
56
  abort("Interrupted at console; exiting.#{$script_interrupt_text}")
@@ -66,6 +66,7 @@ def print_usage
66
66
  puts " cli script spawn NAME SCOPE variable1=value1 variable2=value2 # Starts named script remotely"
67
67
  puts " cli script run NAME SCOPE variable1=value1 variable2=value2 # Starts named script, monitoring status on console,\
68
68
  by default until error or exit"
69
+ puts " cli script init # initialize running scripts (Enterprise Only)"
69
70
  puts " PARAMETERS name-value pairs to form the script's runtime environment"
70
71
  puts " OPTIONS: --wait 0 seconds to monitor status before detaching from the running script; ie --wait 100"
71
72
  puts " --disconnect run the script in disconnect mode"
@@ -79,7 +80,7 @@ def print_usage
79
80
  puts " cli bridgesetup CONFIG_FILENAME # Create a default config file"
80
81
  puts " cli pkginstall PKGFILENAME SCOPE # Install loaded package (Ruby gem or python package)"
81
82
  puts " cli pkguninstall PKGFILENAME SCOPE # Uninstall loaded package (Ruby gem or python package)"
82
- puts " cli rubysloc # Counts Ruby SLOC recursively. Run with --help for more info."
83
+ puts " cli rubysloc # DEPRECATED: Please use scc (https://github.com/boyter/scc)"
83
84
  puts " cli xtce_converter # Convert to and from the XTCE format. Run with --help for more info."
84
85
  puts " cli cstol_converter # Converts CSTOL files (.prc) to COSMOS. Run with --help for more info."
85
86
  puts ""
@@ -591,28 +592,18 @@ def cli_script_monitor(script_id)
591
592
  while (resp = api.read) do
592
593
  # see ScriptRunner.vue for types and states
593
594
  case resp['type']
594
- when 'error', 'fatal'
595
- $script_interrupt_text = ''
596
- puts 'script failed'
597
- break
598
595
  when 'file'
599
596
  puts "Filename #{resp['filename']} scope #{resp['scope']}"
600
597
  when 'line'
601
598
  fn = resp['filename'].nil? ? '<no file>' : resp['filename']
602
599
  puts "At [#{fn}:#{resp['line_no']}] state [#{resp['state']}]"
603
- if resp['state'] == 'error'
600
+ if resp['state'] == 'error' or resp['state'] == 'crashed'
604
601
  $script_interrupt_text = ''
605
602
  puts 'script failed'
606
603
  break
607
604
  end
608
605
  when 'output'
609
606
  puts resp['line']
610
- when 'paused'
611
- if resp['state'] == 'fatal'
612
- $script_interrupt_text = ''
613
- puts 'script failed'
614
- break
615
- end
616
607
  when 'complete'
617
608
  $script_interrupt_text = ''
618
609
  puts 'script complete'
@@ -699,6 +690,12 @@ def cli_script_spawn(disconnect=false, environment={}, args=[])
699
690
  return ret_code
700
691
  end
701
692
 
693
+ def cli_script_init
694
+ require 'openc3/script'
695
+ initialize_offline_access()
696
+ return 0
697
+ end
698
+
702
699
  ## cli_script(args) turns an ARGV of [spawn|run] <--wait 123...> <--disconnect> SCRIPT <scope> <ENV_A=1 ENV_B=2 ...>
703
700
  # into function calls and tidied parameters to remote-control a script via RunningScriptWebSocketApi
704
701
  def cli_script(args=[])
@@ -739,6 +736,8 @@ def cli_script(args=[])
739
736
  ret_code = cli_script_spawn(discon, environ, args)
740
737
  when 'run'
741
738
  ret_code = cli_script_run(discon, environ, args)
739
+ when 'init'
740
+ ret_code = cli_script_init()
742
741
  else
743
742
  abort 'openc3cli internal error: parsing arguments'
744
743
  end
@@ -756,7 +755,7 @@ if not ARGV[0].nil? # argument(s) given
756
755
 
757
756
  when 'script'
758
757
  case ARGV[1]
759
- when 'list', 'run', 'spawn'
758
+ when 'list', 'run', 'spawn', 'init'
760
759
  cli_script(ARGV[1..-1])
761
760
  else
762
761
  # invalid actions, misplaced and malformed leading options and 'help' come here
@@ -240,7 +240,7 @@ CMD:
240
240
  python_example: CMD python interface_microservice.py DEFAULT__INTERFACE__INT1
241
241
  CONTAINER:
242
242
  summary: Docker Container
243
- description: Container to execute and run the microservice in. Only used in COSMOS Enterprise Edition.
243
+ description: Container to execute and run the microservice in. Only used in COSMOS Enterprise.
244
244
  since: 5.7.0
245
245
  parameters:
246
246
  - name: Args
@@ -107,7 +107,7 @@ MICROSERVICE:
107
107
  values: .+
108
108
  CONTAINER:
109
109
  summary: Docker Container
110
- description: Container to execute and run the microservice in. Only used in COSMOS Enterprise Edition.
110
+ description: Container to execute and run the microservice in. Only used in COSMOS Enterprise.
111
111
  parameters:
112
112
  - name: Args
113
113
  required: false
@@ -16,7 +16,7 @@ VARIABLE:
16
16
  NEEDS_DEPENDENCIES:
17
17
  summary: Indicates the plugin needs dependencies and sets the GEM_HOME environment variable
18
18
  description: If the plugin has a top level lib folder or lists runtime dependencies in the gemspec,
19
- NEEDS_DEPENDENCIES is effectively already set. Note that in Enterprise Edition, having
19
+ NEEDS_DEPENDENCIES is effectively already set. Note that in Enterprise, having
20
20
  NEEDS_DEPENDENCIES adds the NFS volume mount to the Kubernetes pod.
21
21
  since: 5.5.0
22
22
  INTERFACE:
@@ -66,7 +66,7 @@ TOOL:
66
66
  description:
67
67
  Position of the tool starting at 2 (1 is reserved for Admin Console).
68
68
  Tools without a position are appended to the end as they are installed.
69
- All COSMOS open source tools have consecutive integer values for position.
69
+ All COSMOS Core tools have consecutive integer values for position.
70
70
  since: 5.0.8
71
71
  parameters:
72
72
  - name: Position
@@ -34,6 +34,7 @@ Layout Widgets:
34
34
  values: .*
35
35
  example: |
36
36
  VERTICALBOX Info
37
+ SUBSETTING 1 RAW border "1px dashed green"
37
38
  LABEL "TEST"
38
39
  LABEL "SCREEN"
39
40
  END
@@ -64,6 +65,8 @@ Layout Widgets:
64
65
  values: .*
65
66
  example: |
66
67
  HORIZONTALBOX Info 10
68
+ SUBSETTING 0 RAW text-align CENTER
69
+ SUBSETTING 1 RAW border "1px solid blue"
67
70
  LABEL "TEST"
68
71
  LABEL "SCREEN"
69
72
  END
@@ -81,7 +81,11 @@ static VALUE burst_protocol_read_data(int argc, VALUE *argv, VALUE self)
81
81
  };
82
82
 
83
83
  rb_str_concat(rb_ivar_get(self, id_ivar_data), data);
84
- rb_ivar_set(self, id_ivar_extra, extra);
84
+
85
+ /* Maintain extra from last read read_data */
86
+ if (!((RSTRING_LEN(data) == 0) && (!(RTEST(extra))))) {
87
+ rb_ivar_set(self, id_ivar_extra, extra);
88
+ }
85
89
 
86
90
  while (1)
87
91
  {
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2023, OpenC3, Inc.
17
+ # All changes Copyright 2025, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -35,6 +35,12 @@ require 'openc3/api/target_api'
35
35
  require 'openc3/api/tlm_api'
36
36
  require 'openc3/utilities/authorization'
37
37
  require 'openc3/topics/topic'
38
+ begin
39
+ require 'openc3-enterprise/api/cmd_authority_api'
40
+ rescue LoadError
41
+ # LoadError expected for Open Source Edition
42
+ end
43
+
38
44
 
39
45
  module OpenC3
40
46
  module Api
@@ -19,6 +19,9 @@
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
+ #
23
+ # A portion of this file was funded by Blue Origin Enterprises, L.P.
24
+ # See https://github.com/OpenC3/cosmos/pull/1963
22
25
 
23
26
  require 'openc3/api/interface_api'
24
27
  require 'openc3/models/target_model'
@@ -387,7 +390,7 @@ module OpenC3
387
390
  target_name, command_name = _extract_target_command_names('get_cmd_cnt', *args)
388
391
  authorize(permission: 'system', target_name: target_name, packet_name: command_name, manual: manual, scope: scope, token: token)
389
392
  TargetModel.packet(target_name, command_name, type: :CMD, scope: scope)
390
- Topic.get_cnt("#{scope}__COMMAND__{#{target_name}}__#{command_name}")
393
+ return TargetModel.get_command_count(target_name, command_name, scope: scope)
391
394
  end
392
395
 
393
396
  # Get the transmit counts for command packets
@@ -399,13 +402,7 @@ module OpenC3
399
402
  unless target_commands.is_a?(Array) and target_commands[0].is_a?(Array)
400
403
  raise "get_cmd_cnts takes an array of arrays containing target, packet_name, e.g. [['INST', 'COLLECT'], ['INST', 'ABORT']]"
401
404
  end
402
- counts = []
403
- target_commands.each do |target_name, command_name|
404
- target_name = target_name.upcase
405
- command_name = command_name.upcase
406
- counts << Topic.get_cnt("#{scope}__COMMAND__{#{target_name}}__#{command_name}")
407
- end
408
- counts
405
+ return TargetModel.get_command_counts(target_commands, scope: scope)
409
406
  end
410
407
 
411
408
  ###########################################################################
@@ -111,15 +111,19 @@ module OpenC3
111
111
  # Get information about all interfaces
112
112
  #
113
113
  # @return [Array<Array<String, Numeric, Numeric, Numeric, Numeric, Numeric,
114
- # Numeric, Numeric>>] Array of Arrays containing \[name, state, num clients,
114
+ # Numeric, Numeric, Boolean>>] Array of Arrays containing \[name, state, num clients,
115
115
  # TX queue size, RX queue size, TX bytes, RX bytes, Command count,
116
- # Telemetry count] for all interfaces
116
+ # Telemetry count, disable_disconnect] for all interfaces
117
117
  def get_all_interface_info(manual: false, scope: $openc3_scope, token: $openc3_token)
118
118
  authorize(permission: 'system', manual: manual, scope: scope, token: token)
119
119
  info = []
120
- InterfaceStatusModel.all(scope: scope).each do |_int_name, int|
120
+ InterfaceStatusModel.all(scope: scope).each do |int_name, int|
121
+ # Get the interface configuration to access disable_disconnect
122
+ interface_model = InterfaceModel.get(name: int_name, scope: scope)
123
+ disable_disconnect = interface_model && interface_model['disable_disconnect'] ? true : false
124
+
121
125
  info << [int['name'], int['state'], int['clients'], int['txsize'], int['rxsize'],
122
- int['txbytes'], int['rxbytes'], int['txcnt'], int['rxcnt']]
126
+ int['txbytes'], int['rxbytes'], int['txcnt'], int['rxcnt'], disable_disconnect]
123
127
  end
124
128
  info.sort! { |a, b| a[0] <=> b[0] }
125
129
  info
@@ -19,6 +19,12 @@
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
+ #
23
+ # A portion of this file was funded by Blue Origin Enterprises, L.P.
24
+ # See https://github.com/OpenC3/cosmos/pull/1963
25
+
26
+ # A portion of this file was funded by Blue Origin Enterprises, L.P.
27
+ # See https://github.com/OpenC3/cosmos/pull/1957
22
28
 
23
29
  require 'openc3/models/target_model'
24
30
  require 'openc3/models/cvt_model'
@@ -48,6 +54,7 @@ module OpenC3
48
54
  'get_all_telemetry', # DEPRECATED
49
55
  'get_all_tlm_names',
50
56
  'get_all_telemetry_names', # DEPRECATED
57
+ 'get_all_tlm_item_names',
51
58
  'get_tlm',
52
59
  'get_telemetry', # DEPRECATED
53
60
  'get_item',
@@ -314,6 +321,20 @@ module OpenC3
314
321
  end
315
322
  alias get_all_telemetry_names get_all_tlm_names
316
323
 
324
+ # Returns an array of all the item names for every packet in a target
325
+ #
326
+ # @param target_name [String] Name of the taret
327
+ # @return [Array<String>] Array of all telemetry item names
328
+ def get_all_tlm_item_names(target_name, manual: false, scope: $openc3_scope, token: $openc3_token)
329
+ authorize(permission: 'tlm', target_name: target_name, manual: manual, scope: scope, token: token)
330
+ begin
331
+ items = TargetModel.all_item_names(target_name, scope: scope)
332
+ rescue RuntimeError
333
+ items = []
334
+ end
335
+ return items
336
+ end
337
+
317
338
  # Returns a telemetry packet hash
318
339
  #
319
340
  # @since 5.0.0
@@ -400,7 +421,7 @@ module OpenC3
400
421
  target_name, packet_name = _extract_target_packet_names('get_tlm_cnt', *args)
401
422
  authorize(permission: 'system', target_name: target_name, packet_name: packet_name, manual: manual, scope: scope, token: token)
402
423
  TargetModel.packet(target_name, packet_name, scope: scope)
403
- Topic.get_cnt("#{scope}__TELEMETRY__{#{target_name}}__#{packet_name}")
424
+ return TargetModel.get_telemetry_count(target_name, packet_name, scope: scope)
404
425
  end
405
426
 
406
427
  # Get the transmit counts for telemetry packets
@@ -409,13 +430,7 @@ module OpenC3
409
430
  # @return [Array<Numeric>] Receive count for the telemetry packets
410
431
  def get_tlm_cnts(target_packets, manual: false, scope: $openc3_scope, token: $openc3_token)
411
432
  authorize(permission: 'system', manual: manual, scope: scope, token: token)
412
- counts = []
413
- target_packets.each do |target_name, packet_name|
414
- target_name = target_name.upcase
415
- packet_name = packet_name.upcase
416
- counts << Topic.get_cnt("#{scope}__TELEMETRY__{#{target_name}}__#{packet_name}")
417
- end
418
- counts
433
+ return TargetModel.get_telemetry_counts(target_packets, scope: scope)
419
434
  end
420
435
 
421
436
  # Get the list of derived telemetry items for a packet
@@ -18,12 +18,16 @@
18
18
 
19
19
  require 'openc3/interfaces/interface'
20
20
  require 'openc3/config/config_parser'
21
+ require 'openc3/utilities/logger'
21
22
  require 'thread'
22
23
  require 'listen'
23
24
  require 'fileutils'
25
+ require 'zlib'
24
26
 
25
27
  module OpenC3
26
28
  class FileInterface < Interface
29
+ attr_reader :filename
30
+
27
31
  # @param command_write_folder [String] Folder to write command files to - Set to nil to disallow writes
28
32
  # @param telemetry_read_folder [String] Folder to read telemetry files from - Set to nil to disallow reads
29
33
  # @param telemetry_archive_folder [String] Folder to move read telemetry files to - Set to DELETE to delete files
@@ -62,6 +66,7 @@ module OpenC3
62
66
  @write_raw_allowed = false unless @command_write_folder
63
67
 
64
68
  @file = nil
69
+ @filename = ''
65
70
  @listener = nil
66
71
  @connected = false
67
72
  @extension = ".bin"
@@ -69,6 +74,9 @@ module OpenC3
69
74
  @queue = Queue.new
70
75
  @polling = false
71
76
  @recursive = false
77
+ @throttle = nil
78
+ @discard_file_header_bytes = nil
79
+ @sleeper = nil
72
80
  end
73
81
 
74
82
  def connect
@@ -90,6 +98,7 @@ module OpenC3
90
98
  def disconnect
91
99
  @file.close if @file and not @file.closed?
92
100
  @file = nil
101
+ @sleeper.cancel if @sleeper
93
102
  @listener.stop if @listener
94
103
  @listener = nil
95
104
  @queue << nil
@@ -102,6 +111,10 @@ module OpenC3
102
111
  if @file
103
112
  # Read more data from existing file
104
113
  data = @file.read(@file_read_size)
114
+ # Throttle after each read size
115
+ if @throttle and @sleeper.sleep(@throttle)
116
+ return nil, nil
117
+ end
105
118
  if data and data.length > 0
106
119
  read_interface_base(data, nil)
107
120
  return data, nil
@@ -111,9 +124,16 @@ module OpenC3
111
124
  end
112
125
 
113
126
  # Find the next file to read
114
- file = get_next_telemetry_file()
115
- if file
116
- @file = File.open(file, 'rb')
127
+ @filename = get_next_telemetry_file()
128
+ if @filename
129
+ if File.extname(@filename) == ".gz"
130
+ @file = Zlib::GzipReader.open(@filename)
131
+ else
132
+ @file = File.open(@filename, "rb")
133
+ end
134
+ if @discard_file_header_bytes
135
+ @file.read(@discard_file_header_bytes)
136
+ end
117
137
  next
118
138
  end
119
139
 
@@ -135,8 +155,8 @@ module OpenC3
135
155
 
136
156
  def convert_data_to_packet(data, extra = nil)
137
157
  packet = super(data, extra)
138
- if packet and @stored
139
- packet.stored = true
158
+ if packet
159
+ packet.stored = @stored
140
160
  end
141
161
  return packet
142
162
  end
@@ -156,6 +176,11 @@ module OpenC3
156
176
  @polling = ConfigParser.handle_true_false(option_values[0])
157
177
  when 'RECURSIVE'
158
178
  @recursive = ConfigParser.handle_true_false(option_values[0])
179
+ when 'THROTTLE'
180
+ @throttle = Float(option_values[0])
181
+ @sleeper = Sleeper.new
182
+ when 'DISCARD_FILE_HEADER_BYTES'
183
+ @discard_file_header_bytes = Integer(option_values[0])
159
184
  end
160
185
  end
161
186
 
@@ -173,11 +198,15 @@ module OpenC3
173
198
  end
174
199
 
175
200
  def get_next_telemetry_file
201
+ files = []
176
202
  if @recursive
177
- return Dir.glob("#{@telemetry_read_folder}/**/*").sort[0]
203
+ files = Dir.glob("#{@telemetry_read_folder}/**/*")
178
204
  else
179
- return Dir.glob("#{@telemetry_read_folder}/*").sort[0]
205
+ files = Dir.glob("#{@telemetry_read_folder}/*")
180
206
  end
207
+ # Dir.glob includes directories, so filter them out
208
+ files = files.sort.select { |fn| File.file?(fn) }
209
+ return files[0]
181
210
  end
182
211
 
183
212
  def create_unique_filename
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
17
+ # All changes Copyright 2025, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -37,7 +37,7 @@ module OpenC3
37
37
  # @param fill_fields [Boolean] Fill any required fields when writing packets
38
38
  # @param allow_empty_data [true/false/nil] See Protocol#initialize
39
39
  def initialize(discard_leading_bytes = 0, sync_pattern = nil, fill_fields = false, allow_empty_data = nil)
40
- super(allow_empty_data)
40
+ super(allow_empty_data) # Calls reset()
41
41
  @discard_leading_bytes = discard_leading_bytes.to_i
42
42
  @sync_pattern = ConfigParser.handle_nil(sync_pattern)
43
43
  @sync_pattern = @sync_pattern.hex_to_byte_string if @sync_pattern
@@ -65,7 +65,7 @@ module OpenC3
65
65
  # @return [String|nil] Data for a packet consisting of the bytes read
66
66
  def read_data(data, extra = nil)
67
67
  @data << data
68
- @extra = extra
68
+ @extra = extra unless (data.length == 0 and extra.nil?) # Maintain extra from last read read_data
69
69
 
70
70
  while true
71
71
  control = handle_sync_pattern()
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
17
+ # All changes Copyright 2025, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -30,12 +30,12 @@ module OpenC3
30
30
 
31
31
  # @param sync_pattern (see BurstProtocol#initialize)
32
32
  # @param max_length [Integer] The maximum allowed value of the length field
33
+ # @param _unused [Integer] Legacy version number - unused
33
34
  # @param allow_empty_data [true/false/nil] See Protocol#initialize
34
- def initialize(sync_pattern = nil, max_length = nil, mode = 4, allow_empty_data = nil)
35
+ def initialize(sync_pattern = nil, max_length = nil, _unused = nil, allow_empty_data = nil)
35
36
  super(0, sync_pattern, false, allow_empty_data)
36
37
  @max_length = ConfigParser.handle_nil(max_length)
37
38
  @max_length = Integer(@max_length) if @max_length
38
- @mode = Integer(mode)
39
39
  end
40
40
 
41
41
  def reset
@@ -47,13 +47,11 @@ module OpenC3
47
47
  packet.received_time = @read_received_time
48
48
  packet.target_name = @read_target_name
49
49
  packet.packet_name = @read_packet_name
50
- if @mode == 4 # COSMOS4.3+ Protocol
51
- packet.stored = @read_stored
52
- if packet.extra and @read_extra
53
- packet.extra.merge(@read_extra)
54
- else
55
- packet.extra = @read_extra
56
- end
50
+ packet.stored = @read_stored
51
+ if packet.extra and @read_extra
52
+ packet.extra.merge(@read_extra)
53
+ else
54
+ packet.extra = @read_extra
57
55
  end
58
56
  return packet
59
57
  end
@@ -67,14 +65,12 @@ module OpenC3
67
65
  @write_target_name = 'UNKNOWN' unless @write_target_name
68
66
  @write_packet_name = packet.packet_name
69
67
  @write_packet_name = 'UNKNOWN' unless @write_packet_name
70
- if @mode == 4 # COSMOS4.3+ Protocol
71
- @write_flags = 0
72
- @write_flags |= COSMOS4_STORED_FLAG_MASK if packet.stored
73
- @write_extra = nil
74
- if packet.extra
75
- @write_flags |= COSMOS4_EXTRA_FLAG_MASK
76
- @write_extra = packet.extra.as_json(:allow_nan => true).to_json(:allow_nan => true)
77
- end
68
+ @write_flags = 0
69
+ @write_flags |= COSMOS4_STORED_FLAG_MASK if packet.stored
70
+ @write_extra = nil
71
+ if packet.extra
72
+ @write_flags |= COSMOS4_EXTRA_FLAG_MASK
73
+ @write_extra = packet.extra.as_json(:allow_nan => true).to_json(:allow_nan => true)
78
74
  end
79
75
  return packet
80
76
  end
@@ -83,12 +79,10 @@ module OpenC3
83
79
  data_length = [data.length].pack('N') # UINT32
84
80
  data_to_send = ''
85
81
  data_to_send << @sync_pattern if @sync_pattern
86
- if @mode == 4 # COSMOS4.3+ Protocol
87
- data_to_send << @write_flags
88
- if @write_extra
89
- data_to_send << [@write_extra.length].pack('N')
90
- data_to_send << @write_extra
91
- end
82
+ data_to_send << @write_flags
83
+ if @write_extra
84
+ data_to_send << [@write_extra.length].pack('N')
85
+ data_to_send << @write_extra
92
86
  end
93
87
  data_to_send << @write_time_seconds
94
88
  data_to_send << @write_time_microseconds
@@ -146,7 +140,7 @@ module OpenC3
146
140
  @reduction_state = :SYNC_REMOVED
147
141
  end
148
142
 
149
- if @reduction_state == :SYNC_REMOVED and @mode == 4
143
+ if @reduction_state == :SYNC_REMOVED
150
144
  # Read and remove flags
151
145
  return :STOP if @data.length < 1
152
146
 
@@ -171,7 +165,7 @@ module OpenC3
171
165
  @reduction_state = :FLAGS_REMOVED
172
166
  end
173
167
 
174
- if @reduction_state == :FLAGS_REMOVED or (@reduction_state == :SYNC_REMOVED and @mode != 4)
168
+ if @reduction_state == :FLAGS_REMOVED
175
169
  # Read and remove packet received time
176
170
  return :STOP if @data.length < 8
177
171
 
@@ -14,21 +14,22 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2024, OpenC3, Inc.
17
+ # All changes Copyright 2025, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  module OpenC3
24
- autoload(:Interface, 'openc3/interfaces/interface.rb')
24
+ autoload(:FileInterface, 'openc3/interfaces/file_interface.rb')
25
25
  autoload(:HttpClientInterface, 'openc3/interfaces/http_client_interface.rb')
26
26
  autoload(:HttpServerInterface, 'openc3/interfaces/http_server_interface.rb')
27
+ autoload(:Interface, 'openc3/interfaces/interface.rb')
27
28
  autoload(:MqttInterface, 'openc3/interfaces/mqtt_interface.rb')
28
29
  autoload(:MqttStreamInterface, 'openc3/interfaces/mqtt_stream_interface.rb')
29
- autoload(:StreamInterface, 'openc3/interfaces/stream_interface.rb')
30
30
  autoload(:SerialInterface, 'openc3/interfaces/serial_interface.rb')
31
31
  autoload(:SimulatedTargetInterface, 'openc3/interfaces/simulated_target_interface.rb')
32
+ autoload(:StreamInterface, 'openc3/interfaces/stream_interface.rb')
32
33
  autoload(:TcpipClientInterface, 'openc3/interfaces/tcpip_client_interface.rb')
33
34
  autoload(:TcpipServerInterface, 'openc3/interfaces/tcpip_server_interface.rb')
34
35
  autoload(:UdpInterface, 'openc3/interfaces/udp_interface.rb')
@@ -57,7 +57,7 @@ module OpenC3
57
57
  # @param url [String] The url of openc3-cosmos-cmd-tlm-api http://openc3-cosmos-cmd-tlm-api:2901
58
58
  # @param timeout [Float] The time to wait before disconnecting 1.0
59
59
  # @param authentication [OpenC3Authentication] The authentication object if nill initialize will generate
60
- def initialize(url: ENV['OPENC3_API_URL'], timeout: 1.0, authentication: nil)
60
+ def initialize(url:, timeout: 1.0, authentication: nil)
61
61
  @http = nil
62
62
  @mutex = Mutex.new
63
63
  @request_data = ""
@@ -43,7 +43,7 @@ module OpenC3
43
43
  # @param url [String] The url of openc3-cosmos-cmd-tlm-api http://openc3-cosmos-cmd-tlm-api:2901
44
44
  # @param timeout [Float] The time to wait before disconnecting 1.0
45
45
  # @param authentication [OpenC3Authentication] The authentication object if nill initialize will generate
46
- def initialize(url: ENV['OPENC3_API_URL'], timeout: 1.0, authentication: nil)
46
+ def initialize(url:, timeout: 1.0, authentication: nil)
47
47
  super(url: url, timeout: timeout, authentication: authentication)
48
48
  @uri = URI("#{url}/openc3-api/api")
49
49
  end
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
17
+ # All changes Copyright 2025, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -100,7 +100,8 @@ module OpenC3
100
100
  cycle_size = 1_000_000_000,
101
101
  cycle_hour = nil,
102
102
  cycle_minute = nil,
103
- enforce_time_order = true
103
+ enforce_time_order = true,
104
+ cycle_thread: true
104
105
  )
105
106
  @remote_log_directory = remote_log_directory
106
107
  @logging_enabled = ConfigParser.handle_true_false(logging_enabled)
@@ -135,13 +136,15 @@ module OpenC3
135
136
  # each time we create an entry which we do a LOT!
136
137
  @entry = String.new
137
138
 
138
- # Always make sure there is a cycle thread - (because it does trimming)
139
- @@mutex.synchronize do
140
- @@instances << self
139
+ if cycle_thread
140
+ # Always make sure there is a cycle thread - (because it does trimming)
141
+ @@mutex.synchronize do
142
+ @@instances << self
141
143
 
142
- unless @@cycle_thread
143
- @@cycle_thread = OpenC3.safe_thread("Log cycle") do
144
- cycle_thread_body()
144
+ unless @@cycle_thread
145
+ @@cycle_thread = OpenC3.safe_thread("Log cycle") do
146
+ cycle_thread_body()
147
+ end
145
148
  end
146
149
  end
147
150
  end