openc3 5.15.1 → 5.16.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/Gemfile +1 -1
- data/Rakefile +1 -0
- data/bin/openc3cli +20 -0
- data/bin/pipinstall +3 -0
- data/data/config/interface_modifiers.yaml +4 -1
- data/data/config/telemetry_modifiers.yaml +6 -1
- data/data/config/widgets.yaml +1 -1
- data/ext/openc3/ext/burst_protocol/burst_protocol.c +317 -0
- data/ext/openc3/ext/burst_protocol/extconf.rb +13 -0
- data/lib/openc3/accessors/accessor.rb +1 -1
- data/lib/openc3/accessors/json_accessor.rb +11 -3
- data/lib/openc3/api/tlm_api.rb +1 -1
- data/lib/openc3/interfaces/http_client_interface.rb +8 -4
- data/lib/openc3/interfaces/http_server_interface.rb +22 -6
- data/lib/openc3/interfaces/interface.rb +6 -0
- data/lib/openc3/interfaces/linc_interface.rb +5 -3
- data/lib/openc3/interfaces/mqtt_interface.rb +7 -3
- data/lib/openc3/interfaces/mqtt_stream_interface.rb +8 -1
- data/lib/openc3/interfaces/protocols/burst_protocol.rb +104 -100
- data/lib/openc3/interfaces/protocols/fixed_protocol.rb +11 -3
- data/lib/openc3/interfaces/serial_interface.rb +16 -1
- data/lib/openc3/interfaces/simulated_target_interface.rb +7 -3
- data/lib/openc3/interfaces/tcpip_client_interface.rb +18 -1
- data/lib/openc3/interfaces/tcpip_server_interface.rb +24 -15
- data/lib/openc3/interfaces/udp_interface.rb +11 -1
- data/lib/openc3/io/posix_serial_driver.rb +20 -5
- data/lib/openc3/logs/packet_log_writer.rb +1 -1
- data/lib/openc3/microservices/decom_microservice.rb +3 -2
- data/lib/openc3/microservices/interface_microservice.rb +5 -5
- data/lib/openc3/models/activity_model.rb +104 -40
- data/lib/openc3/models/gem_model.rb +1 -1
- data/lib/openc3/models/plugin_model.rb +5 -3
- data/lib/openc3/models/python_package_model.rb +15 -5
- data/lib/openc3/models/scope_model.rb +1 -1
- data/lib/openc3/models/target_model.rb +1 -1
- data/lib/openc3/packets/packet.rb +27 -24
- data/lib/openc3/packets/packet_config.rb +18 -1
- data/lib/openc3/packets/parsers/packet_item_parser.rb +10 -6
- data/lib/openc3/packets/structure.rb +7 -7
- data/lib/openc3/packets/structure_item.rb +4 -2
- data/lib/openc3/script/api_shared.rb +33 -29
- data/lib/openc3/script/plugins.rb +13 -13
- data/lib/openc3/script/storage.rb +3 -4
- data/lib/openc3/script/web_socket_api.rb +10 -0
- data/lib/openc3/version.rb +6 -6
- data/templates/target/targets/TARGET/lib/target.py +2 -0
- data/templates/tool_angular/package.json +8 -8
- data/templates/tool_react/package.json +2 -2
- data/templates/tool_svelte/build/smui.css +1 -5
- data/templates/tool_svelte/package.json +3 -3
- data/templates/tool_vue/package.json +12 -12
- data/templates/widget/package.json +11 -11
- metadata +21 -18
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
|
3
|
-
# Copyright
|
3
|
+
# Copyright 2024 OpenC3, Inc.
|
4
4
|
# All Rights Reserved.
|
5
5
|
#
|
6
6
|
# This program is free software; you can modify and/or redistribute it
|
@@ -108,8 +108,8 @@ module OpenC3
|
|
108
108
|
|
109
109
|
# Build list of packets by topic
|
110
110
|
@read_packets_by_topic = {}
|
111
|
-
System.telemetry.all.each do |
|
112
|
-
target_packets.each do |
|
111
|
+
System.telemetry.all.each do |_target_name, target_packets|
|
112
|
+
target_packets.each do |_packet_name, packet|
|
113
113
|
topics = packet.meta['TOPIC']
|
114
114
|
topics = packet.meta['TOPICS'] unless topics
|
115
115
|
if topics
|
@@ -121,6 +121,10 @@ module OpenC3
|
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
124
|
+
def connection_string
|
125
|
+
return "#{@hostname}:#{@port} (ssl: #{@ssl})"
|
126
|
+
end
|
127
|
+
|
124
128
|
# Connects the interface to its target(s)
|
125
129
|
def connect
|
126
130
|
@write_topics = []
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
|
3
|
-
# Copyright
|
3
|
+
# Copyright 2024 OpenC3, Inc.
|
4
4
|
# All Rights Reserved.
|
5
5
|
#
|
6
6
|
# This program is free software; you can modify and/or redistribute it
|
@@ -38,6 +38,13 @@ module OpenC3
|
|
38
38
|
@ca_file = nil
|
39
39
|
end
|
40
40
|
|
41
|
+
def connection_string
|
42
|
+
result = "#{@hostname}:#{@port} (ssl: #{@ssl})"
|
43
|
+
result += " write topic: #{@write_topic}" if @write_topic
|
44
|
+
result += " read topic: #{@read_topic}" if @read_topic
|
45
|
+
return result
|
46
|
+
end
|
47
|
+
|
41
48
|
# Creates a new {SerialStream} using the parameters passed in the constructor
|
42
49
|
def connect
|
43
50
|
@stream = MqttStream.new(@hostname, @port, @ssl, @write_topic, @read_topic)
|
@@ -22,7 +22,7 @@
|
|
22
22
|
|
23
23
|
require 'openc3/config/config_parser'
|
24
24
|
require 'openc3/interfaces/protocols/protocol'
|
25
|
-
require '
|
25
|
+
require 'openc3/ext/burst_protocol' if RUBY_ENGINE == 'ruby' and !ENV['OPENC3_NO_EXT']
|
26
26
|
|
27
27
|
module OpenC3
|
28
28
|
# Reads all data available on the interface and creates a packet
|
@@ -51,50 +51,116 @@ module OpenC3
|
|
51
51
|
@sync_state = :SEARCHING
|
52
52
|
end
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
@
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
54
|
+
if RUBY_ENGINE != 'ruby' or ENV['OPENC3_NO_EXT']
|
55
|
+
|
56
|
+
# Reads from the interface. It can look for a sync pattern before
|
57
|
+
# creating a Packet. It can discard a set number of bytes at the beginning
|
58
|
+
# before creating the Packet.
|
59
|
+
#
|
60
|
+
# Note: On the first call to this from any interface read(), data will contain a blank
|
61
|
+
# string. Blank string is an opportunity for protocols to return any queued up packets.
|
62
|
+
# If they have no queued up packets, they should pass the blank string down to chained
|
63
|
+
# protocols giving them the same opportunity.
|
64
|
+
#
|
65
|
+
# @return [String|nil] Data for a packet consisting of the bytes read
|
66
|
+
def read_data(data, extra = nil)
|
67
|
+
@data << data
|
68
|
+
@extra = extra
|
69
|
+
|
70
|
+
while true
|
71
|
+
control = handle_sync_pattern()
|
72
|
+
return control if control and data.length > 0 # Only return here if not blank string test
|
73
|
+
|
74
|
+
# Reduce the data to a single packet
|
75
|
+
packet_data, extra = reduce_to_single_packet()
|
76
|
+
if packet_data == :RESYNC
|
77
|
+
@sync_state = :SEARCHING
|
78
|
+
next if data.length > 0 # Only immediately resync if not blank string test
|
79
|
+
end
|
80
|
+
|
81
|
+
# Potentially allow blank string to be sent to other protocols if no packet is ready in this one
|
82
|
+
if Symbol === packet_data
|
83
|
+
if (data.length <= 0) and packet_data != :DISCONNECT
|
84
|
+
# On blank string test, return blank string (unless we had a packet or need disconnect)
|
85
|
+
# The base class handles the special case of returning STOP if on the last protocol in the
|
86
|
+
# chain
|
87
|
+
return super(data, extra)
|
88
|
+
else
|
89
|
+
return packet_data, extra # Return any control code if not on blank string test
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
75
93
|
@sync_state = :SEARCHING
|
76
|
-
|
94
|
+
|
95
|
+
# Discard leading bytes if necessary
|
96
|
+
packet_data.replace(packet_data[@discard_leading_bytes..-1]) if @discard_leading_bytes > 0
|
97
|
+
return packet_data, extra
|
77
98
|
end
|
99
|
+
end
|
78
100
|
|
79
|
-
|
80
|
-
if
|
81
|
-
|
82
|
-
|
83
|
-
# The base class handles the special case of returning STOP if on the last protocol in the
|
84
|
-
# chain
|
85
|
-
return super(data, extra)
|
86
|
-
else
|
87
|
-
return packet_data, extra # Return any control code if not on blank string test
|
88
|
-
end
|
101
|
+
def reduce_to_single_packet
|
102
|
+
if @data.length <= 0
|
103
|
+
# Need some data
|
104
|
+
return :STOP
|
89
105
|
end
|
90
106
|
|
91
|
-
|
107
|
+
# Reduce to packet data and clear data for next packet
|
108
|
+
packet_data = @data.clone
|
109
|
+
@data.replace('')
|
110
|
+
return packet_data, @extra
|
111
|
+
end
|
112
|
+
|
113
|
+
# @return [Boolean] control code (nil, :STOP)
|
114
|
+
def handle_sync_pattern
|
115
|
+
if @sync_pattern and @sync_state == :SEARCHING
|
116
|
+
loop do
|
117
|
+
# Make sure we have some data to look for a sync word in
|
118
|
+
return :STOP if @data.length < @sync_pattern.length
|
119
|
+
|
120
|
+
# Find the beginning of the sync pattern
|
121
|
+
sync_index = @data.index(@sync_pattern.getbyte(0).chr)
|
122
|
+
if sync_index
|
123
|
+
# Make sure we have enough data for the whole sync pattern past this index
|
124
|
+
return :STOP if @data.length < (sync_index + @sync_pattern.length)
|
125
|
+
|
126
|
+
# Check for the rest of the sync pattern
|
127
|
+
found = true
|
128
|
+
index = sync_index
|
129
|
+
@sync_pattern.each_byte do |byte|
|
130
|
+
if @data.getbyte(index) != byte
|
131
|
+
found = false
|
132
|
+
break
|
133
|
+
end
|
134
|
+
index += 1
|
135
|
+
end
|
92
136
|
|
93
|
-
|
94
|
-
|
95
|
-
|
137
|
+
if found
|
138
|
+
if sync_index != 0
|
139
|
+
log_discard(sync_index, true)
|
140
|
+
# Delete Data Before Sync Pattern
|
141
|
+
@data.replace(@data[sync_index..-1])
|
142
|
+
end
|
143
|
+
@sync_state = :FOUND
|
144
|
+
return nil
|
145
|
+
|
146
|
+
else # not found
|
147
|
+
log_discard(sync_index + 1, false)
|
148
|
+
# Delete Data Before and including first character of suspected sync Pattern
|
149
|
+
@data.replace(@data[(sync_index + 1)..-1])
|
150
|
+
next
|
151
|
+
end # if found
|
152
|
+
|
153
|
+
else # sync_index = nil
|
154
|
+
log_discard(@data.length, false)
|
155
|
+
@data.replace('')
|
156
|
+
return :STOP
|
157
|
+
end # unless sync_index.nil?
|
158
|
+
end # end loop
|
159
|
+
end # if @sync_pattern
|
160
|
+
nil
|
96
161
|
end
|
97
|
-
|
162
|
+
|
163
|
+
end # if RUBY_ENGINE != 'ruby' or ENV['OPENC3_NO_EXT']
|
98
164
|
|
99
165
|
# Called to perform modifications on a command packet before it is sent
|
100
166
|
#
|
@@ -131,56 +197,6 @@ module OpenC3
|
|
131
197
|
return super(data, extra)
|
132
198
|
end
|
133
199
|
|
134
|
-
# @return [Boolean] control code (nil, :STOP)
|
135
|
-
def handle_sync_pattern
|
136
|
-
if @sync_pattern and @sync_state == :SEARCHING
|
137
|
-
loop do
|
138
|
-
# Make sure we have some data to look for a sync word in
|
139
|
-
return :STOP if @data.length < @sync_pattern.length
|
140
|
-
|
141
|
-
# Find the beginning of the sync pattern
|
142
|
-
sync_index = @data.index(@sync_pattern.getbyte(0).chr)
|
143
|
-
if sync_index
|
144
|
-
# Make sure we have enough data for the whole sync pattern past this index
|
145
|
-
return :STOP if @data.length < (sync_index + @sync_pattern.length)
|
146
|
-
|
147
|
-
# Check for the rest of the sync pattern
|
148
|
-
found = true
|
149
|
-
index = sync_index
|
150
|
-
@sync_pattern.each_byte do |byte|
|
151
|
-
if @data.getbyte(index) != byte
|
152
|
-
found = false
|
153
|
-
break
|
154
|
-
end
|
155
|
-
index += 1
|
156
|
-
end
|
157
|
-
|
158
|
-
if found
|
159
|
-
if sync_index != 0
|
160
|
-
log_discard(sync_index, true)
|
161
|
-
# Delete Data Before Sync Pattern
|
162
|
-
@data.replace(@data[sync_index..-1])
|
163
|
-
end
|
164
|
-
@sync_state = :FOUND
|
165
|
-
return nil
|
166
|
-
|
167
|
-
else # not found
|
168
|
-
log_discard(sync_index + 1, false)
|
169
|
-
# Delete Data Before and including first character of suspected sync Pattern
|
170
|
-
@data.replace(@data[(sync_index + 1)..-1])
|
171
|
-
next
|
172
|
-
end # if found
|
173
|
-
|
174
|
-
else # sync_index = nil
|
175
|
-
log_discard(@data.length, false)
|
176
|
-
@data.replace('')
|
177
|
-
return :STOP
|
178
|
-
end # unless sync_index.nil?
|
179
|
-
end # end loop
|
180
|
-
end # if @sync_pattern
|
181
|
-
nil
|
182
|
-
end
|
183
|
-
|
184
200
|
def log_discard(length, found)
|
185
201
|
Logger.error("#{@interface ? @interface.name : ""}: Sync #{'not ' unless found}found. Discarding #{length} bytes of data.")
|
186
202
|
if @data.length >= 0
|
@@ -193,17 +209,5 @@ module OpenC3
|
|
193
209
|
@data.length >= 6 ? @data.getbyte(5) : 0))
|
194
210
|
end
|
195
211
|
end
|
196
|
-
|
197
|
-
def reduce_to_single_packet
|
198
|
-
if @data.length <= 0
|
199
|
-
# Need some data
|
200
|
-
return :STOP
|
201
|
-
end
|
202
|
-
|
203
|
-
# Reduce to packet data and clear data for next packet
|
204
|
-
packet_data = @data.clone
|
205
|
-
@data.replace('')
|
206
|
-
return packet_data, @extra
|
207
|
-
end
|
208
212
|
end
|
209
213
|
end
|
@@ -102,7 +102,7 @@ module OpenC3
|
|
102
102
|
end
|
103
103
|
|
104
104
|
if unique_id_mode
|
105
|
-
target_packets.each do |
|
105
|
+
target_packets.each do |_packet_name, packet|
|
106
106
|
if packet.identify?(@data[@discard_leading_bytes..-1])
|
107
107
|
identified_packet = packet
|
108
108
|
break
|
@@ -136,7 +136,15 @@ module OpenC3
|
|
136
136
|
@packet_name = identified_packet.packet_name
|
137
137
|
|
138
138
|
# Get the data from this packet
|
139
|
-
|
139
|
+
# Previous implementation looked like the following:
|
140
|
+
# packet_data = @data.slice!(0, identified_packet.defined_length + @discard_leading_bytes)
|
141
|
+
# But slice! is 6x slower at small packets (1024)
|
142
|
+
# and 1000x slower at large packets (1Mb)
|
143
|
+
# Run test/benchmarks/string_mod_benchmark.rb for details
|
144
|
+
|
145
|
+
# Triple dot range because it's effectively a length calculation and we start with 0
|
146
|
+
packet_data = @data[0...(identified_packet.defined_length + @discard_leading_bytes)]
|
147
|
+
@data = @data[(identified_packet.defined_length + @discard_leading_bytes)..-1]
|
140
148
|
break
|
141
149
|
end
|
142
150
|
end
|
@@ -152,7 +160,7 @@ module OpenC3
|
|
152
160
|
@data.replace('')
|
153
161
|
end
|
154
162
|
|
155
|
-
return packet_data
|
163
|
+
return packet_data, @extra
|
156
164
|
end
|
157
165
|
|
158
166
|
def reduce_to_single_packet
|
@@ -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 2024, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
#
|
20
20
|
# This file may also be used under the terms of a commercial license
|
@@ -65,6 +65,21 @@ module OpenC3
|
|
65
65
|
@data_bits = 8
|
66
66
|
end
|
67
67
|
|
68
|
+
def connection_string
|
69
|
+
type = ''
|
70
|
+
if @write_port_name and @read_port_name
|
71
|
+
port = @write_port_name
|
72
|
+
type = 'R/W'
|
73
|
+
elsif @write_port_name
|
74
|
+
port = @write_port_name
|
75
|
+
type = 'write only'
|
76
|
+
else
|
77
|
+
port = @read_port_name
|
78
|
+
type = 'read only'
|
79
|
+
end
|
80
|
+
return "#{port} (#{type}) #{@baud_rate} #{@parity} #{@stop_bits}"
|
81
|
+
end
|
82
|
+
|
68
83
|
# Creates a new {SerialStream} using the parameters passed in the constructor
|
69
84
|
def connect
|
70
85
|
@stream = SerialStream.new(
|
@@ -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 2024, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
#
|
20
20
|
# This file may also be used under the terms of a commercial license
|
@@ -38,6 +38,10 @@ module OpenC3
|
|
38
38
|
@write_raw_allowed = false
|
39
39
|
end
|
40
40
|
|
41
|
+
def connection_string
|
42
|
+
return @sim_target_class.to_s
|
43
|
+
end
|
44
|
+
|
41
45
|
# Initialize the simulated target object and "connect" to the target
|
42
46
|
def connect
|
43
47
|
unless @initialized
|
@@ -139,12 +143,12 @@ module OpenC3
|
|
139
143
|
end
|
140
144
|
|
141
145
|
# write_raw is not implemented and will raise a RuntimeError
|
142
|
-
def write_raw(
|
146
|
+
def write_raw(_data)
|
143
147
|
raise "write_raw not implemented for SimulatedTargetInterface"
|
144
148
|
end
|
145
149
|
|
146
150
|
# Raise an error because raw logging is not supported for this interface
|
147
|
-
def stream_log_pair=(
|
151
|
+
def stream_log_pair=(_stream_log_pair)
|
148
152
|
raise "Raw logging not supported for SimulatedTargetInterface"
|
149
153
|
end
|
150
154
|
|
@@ -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 2024, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
#
|
20
20
|
# This file may also be used under the terms of a commercial license
|
@@ -57,6 +57,23 @@ module OpenC3
|
|
57
57
|
@write_raw_allowed = false unless @write_port
|
58
58
|
end
|
59
59
|
|
60
|
+
def connection_string
|
61
|
+
# Probably most common is write == read so handle that
|
62
|
+
if @write_port == @read_port
|
63
|
+
return "#{@hostname}:#{@write_port} (R/W)"
|
64
|
+
end
|
65
|
+
|
66
|
+
result = ''
|
67
|
+
if @write_port
|
68
|
+
result += "#{@hostname}:#{@write_port} (write)"
|
69
|
+
end
|
70
|
+
if @read_port
|
71
|
+
result += ' ' if result.length != 0
|
72
|
+
result += "#{@hostname}:#{@read_port} (read)"
|
73
|
+
end
|
74
|
+
return result
|
75
|
+
end
|
76
|
+
|
60
77
|
# Connects the {TcpipClientStream} by passing the
|
61
78
|
# initialization parameters to the {TcpipClientStream}.
|
62
79
|
def connect
|
@@ -14,14 +14,13 @@
|
|
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 2024, 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
|
require 'socket'
|
24
|
-
require 'thread' # For Mutex
|
25
24
|
require 'timeout' # For Timeout::Error
|
26
25
|
require 'openc3/interfaces/stream_interface'
|
27
26
|
require 'openc3/streams/tcpip_socket_stream'
|
@@ -119,6 +118,16 @@ module OpenC3
|
|
119
118
|
@connected = false
|
120
119
|
end
|
121
120
|
|
121
|
+
def connection_string
|
122
|
+
if @write_port == @read_port
|
123
|
+
return "listening on #{@listen_address}:#{@write_port} (R/W)"
|
124
|
+
end
|
125
|
+
result = "listening on"
|
126
|
+
result += " #{@listen_address}:#{@write_port} (write)" if @write_port
|
127
|
+
result += " #{@listen_address}:#{@read_port} (read)" if @read_port
|
128
|
+
return result
|
129
|
+
end
|
130
|
+
|
122
131
|
# Create the read and write port listen threads. Incoming connections will
|
123
132
|
# spawn separate threads to process the reads and writes.
|
124
133
|
def connect
|
@@ -137,20 +146,20 @@ module OpenC3
|
|
137
146
|
write_thread_body()
|
138
147
|
break if @cancel_threads
|
139
148
|
end
|
140
|
-
rescue Exception =>
|
149
|
+
rescue Exception => e
|
141
150
|
shutdown_interfaces(@write_interface_infos)
|
142
151
|
Logger.error("#{@name}: Tcpip server write thread unexpectedly died")
|
143
|
-
Logger.error(
|
152
|
+
Logger.error(e.formatted)
|
144
153
|
end
|
145
154
|
@write_raw_thread = Thread.new do
|
146
155
|
loop do
|
147
156
|
write_raw_thread_body()
|
148
157
|
break if @cancel_threads
|
149
158
|
end
|
150
|
-
rescue Exception =>
|
159
|
+
rescue Exception => e
|
151
160
|
shutdown_interfaces(@write_interface_infos)
|
152
161
|
Logger.error("#{@name}: Tcpip server write raw thread unexpectedly died")
|
153
|
-
Logger.error(
|
162
|
+
Logger.error(e.formatted)
|
154
163
|
end
|
155
164
|
else
|
156
165
|
@write_thread = nil
|
@@ -350,9 +359,9 @@ module OpenC3
|
|
350
359
|
listen_thread_body(listen_socket, listen_write, listen_read, thread_reader)
|
351
360
|
break if @cancel_threads
|
352
361
|
end
|
353
|
-
rescue =>
|
362
|
+
rescue => e
|
354
363
|
Logger.error("#{@name}: Tcpip server listen thread unexpectedly died")
|
355
|
-
Logger.error(
|
364
|
+
Logger.error(e.formatted)
|
356
365
|
end
|
357
366
|
end
|
358
367
|
|
@@ -432,9 +441,9 @@ module OpenC3
|
|
432
441
|
begin
|
433
442
|
begin
|
434
443
|
read_thread_body(interface_info.interface)
|
435
|
-
rescue Exception =>
|
444
|
+
rescue Exception => e
|
436
445
|
Logger.error "#{@name}: Tcpip server read thread unexpectedly died"
|
437
|
-
Logger.error
|
446
|
+
Logger.error e.formatted
|
438
447
|
end
|
439
448
|
Logger.info "#{@name}: Tcpip server lost read connection to #{interface_info.hostname}(#{interface_info.host_ip}):#{interface_info.port}"
|
440
449
|
@read_threads.delete(Thread.current)
|
@@ -456,9 +465,9 @@ module OpenC3
|
|
456
465
|
@read_interface_infos.delete_at(index_to_delete)
|
457
466
|
end
|
458
467
|
end
|
459
|
-
rescue Exception =>
|
468
|
+
rescue Exception => e
|
460
469
|
Logger.error "#{@name}: Tcpip server read thread unexpectedly died"
|
461
|
-
Logger.error
|
470
|
+
Logger.error e.formatted
|
462
471
|
end
|
463
472
|
end
|
464
473
|
end
|
@@ -596,9 +605,9 @@ module OpenC3
|
|
596
605
|
rescue Errno::EPIPE, Errno::ECONNABORTED, IOError, Errno::ECONNRESET
|
597
606
|
# Client has normally disconnected
|
598
607
|
need_disconnect = true
|
599
|
-
rescue Exception =>
|
600
|
-
if
|
601
|
-
Logger.error "#{@name}: Error sending to client: #{
|
608
|
+
rescue Exception => e
|
609
|
+
if e.message != "Stream not connected for write_raw"
|
610
|
+
Logger.error "#{@name}: Error sending to client: #{e.class} #{e.message}"
|
602
611
|
end
|
603
612
|
need_disconnect = true
|
604
613
|
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 2024, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
#
|
20
20
|
# This file may also be used under the terms of a commercial license
|
@@ -90,6 +90,16 @@ module OpenC3
|
|
90
90
|
@write_raw_allowed = false unless @write_dest_port
|
91
91
|
end
|
92
92
|
|
93
|
+
def connection_string
|
94
|
+
result = ''
|
95
|
+
result += " #{@hostname}:#{@write_dest_port} (write dest port)" if @write_dest_port
|
96
|
+
result += " #{@write_src_port} (write src port)" if @write_src_port
|
97
|
+
result += " #{@hostname}:#{@read_port} (read)" if @read_port
|
98
|
+
result += " #{@interface_address} (interface addr)" if @interface_address
|
99
|
+
result += " #{@bind_address} (bind addr)" if @bind_address != '0.0.0.0'
|
100
|
+
return result.strip
|
101
|
+
end
|
102
|
+
|
93
103
|
# Creates a new {UdpWriteSocket} if the the write_dest_port was given in
|
94
104
|
# the constructor and a new {UdpReadSocket} if the read_port was given in
|
95
105
|
# the constructor.
|
@@ -14,10 +14,10 @@
|
|
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 2024, 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 'fcntl'
|
@@ -82,12 +82,17 @@ module OpenC3
|
|
82
82
|
tio.ospeed = baud_rate
|
83
83
|
@handle.tcflush(Termios::TCIOFLUSH)
|
84
84
|
@handle.tcsetattr(Termios::TCSANOW, tio)
|
85
|
+
|
86
|
+
@pipe_reader, @pipe_writer = IO.pipe
|
87
|
+
@readers = [@handle, @pipe_reader]
|
85
88
|
end
|
86
89
|
|
87
90
|
# (see SerialDriver#close)
|
88
91
|
def close
|
89
92
|
if @handle
|
90
93
|
# Close the serial Port
|
94
|
+
@pipe_writer.write('.')
|
95
|
+
@pipe_writer.close
|
91
96
|
@handle.close
|
92
97
|
@handle = nil
|
93
98
|
end
|
@@ -132,9 +137,19 @@ module OpenC3
|
|
132
137
|
begin
|
133
138
|
data = @handle.read_nonblock(65535)
|
134
139
|
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
|
135
|
-
|
136
|
-
|
137
|
-
|
140
|
+
begin
|
141
|
+
read_ready, _ = IO.fast_select(@readers, nil, nil, @read_timeout)
|
142
|
+
rescue IOError
|
143
|
+
@pipe_reader.close unless @pipe_reader.closed?
|
144
|
+
return ""
|
145
|
+
end
|
146
|
+
if read_ready
|
147
|
+
if read_ready.include?(@pipe_reader)
|
148
|
+
@pipe_reader.close unless @pipe_reader.closed?
|
149
|
+
return ""
|
150
|
+
else
|
151
|
+
retry
|
152
|
+
end
|
138
153
|
else
|
139
154
|
raise Timeout::Error, "Read Timeout"
|
140
155
|
end
|
@@ -331,7 +331,7 @@ module OpenC3
|
|
331
331
|
@entry << [length, flags, packet_index, time_nsec_since_epoch].pack(OPENC3_PACKET_PACK_DIRECTIVE)
|
332
332
|
@entry << [received_time_nsec_since_epoch].pack(OPENC3_RECEIVED_TIME_PACK_DIRECTIVE) if received_time_nsec_since_epoch
|
333
333
|
@entry << [extra_encoded.length].pack(OPENC3_EXTRA_LENGTH_PACK_DIRECTIVE) << extra_encoded if extra_encoded
|
334
|
-
@entry << data
|
334
|
+
@entry << data.force_encoding('ASCII-8BIT')
|
335
335
|
@first_time = time_nsec_since_epoch if !@first_time or time_nsec_since_epoch < @first_time
|
336
336
|
@last_time = time_nsec_since_epoch if !@last_time or time_nsec_since_epoch > @last_time
|
337
337
|
else
|
@@ -81,7 +81,7 @@ module OpenC3
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
def decom_packet(
|
84
|
+
def decom_packet(_topic, msg_id, msg_hash, _redis)
|
85
85
|
OpenC3.in_span("decom_packet") do
|
86
86
|
msgid_seconds_from_epoch = msg_id.split('-')[0].to_i / 1000.0
|
87
87
|
delta = Time.now.to_f - msgid_seconds_from_epoch
|
@@ -133,7 +133,8 @@ module OpenC3
|
|
133
133
|
if log_change
|
134
134
|
case item.limits.state
|
135
135
|
when :BLUE, :GREEN, :GREEN_LOW, :GREEN_HIGH
|
136
|
-
|
136
|
+
# Only print INFO messages if we're changing ... not on initialization
|
137
|
+
@logger.info message if old_limits_state
|
137
138
|
when :YELLOW, :YELLOW_LOW, :YELLOW_HIGH
|
138
139
|
@logger.warn(message, type: Logger::NOTIFICATION)
|
139
140
|
when :RED, :RED_LOW, :RED_HIGH
|
@@ -450,7 +450,7 @@ module OpenC3
|
|
450
450
|
@interface # Return the interface/router since we may have recreated it
|
451
451
|
# Need to rescue Exception so we cover LoadError
|
452
452
|
rescue Exception => e
|
453
|
-
@logger.error("Attempting connection
|
453
|
+
@logger.error("Attempting connection #{@interface.connection_string} failed due to #{e.message}")
|
454
454
|
if SignalException === e
|
455
455
|
@logger.info "#{@interface.name}: Closing from signal"
|
456
456
|
@cancel_thread = true
|
@@ -479,7 +479,7 @@ module OpenC3
|
|
479
479
|
connect() unless @cancel_thread
|
480
480
|
end
|
481
481
|
rescue Exception => e
|
482
|
-
handle_connection_failed(e)
|
482
|
+
handle_connection_failed(@interface.connection_string, e)
|
483
483
|
break if @cancel_thread
|
484
484
|
end
|
485
485
|
when 'CONNECTED'
|
@@ -580,9 +580,9 @@ module OpenC3
|
|
580
580
|
TelemetryTopic.write_packet(packet, queued: @queued, scope: @scope)
|
581
581
|
end
|
582
582
|
|
583
|
-
def handle_connection_failed(connect_error)
|
583
|
+
def handle_connection_failed(connection, connect_error)
|
584
584
|
@error = connect_error
|
585
|
-
@logger.error "#{@interface.name}: Connection
|
585
|
+
@logger.error "#{@interface.name}: Connection #{connection} failed due to #{connect_error.formatted(false, false)}"
|
586
586
|
case connect_error
|
587
587
|
when SignalException
|
588
588
|
@logger.info "#{@interface.name}: Closing from signal"
|
@@ -627,7 +627,7 @@ module OpenC3
|
|
627
627
|
end
|
628
628
|
|
629
629
|
def connect
|
630
|
-
@logger.info "#{@interface.name}:
|
630
|
+
@logger.info "#{@interface.name}: Connect #{@interface.connection_string}"
|
631
631
|
begin
|
632
632
|
@interface.connect
|
633
633
|
rescue Exception => e
|