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.
- checksums.yaml +4 -4
- data/Gemfile +2 -3
- data/bin/openc3cli +13 -14
- data/data/config/interface_modifiers.yaml +1 -1
- data/data/config/microservice.yaml +1 -1
- data/data/config/plugins.yaml +1 -1
- data/data/config/tool.yaml +1 -1
- data/data/config/widgets.yaml +3 -0
- data/ext/openc3/ext/burst_protocol/burst_protocol.c +5 -1
- data/lib/openc3/api/api.rb +7 -1
- data/lib/openc3/api/cmd_api.rb +5 -8
- data/lib/openc3/api/interface_api.rb +8 -4
- data/lib/openc3/api/tlm_api.rb +23 -8
- data/lib/openc3/interfaces/file_interface.rb +36 -7
- data/lib/openc3/interfaces/protocols/burst_protocol.rb +3 -3
- data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +20 -26
- data/lib/openc3/interfaces.rb +4 -3
- data/lib/openc3/io/json_api_object.rb +1 -1
- data/lib/openc3/io/json_drb_object.rb +1 -1
- data/lib/openc3/logs/log_writer.rb +11 -8
- data/lib/openc3/logs/packet_log_reader.rb +2 -2
- data/lib/openc3/logs/packet_log_writer.rb +1 -1
- data/lib/openc3/microservices/interface_decom_common.rb +4 -1
- data/lib/openc3/microservices/interface_microservice.rb +69 -6
- data/lib/openc3/microservices/microservice.rb +3 -1
- data/lib/openc3/microservices/multi_microservice.rb +1 -1
- data/lib/openc3/migrations/20250402000000_periodic_only_default.rb +24 -0
- data/lib/openc3/models/model.rb +6 -2
- data/lib/openc3/models/offline_access_model.rb +7 -6
- data/lib/openc3/models/scope_model.rb +5 -2
- data/lib/openc3/models/script_status_model.rb +242 -0
- data/lib/openc3/models/target_model.rb +150 -15
- data/lib/openc3/packets/commands.rb +10 -3
- data/lib/openc3/script/api_shared.rb +4 -0
- data/lib/openc3/script/commands.rb +1 -1
- data/lib/openc3/script/script.rb +14 -0
- data/lib/openc3/script/script_runner.rb +22 -7
- data/lib/openc3/utilities/authentication.rb +6 -6
- data/lib/openc3/utilities/cosmos_rails_formatter.rb +1 -1
- data/lib/openc3/utilities/local_mode.rb +5 -2
- data/lib/openc3/utilities/message_log.rb +2 -0
- data/lib/openc3/utilities/metric.rb +1 -1
- data/lib/openc3/utilities/ruby_lex_utils.rb +114 -279
- data/lib/openc3/utilities/target_file.rb +6 -2
- data/lib/openc3/version.rb +6 -6
- data/templates/tool_angular/package.json +2 -2
- data/templates/tool_react/package.json +1 -1
- data/templates/tool_svelte/package.json +1 -1
- data/templates/tool_vue/eslint.config.mjs +17 -41
- data/templates/tool_vue/package.json +3 -3
- data/templates/widget/package.json +2 -2
- metadata +21 -23
- data/ext/mkrf_conf.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c408df49ec8cf1fbcf88e8c05207ac1c65274d56dbee94986c4f56308bc52b23
|
4
|
+
data.tar.gz: 8e8897d618e69898470fcd8a201ba968688fbe598c4ecb46d1a375da14282490
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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 #
|
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
|
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
|
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
|
data/data/config/plugins.yaml
CHANGED
@@ -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
|
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:
|
data/data/config/tool.yaml
CHANGED
@@ -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
|
69
|
+
All COSMOS Core tools have consecutive integer values for position.
|
70
70
|
since: 5.0.8
|
71
71
|
parameters:
|
72
72
|
- name: Position
|
data/data/config/widgets.yaml
CHANGED
@@ -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
|
-
|
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
|
{
|
data/lib/openc3/api/api.rb
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
# GNU Affero General Public License for more details.
|
15
15
|
|
16
16
|
# Modified by OpenC3, Inc.
|
17
|
-
# All changes Copyright
|
17
|
+
# All changes Copyright 2025, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
#
|
20
20
|
# This file may also be used under the terms of a commercial license
|
@@ -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
|
data/lib/openc3/api/cmd_api.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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 |
|
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
|
data/lib/openc3/api/tlm_api.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
115
|
-
if
|
116
|
-
|
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
|
139
|
-
packet.stored =
|
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
|
-
|
203
|
+
files = Dir.glob("#{@telemetry_read_folder}/**/*")
|
178
204
|
else
|
179
|
-
|
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
|
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
|
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,
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
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
|
168
|
+
if @reduction_state == :FLAGS_REMOVED
|
175
169
|
# Read and remove packet received time
|
176
170
|
return :STOP if @data.length < 8
|
177
171
|
|
data/lib/openc3/interfaces.rb
CHANGED
@@ -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
|
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(:
|
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
|
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
|
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
|
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
|
-
|
139
|
-
|
140
|
-
@@
|
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
|
-
|
143
|
-
|
144
|
-
|
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
|