openc3 5.5.2 → 5.6.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.
Potentially problematic release.
This version of openc3 might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bin/openc3cli +167 -69
- data/data/config/_interfaces.yaml +1 -6
- data/data/config/interface_modifiers.yaml +55 -4
- data/data/config/microservice.yaml +30 -3
- data/ext/openc3/ext/crc/crc.c +82 -1
- data/lib/openc3/api/cmd_api.rb +19 -7
- data/lib/openc3/api/tlm_api.rb +13 -12
- data/lib/openc3/bridge/bridge_config.rb +4 -4
- data/lib/openc3/config/config_parser.rb +1 -0
- data/lib/openc3/conversions/unix_time_conversion.rb +3 -1
- data/lib/openc3/ext/.keep +0 -0
- data/lib/openc3/interfaces/interface.rb +54 -26
- data/lib/openc3/interfaces/serial_interface.rb +4 -5
- data/lib/openc3/interfaces/simulated_target_interface.rb +4 -4
- data/lib/openc3/interfaces/stream_interface.rb +2 -2
- data/lib/openc3/interfaces/tcpip_client_interface.rb +4 -3
- data/lib/openc3/interfaces/tcpip_server_interface.rb +18 -19
- data/lib/openc3/interfaces/udp_interface.rb +10 -4
- data/lib/openc3/io/json_api.rb +72 -0
- data/lib/openc3/io/serial_driver.rb +4 -5
- data/lib/openc3/logs/buffered_packet_log_writer.rb +2 -4
- data/lib/openc3/logs/log_writer.rb +9 -8
- data/lib/openc3/logs/packet_log_reader.rb +8 -1
- data/lib/openc3/logs/packet_log_writer.rb +3 -4
- data/lib/openc3/logs/stream_log.rb +116 -0
- data/lib/openc3/logs/stream_log_pair.rb +70 -0
- data/lib/openc3/microservices/cleanup_microservice.rb +1 -1
- data/lib/openc3/microservices/decom_microservice.rb +17 -2
- data/lib/openc3/microservices/interface_decom_common.rb +42 -0
- data/lib/openc3/microservices/interface_microservice.rb +24 -17
- data/lib/openc3/microservices/router_microservice.rb +46 -4
- data/lib/openc3/migrations/20221202214600_add_target_names.rb +1 -1
- data/lib/openc3/migrations/20230319154100_log_stream.rb +40 -0
- data/lib/openc3/migrations/20230413101100_remove_log.rb +30 -0
- data/lib/openc3/models/gem_model.rb +2 -2
- data/lib/openc3/models/interface_model.rb +13 -14
- data/lib/openc3/models/metadata_model.rb +1 -1
- data/lib/openc3/models/note_model.rb +1 -1
- data/lib/openc3/models/plugin_model.rb +3 -2
- data/lib/openc3/operators/operator.rb +2 -0
- data/lib/openc3/packets/commands.rb +2 -0
- data/lib/openc3/packets/packet_config.rb +3 -2
- data/lib/openc3/packets/parsers/xtce_converter.rb +2 -1
- data/lib/openc3/script/gems.rb +125 -0
- data/lib/openc3/script/plugins.rb +186 -0
- data/lib/openc3/script/screen.rb +119 -0
- data/lib/openc3/script/script.rb +3 -0
- data/lib/openc3/script/script_runner.rb +19 -8
- data/lib/openc3/script/suite_results.rb +2 -2
- data/lib/openc3/script/web_socket_api.rb +5 -1
- data/lib/openc3/streams/serial_stream.rb +14 -11
- data/lib/openc3/streams/tcpip_client_stream.rb +5 -2
- data/lib/openc3/streams/tcpip_socket_stream.rb +37 -71
- data/lib/openc3/streams/web_socket_client_stream.rb +5 -3
- data/lib/openc3/system/system.rb +2 -0
- data/lib/openc3/topics/interface_topic.rb +13 -4
- data/lib/openc3/topics/router_topic.rb +6 -6
- data/lib/openc3/topics/telemetry_decom_topic.rb +10 -1
- data/lib/openc3/utilities/bucket_utilities.rb +12 -5
- data/lib/openc3/utilities/cli_generator.rb +56 -4
- data/lib/openc3/utilities/crc.rb +42 -7
- data/lib/openc3/utilities/process_manager.rb +3 -1
- data/lib/openc3/utilities/ruby_lex_utils.rb +265 -504
- data/lib/openc3/version.rb +6 -6
- data/templates/conversion/conversion.rb +10 -2
- data/templates/microservice/microservices/TEMPLATE/microservice.rb +1 -1
- data/templates/plugin/Rakefile +8 -1
- data/templates/widget/.browserslistrc +16 -0
- data/templates/widget/.eslintrc.js +43 -0
- data/templates/widget/.nycrc +3 -0
- data/templates/widget/.prettierrc.js +5 -0
- data/templates/widget/LICENSE.txt +20 -0
- data/templates/widget/Rakefile +24 -0
- data/templates/widget/babel.config.json +11 -0
- data/templates/widget/package.json +35 -0
- data/templates/widget/src/Widget.vue +46 -0
- data/templates/widget/vue.config.js +25 -0
- data/templates/widget/yarn.lock +8938 -0
- metadata +23 -4
- data/lib/openc3/io/raw_logger.rb +0 -170
- data/lib/openc3/io/raw_logger_pair.rb +0 -80
@@ -40,7 +40,7 @@ module OpenC3
|
|
40
40
|
|
41
41
|
def script_syntax_check(script, scope: $openc3_scope)
|
42
42
|
endpoint = "/script-api/scripts/syntax"
|
43
|
-
response = $script_runner_api_server.request('post', endpoint, :data
|
43
|
+
response = $script_runner_api_server.request('post', endpoint, json: true, data: script, scope: scope)
|
44
44
|
if response.nil? || response.code != 200
|
45
45
|
_script_response_error(response, "Script syntax check request failed", scope: scope)
|
46
46
|
else
|
@@ -64,13 +64,24 @@ module OpenC3
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
-
def script_run(filename, disconnect: false, scope: $openc3_scope)
|
67
|
+
def script_run(filename, disconnect: false, environment: nil, scope: $openc3_scope)
|
68
68
|
if disconnect
|
69
69
|
endpoint = "/script-api/scripts/#{filename}/run/disconnect"
|
70
70
|
else
|
71
71
|
endpoint = "/script-api/scripts/#{filename}/run"
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
|
+
# Encode the environment hash into an array of key values
|
75
|
+
if environment && !environment.empty?
|
76
|
+
env_data = []
|
77
|
+
environment.map do |key, value|
|
78
|
+
env_data << { "key" => key, "value" => value }
|
79
|
+
end
|
80
|
+
else
|
81
|
+
env_data = []
|
82
|
+
end
|
83
|
+
# NOTE: json: true causes json_api_object to JSON generate and set the Content-Type to json
|
84
|
+
response = $script_runner_api_server.request('post', endpoint, json: true, data: { environment: env_data }, scope: scope)
|
74
85
|
if response.nil? || response.code != 200
|
75
86
|
_script_response_error(response, "Failed to run #{filename}", scope: scope)
|
76
87
|
else
|
@@ -111,7 +122,7 @@ module OpenC3
|
|
111
122
|
|
112
123
|
def script_instrumented(filename, script, scope: $openc3_scope)
|
113
124
|
endpoint = "/script-api/scripts/#{filename}/instrumented"
|
114
|
-
response = $script_runner_api_server.request('post', endpoint, :data
|
125
|
+
response = $script_runner_api_server.request('post', endpoint, json: true, data: script, scope: scope)
|
115
126
|
if response.nil? || response.code != 200
|
116
127
|
_script_response_error(response, "Script instrumented request failed", scope: scope)
|
117
128
|
else
|
@@ -127,7 +138,7 @@ module OpenC3
|
|
127
138
|
|
128
139
|
def script_create(filename, script, breakpoints = [], scope: $openc3_scope)
|
129
140
|
endpoint = "/script-api/scripts/#{filename}"
|
130
|
-
response = $script_runner_api_server.request('post', endpoint, :data
|
141
|
+
response = $script_runner_api_server.request('post', endpoint, json: true, data: { text: script, breakpoints: breakpoints }, scope: scope)
|
131
142
|
if response.nil? || response.code != 200
|
132
143
|
_script_response_error(response, "Script create request failed", scope: scope)
|
133
144
|
else
|
@@ -205,7 +216,7 @@ module OpenC3
|
|
205
216
|
|
206
217
|
def running_script_debug(id, debug_code, scope: $openc3_scope)
|
207
218
|
endpoint = "/script-api/running-script/#{id}/debug"
|
208
|
-
response = $script_runner_api_server.request('post', endpoint, data: {'args' => debug_code}, scope: scope)
|
219
|
+
response = $script_runner_api_server.request('post', endpoint, json: true, data: {'args' => debug_code}, scope: scope)
|
209
220
|
if response.nil? || response.code != 200
|
210
221
|
_script_response_error(response, "Running script debug request failed", scope: scope)
|
211
222
|
else
|
@@ -216,9 +227,9 @@ module OpenC3
|
|
216
227
|
def running_script_prompt(id, method_name, answer, prompt_id, password: nil, scope: $openc3_scope)
|
217
228
|
endpoint = "/script-api/running-script/#{id}/prompt"
|
218
229
|
if password
|
219
|
-
response = $script_runner_api_server.request('post', endpoint, data: {'method' => method_name, 'answer' => answer, 'prompt_id' => prompt_id, 'password' => password}, scope: scope)
|
230
|
+
response = $script_runner_api_server.request('post', endpoint, json: true, data: {'method' => method_name, 'answer' => answer, 'prompt_id' => prompt_id, 'password' => password}, scope: scope)
|
220
231
|
else
|
221
|
-
response = $script_runner_api_server.request('post', endpoint, data: {'method' => method_name, 'answer' => answer, 'prompt_id' => prompt_id}, scope: scope)
|
232
|
+
response = $script_runner_api_server.request('post', endpoint, json: true, data: {'method' => method_name, 'answer' => answer, 'prompt_id' => prompt_id}, scope: scope)
|
222
233
|
end
|
223
234
|
if response.nil? || response.code != 200
|
224
235
|
_script_response_error(response, "Running script prompt request failed", scope: scope)
|
@@ -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
|
module OpenC3
|
@@ -108,7 +108,7 @@ module OpenC3
|
|
108
108
|
end
|
109
109
|
|
110
110
|
def header
|
111
|
-
@report << "---
|
111
|
+
@report << "--- Script Report ---"
|
112
112
|
# @report << ''
|
113
113
|
# if @metadata
|
114
114
|
# begin
|
@@ -401,12 +401,16 @@ module OpenC3
|
|
401
401
|
end
|
402
402
|
|
403
403
|
# # Example Use
|
404
|
+
# # The following lines are only for outside of the COSMOS Docker or Kubernetes Cluster
|
405
|
+
# # Environment variables are already set inside of our containers
|
406
|
+
# # START OUTSIDE OF DOCKER ONLY
|
404
407
|
# $openc3_scope = 'DEFAULT'
|
405
408
|
# ENV['OPENC3_API_HOSTNAME'] = 'localhost'
|
406
409
|
# ENV['OPENC3_API_PORT'] = '2900'
|
407
410
|
# ENV['OPENC3_SCRIPT_API_HOSTNAME'] = 'localhost'
|
408
411
|
# ENV['OPENC3_SCRIPT_API_PORT'] = '2900'
|
409
412
|
# ENV['OPENC3_API_PASSWORD'] = 'password'
|
413
|
+
# # END OUTSIDE OF DOCKER ONLY
|
410
414
|
#
|
411
415
|
# OpenC3::StreamingWebSocketApi.new do |api|
|
412
416
|
# api.add(items: ['DECOM__TLM__INST__HEALTH_STATUS__TEMP1__CONVERTED', 'DECOM__TLM__INST__HEALTH_STATUS__TEMP2__CONVERTED'])
|
@@ -420,4 +424,4 @@ end
|
|
420
424
|
# end
|
421
425
|
#
|
422
426
|
# # Warning this saves all data to RAM. Do not use for large queries
|
423
|
-
# data = OpenC3::StreamingWebSocketApi.read_all(items: ['DECOM__TLM__INST__HEALTH_STATUS__TEMP1__CONVERTED', 'DECOM__TLM__INST__HEALTH_STATUS__TEMP2__CONVERTED'], end_time: Time.now + 30)
|
427
|
+
# data = OpenC3::StreamingWebSocketApi.read_all(items: ['DECOM__TLM__INST__HEALTH_STATUS__TEMP1__CONVERTED', 'DECOM__TLM__INST__HEALTH_STATUS__TEMP2__CONVERTED'], start_time: Time.now - 30, end_time: Time.now + 30)
|
@@ -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 'thread' # For Mutex
|
@@ -38,15 +38,13 @@ module OpenC3
|
|
38
38
|
# name is typically a device such as '/dev/ttyS0'.
|
39
39
|
# @param baud_rate [Integer] The serial port baud rate
|
40
40
|
# @param parity [Symbol] Must be :NONE, :EVEN, or :ODD
|
41
|
-
# @param stop_bits [Integer]
|
42
|
-
# @param write_timeout [Integer]
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
# continously try to read data until it has received data or an error
|
49
|
-
# occurs.
|
41
|
+
# @param stop_bits [Integer] Stop bits. Must be 1 or 2.
|
42
|
+
# @param write_timeout [Integer] Seconds to wait for the write to complete.
|
43
|
+
# The {SerialDriver} will continously try to send the data until
|
44
|
+
# it has been sent or an error occurs.
|
45
|
+
# @param read_timeout [Integer] Seconds to wait for the read to complete.
|
46
|
+
# Pass nil to block until the read is complete. The {SerialDriver} will
|
47
|
+
# continously try to read data until it has received data or an error occurs.
|
50
48
|
# @param flow_control [Symbol] Currently supported :NONE and :RTSCTS (default :NONE)
|
51
49
|
# @param data_bits [Integer] Number of data bits (default 8)
|
52
50
|
def initialize(write_port_name,
|
@@ -67,7 +65,12 @@ module OpenC3
|
|
67
65
|
@parity = parity
|
68
66
|
@stop_bits = stop_bits.to_i
|
69
67
|
@write_timeout = ConfigParser.handle_nil(write_timeout)
|
70
|
-
|
68
|
+
if @write_timeout
|
69
|
+
@write_timeout = @write_timeout.to_f
|
70
|
+
else
|
71
|
+
Logger.instance.warn("Warning: To avoid interface lock, write_timeout can not be nil. Setting to 10 seconds.")
|
72
|
+
@write_timeout = 10.0
|
73
|
+
end
|
71
74
|
@read_timeout = ConfigParser.handle_nil(read_timeout)
|
72
75
|
@read_timeout = @read_timeout.to_f if @read_timeout
|
73
76
|
@flow_control = flow_control.to_s.intern
|
@@ -36,8 +36,11 @@ module OpenC3
|
|
36
36
|
# a read only stream.
|
37
37
|
# @param read_port [Integer|nil] The port to read. Pass nil to make this
|
38
38
|
# a write only stream.
|
39
|
-
# @param write_timeout
|
40
|
-
# @param read_timeout
|
39
|
+
# @param write_timeout [Float] Seconds to wait before aborting writes
|
40
|
+
# @param read_timeout [Float|nil] Seconds to wait before aborting reads.
|
41
|
+
# Pass nil to block until the read is complete.
|
42
|
+
# @param connect_timeout [Float|nil] Seconds to wait before aborting connect.
|
43
|
+
# Pass nil to block until the connection is complete.
|
41
44
|
def initialize(hostname, write_port, read_port, write_timeout, read_timeout, connect_timeout = 5.0)
|
42
45
|
@hostname = hostname
|
43
46
|
if @hostname.to_s.upcase == 'LOCALHOST'
|
@@ -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 'socket'
|
@@ -31,21 +31,23 @@ module OpenC3
|
|
31
31
|
class TcpipSocketStream < Stream
|
32
32
|
attr_reader :write_socket
|
33
33
|
|
34
|
-
FAST_READ = (RUBY_VERSION > "2.1")
|
35
|
-
|
36
34
|
# @param write_socket [Socket] Socket to write
|
37
35
|
# @param read_socket [Socket] Socket to read
|
38
|
-
# @param write_timeout [Float
|
39
|
-
#
|
40
|
-
#
|
41
|
-
# to complete or nil to block until the socket is ready to read.
|
36
|
+
# @param write_timeout [Float] Seconds to wait before aborting writes
|
37
|
+
# @param read_timeout [Float|nil] Seconds to wait before aborting reads.
|
38
|
+
# Pass nil to block until the read is complete.
|
42
39
|
def initialize(write_socket, read_socket, write_timeout, read_timeout)
|
43
40
|
super()
|
44
41
|
|
45
42
|
@write_socket = write_socket
|
46
43
|
@read_socket = read_socket
|
47
44
|
@write_timeout = ConfigParser.handle_nil(write_timeout)
|
48
|
-
|
45
|
+
if @write_timeout
|
46
|
+
@write_timeout = @write_timeout.to_f
|
47
|
+
else
|
48
|
+
Logger.warn("Warning: To avoid interface lock, write_timeout can not be nil. Setting to 10 seconds.")
|
49
|
+
@write_timeout = 10.0
|
50
|
+
end
|
49
51
|
@read_timeout = ConfigParser.handle_nil(read_timeout)
|
50
52
|
@read_timeout = @read_timeout.to_f if @read_timeout
|
51
53
|
|
@@ -61,67 +63,37 @@ module OpenC3
|
|
61
63
|
raise "Attempt to read from write only stream" unless @read_socket
|
62
64
|
|
63
65
|
# No read mutex is needed because reads happen serially
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
if result
|
78
|
-
|
79
|
-
raise IOError
|
80
|
-
else
|
81
|
-
next
|
82
|
-
end
|
66
|
+
begin
|
67
|
+
while true # Loop until we get some data
|
68
|
+
data = @read_socket.read_nonblock(65535, exception: false)
|
69
|
+
raise EOFError, 'end of file reached' unless data
|
70
|
+
|
71
|
+
if data == :wait_readable
|
72
|
+
# Wait for the socket to be ready for reading or for the timeout
|
73
|
+
begin
|
74
|
+
result = IO.fast_select([@read_socket, @pipe_reader], nil, nil, @read_timeout)
|
75
|
+
# If select returns something it means the socket is now available for
|
76
|
+
# reading so retry the read. If it returns nil it means we timed out.
|
77
|
+
# If the pipe is present that means we closed the socket
|
78
|
+
if result
|
79
|
+
if result.include?(@pipe_reader)
|
80
|
+
raise IOError
|
83
81
|
else
|
84
|
-
|
82
|
+
next
|
85
83
|
end
|
86
|
-
rescue IOError, Errno::ENOTSOCK
|
87
|
-
# These can happen with the socket being closed while waiting on select
|
88
|
-
data = ''
|
89
|
-
end
|
90
|
-
end
|
91
|
-
break
|
92
|
-
end
|
93
|
-
rescue Errno::ECONNRESET, Errno::ECONNABORTED, IOError, Errno::ENOTSOCK
|
94
|
-
data = ''
|
95
|
-
end
|
96
|
-
else
|
97
|
-
begin
|
98
|
-
data = @read_socket.read_nonblock(65535)
|
99
|
-
rescue IO::WaitReadable
|
100
|
-
# Wait for the socket to be ready for reading or for the timeout
|
101
|
-
begin
|
102
|
-
result = IO.fast_select([@read_socket, @pipe_reader], nil, nil, @read_timeout)
|
103
|
-
|
104
|
-
# If select returns something it means the socket is now available for
|
105
|
-
# reading so retry the read. If it returns nil it means we timed out.
|
106
|
-
# If the pipe is present that means we closed the socket
|
107
|
-
if result
|
108
|
-
if result.include?(@pipe_reader)
|
109
|
-
raise IOError
|
110
84
|
else
|
111
|
-
|
85
|
+
raise Timeout::Error, "Read Timeout"
|
112
86
|
end
|
113
|
-
|
114
|
-
|
87
|
+
rescue IOError, Errno::ENOTSOCK
|
88
|
+
# These can happen with the socket being closed while waiting on select
|
89
|
+
data = ''
|
115
90
|
end
|
116
|
-
rescue IOError, Errno::ENOTSOCK
|
117
|
-
# These can happen with the socket being closed while waiting on select
|
118
|
-
data = ''
|
119
91
|
end
|
120
|
-
|
121
|
-
data = ''
|
92
|
+
break
|
122
93
|
end
|
94
|
+
rescue Errno::ECONNRESET, Errno::ECONNABORTED, IOError, Errno::ENOTSOCK
|
95
|
+
data = ''
|
123
96
|
end
|
124
|
-
|
125
97
|
data
|
126
98
|
end
|
127
99
|
|
@@ -129,18 +101,12 @@ module OpenC3
|
|
129
101
|
def read_nonblock
|
130
102
|
# No read mutex is needed because reads happen serially
|
131
103
|
begin
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
data = '' if data == :wait_readable
|
137
|
-
else
|
138
|
-
data = @read_socket.read_nonblock(65535)
|
139
|
-
end
|
104
|
+
data = @read_socket.read_nonblock(65535, exception: false)
|
105
|
+
raise EOFError, 'end of file reached' unless data
|
106
|
+
data = '' if data == :wait_readable
|
140
107
|
rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNRESET, Errno::ECONNABORTED, IOError
|
141
108
|
data = ''
|
142
109
|
end
|
143
|
-
|
144
110
|
data
|
145
111
|
end
|
146
112
|
|
@@ -194,5 +160,5 @@ module OpenC3
|
|
194
160
|
@pipe_writer.write('.')
|
195
161
|
@connected = false
|
196
162
|
end
|
197
|
-
end
|
163
|
+
end
|
198
164
|
end
|
@@ -26,9 +26,11 @@ module OpenC3
|
|
26
26
|
attr_accessor :headers
|
27
27
|
|
28
28
|
# @param url [String] The host to connect to
|
29
|
-
# @param write_timeout
|
30
|
-
# @param read_timeout
|
31
|
-
#
|
29
|
+
# @param write_timeout [Float] Seconds to wait before aborting writes
|
30
|
+
# @param read_timeout [Float|nil] Seconds to wait before aborting reads.
|
31
|
+
# Pass nil to block until the read is complete.
|
32
|
+
# @param connect_timeout [Float|nil] Seconds to wait before aborting connect.
|
33
|
+
# Pass nil to block until the connection is complete.
|
32
34
|
def initialize(url, write_timeout, read_timeout, connect_timeout = 5.0)
|
33
35
|
@url = url
|
34
36
|
@uri = URI.parse @url
|
data/lib/openc3/system/system.rb
CHANGED
@@ -20,6 +20,7 @@
|
|
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
|
+
require 'openc3/top_level'
|
23
24
|
require 'openc3/config/config_parser'
|
24
25
|
require 'openc3/packets/packet_config'
|
25
26
|
require 'openc3/packets/commands'
|
@@ -116,6 +117,7 @@ module OpenC3
|
|
116
117
|
# @param target_names [Array of target names]
|
117
118
|
# @param target_config_dir Directory where target config folders are
|
118
119
|
def initialize(target_names, target_config_dir)
|
120
|
+
OpenC3.add_to_search_path(target_config_dir, true)
|
119
121
|
@targets = {}
|
120
122
|
@packet_config = PacketConfig.new
|
121
123
|
@commands = Commands.new(@packet_config)
|
@@ -64,11 +64,11 @@ module OpenC3
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def self.start_raw_logging(interface_name, scope:)
|
67
|
-
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { '
|
67
|
+
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'log_stream' => 'true' }, '*', 100)
|
68
68
|
end
|
69
69
|
|
70
70
|
def self.stop_raw_logging(interface_name, scope:)
|
71
|
-
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { '
|
71
|
+
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'log_stream' => 'false' }, '*', 100)
|
72
72
|
end
|
73
73
|
|
74
74
|
def self.shutdown(interface, scope:)
|
@@ -77,14 +77,14 @@ module OpenC3
|
|
77
77
|
InterfaceTopic.clear_topics(InterfaceTopic.topics(interface, scope: scope))
|
78
78
|
end
|
79
79
|
|
80
|
-
def interface_cmd(interface_name, cmd_name, *cmd_params, scope:)
|
80
|
+
def self.interface_cmd(interface_name, cmd_name, *cmd_params, scope:)
|
81
81
|
data = {}
|
82
82
|
data['cmd_name'] = cmd_name
|
83
83
|
data['cmd_params'] = cmd_params
|
84
84
|
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'interface_cmd' => JSON.generate(data, allow_nan: true) }, '*', 100)
|
85
85
|
end
|
86
86
|
|
87
|
-
def protocol_cmd(interface_name, cmd_name, *cmd_params, read_write: :READ_WRITE, index: -1, scope:)
|
87
|
+
def self.protocol_cmd(interface_name, cmd_name, *cmd_params, read_write: :READ_WRITE, index: -1, scope:)
|
88
88
|
data = {}
|
89
89
|
data['cmd_name'] = cmd_name
|
90
90
|
data['cmd_params'] = cmd_params
|
@@ -92,5 +92,14 @@ module OpenC3
|
|
92
92
|
data['index'] = index
|
93
93
|
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'protocol_cmd' => JSON.generate(data, allow_nan: true) }, '*', 100)
|
94
94
|
end
|
95
|
+
|
96
|
+
def self.inject_tlm(interface_name, target_name, packet_name, item_hash = nil, type: :CONVERTED, scope:)
|
97
|
+
data = {}
|
98
|
+
data['target_name'] = target_name.to_s.upcase
|
99
|
+
data['packet_name'] = packet_name.to_s.upcase
|
100
|
+
data['item_hash'] = item_hash
|
101
|
+
data['type'] = type
|
102
|
+
Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'inject_tlm' => JSON.generate(data, allow_nan: true) }, '*', 100)
|
103
|
+
end
|
95
104
|
end
|
96
105
|
end
|
@@ -57,9 +57,9 @@ module OpenC3
|
|
57
57
|
Topic.write_topic(topic, { 'target_name' => packet.target_name, 'cmd_name' => packet.packet_name, 'cmd_buffer' => packet.buffer(false) }, '*', 100)
|
58
58
|
elsif target_names.length == 1
|
59
59
|
topic = "{#{scope}__CMD}TARGET__#{target_names[0]}"
|
60
|
-
Topic.write_topic(topic, { 'target_name' => packet.target_name, 'cmd_name' => 'UNKNOWN', 'cmd_buffer' => packet.buffer(false) }, '*', 100)
|
60
|
+
Topic.write_topic(topic, { 'target_name' => packet.target_name ? packet.target_name : 'UNKNOWN', 'cmd_name' => 'UNKNOWN', 'cmd_buffer' => packet.buffer(false) }, '*', 100)
|
61
61
|
else
|
62
|
-
raise "No route for command: #{packet.target_name} #{packet.packet_name}"
|
62
|
+
raise "No route for command: #{packet.target_name ? packet.target_name : 'UNKNOWN'} #{packet.packet_name ? packet.packet_name : 'UNKNOWN'}"
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -76,11 +76,11 @@ module OpenC3
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def self.start_raw_logging(router_name, scope:)
|
79
|
-
Topic.write_topic("{#{scope}__CMD}ROUTER__#{router_name}", { '
|
79
|
+
Topic.write_topic("{#{scope}__CMD}ROUTER__#{router_name}", { 'log_stream' => 'true' }, '*', 100)
|
80
80
|
end
|
81
81
|
|
82
82
|
def self.stop_raw_logging(router_name, scope:)
|
83
|
-
Topic.write_topic("{#{scope}__CMD}ROUTER__#{router_name}", { '
|
83
|
+
Topic.write_topic("{#{scope}__CMD}ROUTER__#{router_name}", { 'log_stream' => 'false' }, '*', 100)
|
84
84
|
end
|
85
85
|
|
86
86
|
def self.shutdown(router, scope:)
|
@@ -89,14 +89,14 @@ module OpenC3
|
|
89
89
|
RouterTopic.clear_topics(RouterTopic.topics(router, scope: scope))
|
90
90
|
end
|
91
91
|
|
92
|
-
def router_cmd(router_name, cmd_name, *cmd_params, scope:)
|
92
|
+
def self.router_cmd(router_name, cmd_name, *cmd_params, scope:)
|
93
93
|
data = {}
|
94
94
|
data['cmd_name'] = cmd_name
|
95
95
|
data['cmd_params'] = cmd_params
|
96
96
|
Topic.write_topic("{#{scope}__CMD}ROUTER__#{router_name}", { 'router_cmd' => JSON.generate(data, allow_nan: true) }, '*', 100)
|
97
97
|
end
|
98
98
|
|
99
|
-
def protocol_cmd(router_name, cmd_name, *cmd_params, read_write: :READ_WRITE, index: -1, scope:)
|
99
|
+
def self.protocol_cmd(router_name, cmd_name, *cmd_params, read_write: :READ_WRITE, index: -1, scope:)
|
100
100
|
data = {}
|
101
101
|
data['cmd_name'] = cmd_name
|
102
102
|
data['cmd_params'] = cmd_params
|
@@ -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/topics/topic'
|
@@ -56,5 +56,14 @@ module OpenC3
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|
59
|
+
|
60
|
+
def self.inject_tlm(target_name, packet_name, item_hash = nil, type: :CONVERTED, scope:)
|
61
|
+
data = {}
|
62
|
+
data['target_name'] = target_name.to_s.upcase
|
63
|
+
data['packet_name'] = packet_name.to_s.upcase
|
64
|
+
data['item_hash'] = item_hash
|
65
|
+
data['type'] = type
|
66
|
+
Topic.write_topic("#{scope}__DECOMINTERFACE__{#{target_name}}", { 'inject_tlm' => JSON.generate(data, allow_nan: true) }, '*', 100)
|
67
|
+
end
|
59
68
|
end
|
60
69
|
end
|
@@ -60,15 +60,22 @@ module OpenC3
|
|
60
60
|
Thread.new do
|
61
61
|
client = Bucket.getClient()
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
orig_filename = nil
|
64
|
+
if File.extname(filename) != '.txt'
|
65
|
+
orig_filename = filename
|
66
|
+
filename = compress_file(filename)
|
67
|
+
bucket_key += '.gz'
|
68
|
+
end
|
69
|
+
# We want to open this as a file and pass that to put_object to allow
|
70
|
+
# this to work with really large files. Otherwise the entire file has
|
71
|
+
# to be held in memory!
|
72
|
+
File.open(filename, 'rb') do |file|
|
73
|
+
client.put_object(bucket: ENV['OPENC3_LOGS_BUCKET'], key: bucket_key, body: file, metadata: metadata)
|
67
74
|
end
|
68
75
|
Logger.debug "wrote #{ENV['OPENC3_LOGS_BUCKET']}/#{bucket_key}"
|
69
76
|
ReducerModel.add_file(bucket_key) # Record the new file for data reduction
|
70
77
|
|
71
|
-
File.delete(
|
78
|
+
File.delete(orig_filename) if orig_filename
|
72
79
|
File.delete(filename)
|
73
80
|
rescue => err
|
74
81
|
Logger.error("Error saving log file to bucket: #{filename}\n#{err.formatted}")
|
@@ -18,7 +18,7 @@
|
|
18
18
|
|
19
19
|
module OpenC3
|
20
20
|
class CliGenerator
|
21
|
-
GENERATORS = %w(plugin target microservice conversion limits_response)
|
21
|
+
GENERATORS = %w(plugin target microservice widget conversion limits_response)
|
22
22
|
TEMPLATES_DIR = "#{File.dirname(__FILE__)}/../../../templates"
|
23
23
|
|
24
24
|
# Called by openc3cli with ARGV[1..-1]
|
@@ -43,11 +43,12 @@ module OpenC3
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def self.process_template(template_dir, the_binding)
|
46
|
-
Dir.glob("#{template_dir}/**/*").each do |file|
|
46
|
+
Dir.glob("#{template_dir}/**/*", File::FNM_DOTMATCH).each do |file|
|
47
|
+
next if File.basename(file) == '.'
|
47
48
|
base_name = file.sub("#{template_dir}/", '')
|
48
|
-
yield base_name
|
49
|
+
next if yield base_name
|
49
50
|
if File.directory?(file)
|
50
|
-
FileUtils.mkdir(base_name)
|
51
|
+
FileUtils.mkdir(base_name) unless File.exist?(base_name)
|
51
52
|
next
|
52
53
|
end
|
53
54
|
output = ERB.new(File.read(file), trim_mode: "-").result(the_binding)
|
@@ -73,6 +74,7 @@ module OpenC3
|
|
73
74
|
|
74
75
|
process_template("#{TEMPLATES_DIR}/plugin", binding) do |filename|
|
75
76
|
filename.sub!("plugin.gemspec", "#{plugin_name}.gemspec")
|
77
|
+
false
|
76
78
|
end
|
77
79
|
|
78
80
|
puts "Plugin #{plugin_name} successfully generated!"
|
@@ -98,6 +100,7 @@ module OpenC3
|
|
98
100
|
# Rename the template TARGET to our actual target named after the plugin
|
99
101
|
filename.sub!("targets/TARGET", "targets/#{target_name}")
|
100
102
|
filename.sub!("target.rb", target_lib_filename)
|
103
|
+
false
|
101
104
|
end
|
102
105
|
|
103
106
|
# Add this target to plugin.txt
|
@@ -134,6 +137,7 @@ module OpenC3
|
|
134
137
|
# Rename the template MICROSERVICE to our actual microservice name
|
135
138
|
filename.sub!("microservices/TEMPLATE", "microservices/#{microservice_name}")
|
136
139
|
filename.sub!("microservice.rb", microservice_filename)
|
140
|
+
false
|
137
141
|
end
|
138
142
|
|
139
143
|
# Add this microservice to plugin.txt
|
@@ -149,6 +153,52 @@ module OpenC3
|
|
149
153
|
return microservice_name
|
150
154
|
end
|
151
155
|
|
156
|
+
def self.generate_widget(args)
|
157
|
+
if args.length != 2
|
158
|
+
abort("Usage: cli generate #{args[0]} <SuperdataWidget>")
|
159
|
+
end
|
160
|
+
# Per https://stackoverflow.com/a/47591707/453280
|
161
|
+
if args[1] !~ /.*Widget$/ or args[1][0...-6] != args[1][0...-6].capitalize
|
162
|
+
abort("Widget name should be Uppercase followed by Widget, e.g. SuperdataWidget. Found '#{args[1]}'.")
|
163
|
+
end
|
164
|
+
|
165
|
+
# Create the local variables
|
166
|
+
widget_name = args[1]
|
167
|
+
widget_filename = "#{widget_name}.vue"
|
168
|
+
widget_path = "src/#{widget_filename}"
|
169
|
+
if File.exist?(widget_path)
|
170
|
+
abort("Widget #{widget_path} already exists!")
|
171
|
+
end
|
172
|
+
skip_package = false
|
173
|
+
if File.exist?('package.json')
|
174
|
+
puts "package.json already exists ... you'll have to manually add this widget to the end of the \"build\" script."
|
175
|
+
skip_package = true
|
176
|
+
end
|
177
|
+
|
178
|
+
process_template("#{TEMPLATES_DIR}/widget", binding) do |filename|
|
179
|
+
if skip_package && filename == 'package.json'
|
180
|
+
true # causes the block to skip processing this file
|
181
|
+
elsif filename.include?('node_modules')
|
182
|
+
true
|
183
|
+
else
|
184
|
+
filename.sub!("Widget.vue", widget_filename)
|
185
|
+
false
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Add this widget to plugin.txt but remove Widget from the name
|
190
|
+
File.open("plugin.txt", 'a') do |file|
|
191
|
+
file.puts <<~DOC
|
192
|
+
|
193
|
+
WIDGET #{widget_name[0...-6]}
|
194
|
+
DOC
|
195
|
+
end
|
196
|
+
|
197
|
+
puts "Widget #{widget_name} successfully generated!"
|
198
|
+
puts "Please be sure #{widget_name} does not overlap an existing widget: https://openc3.com/docs/v5/telemetry-screens"
|
199
|
+
return widget_name
|
200
|
+
end
|
201
|
+
|
152
202
|
def self.generate_conversion(args)
|
153
203
|
if args.length != 3
|
154
204
|
abort("Usage: cli generate conversion <TARGET> <NAME>")
|
@@ -170,6 +220,7 @@ module OpenC3
|
|
170
220
|
|
171
221
|
process_template("#{TEMPLATES_DIR}/conversion", binding) do |filename|
|
172
222
|
filename.sub!("conversion.rb", conversion_filename)
|
223
|
+
false
|
173
224
|
end
|
174
225
|
|
175
226
|
puts "Conversion #{conversion_filename} successfully generated!"
|
@@ -199,6 +250,7 @@ module OpenC3
|
|
199
250
|
|
200
251
|
process_template("#{TEMPLATES_DIR}/limits_response", binding) do |filename|
|
201
252
|
filename.sub!("response.rb", response_filename)
|
253
|
+
false
|
202
254
|
end
|
203
255
|
|
204
256
|
puts "Limits response #{response_filename} successfully generated!"
|