cosmos 3.1.2 → 3.2.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 +3 -0
- data/Manifest.txt +17 -1
- data/autohotkey/tools/test_runner2.ahk +1 -0
- data/autohotkey/tools/tlm_grapher.ahk +13 -1
- data/data/crc.txt +39 -30
- data/demo/config/data/crc.txt +3 -3
- data/demo/config/targets/TEMPLATED/lib/templated_interface.rb +3 -1
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +7 -1
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +6 -1
- data/lib/cosmos.rb +2 -2
- data/lib/cosmos/gui/dialogs/about_dialog.rb +18 -5
- data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +0 -7
- data/lib/cosmos/gui/line_graph/overview_graph.rb +12 -2
- data/lib/cosmos/gui/utilities/script_module_gui.rb +11 -3
- data/lib/cosmos/interfaces/interface.rb +12 -0
- data/lib/cosmos/interfaces/stream_interface.rb +1 -21
- data/lib/cosmos/interfaces/tcpip_server_interface.rb +10 -0
- data/lib/cosmos/io/json_drb_object.rb +75 -56
- data/lib/cosmos/io/tcpip_server.rb +1 -11
- data/lib/cosmos/packet_logs.rb +1 -0
- data/lib/cosmos/packet_logs/ccsds_log_reader.rb +103 -0
- data/lib/cosmos/packets/packet.rb +70 -1
- data/lib/cosmos/packets/packet_config.rb +59 -611
- data/lib/cosmos/packets/parsers/format_string_parser.rb +58 -0
- data/lib/cosmos/packets/parsers/limits_parser.rb +146 -0
- data/lib/cosmos/packets/parsers/limits_response_parser.rb +52 -0
- data/lib/cosmos/packets/parsers/macro_parser.rb +116 -0
- data/lib/cosmos/packets/parsers/packet_item_parser.rb +215 -0
- data/lib/cosmos/packets/parsers/packet_parser.rb +123 -0
- data/lib/cosmos/packets/parsers/processor_parser.rb +63 -0
- data/lib/cosmos/packets/parsers/state_parser.rb +116 -0
- data/lib/cosmos/packets/structure.rb +59 -22
- data/lib/cosmos/packets/structure_item.rb +1 -1
- data/lib/cosmos/script/script.rb +4 -5
- data/lib/cosmos/streams/serial_stream.rb +5 -0
- data/lib/cosmos/streams/stream.rb +8 -2
- data/lib/cosmos/streams/stream_protocol.rb +1 -0
- data/lib/cosmos/streams/tcpip_client_stream.rb +37 -7
- data/lib/cosmos/streams/tcpip_socket_stream.rb +9 -6
- data/lib/cosmos/system/target.rb +3 -6
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +57 -48
- data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +7 -3
- data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +1 -1
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +7 -1
- data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +1 -2
- data/lib/cosmos/top_level.rb +22 -11
- data/lib/cosmos/utilities/message_log.rb +14 -9
- data/lib/cosmos/version.rb +5 -5
- data/spec/interfaces/cmd_tlm_server_interface_spec.rb +16 -16
- data/spec/interfaces/linc_interface_spec.rb +3 -0
- data/spec/interfaces/tcpip_client_interface_spec.rb +1 -0
- data/spec/interfaces/tcpip_server_interface_spec.rb +9 -0
- data/spec/io/json_drb_object_spec.rb +1 -1
- data/spec/io/serial_driver_spec.rb +0 -1
- data/spec/packet_logs/packet_log_writer_spec.rb +5 -3
- data/spec/packets/packet_config_spec.rb +22 -837
- data/spec/packets/packet_item_spec.rb +10 -10
- data/spec/packets/packet_spec.rb +239 -1
- data/spec/packets/parsers/format_string_parser_spec.rb +122 -0
- data/spec/packets/parsers/limits_parser_spec.rb +282 -0
- data/spec/packets/parsers/limits_response_parser_spec.rb +149 -0
- data/spec/packets/parsers/macro_parser_spec.rb +184 -0
- data/spec/packets/parsers/packet_item_parser_spec.rb +306 -0
- data/spec/packets/parsers/packet_parser_spec.rb +99 -0
- data/spec/packets/parsers/processor_parser_spec.rb +114 -0
- data/spec/packets/parsers/state_parser_spec.rb +156 -0
- data/spec/packets/structure_item_spec.rb +14 -14
- data/spec/packets/structure_spec.rb +162 -16
- data/spec/streams/fixed_stream_protocol_spec.rb +7 -4
- data/spec/streams/length_stream_protocol_spec.rb +3 -0
- data/spec/streams/preidentified_stream_protocol_spec.rb +3 -0
- data/spec/streams/serial_stream_spec.rb +12 -0
- data/spec/streams/stream_protocol_spec.rb +14 -0
- data/spec/streams/stream_spec.rb +1 -0
- data/spec/streams/tcpip_client_stream_spec.rb +3 -0
- data/spec/streams/tcpip_socket_stream_spec.rb +15 -3
- data/spec/streams/template_stream_protocol_spec.rb +5 -0
- data/spec/streams/terminated_stream_protocol_spec.rb +4 -0
- data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +21 -1
- data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +1 -1
- data/spec/tools/cmd_tlm_server/interfaces_spec.rb +1 -1
- metadata +19 -3
|
@@ -12,8 +12,8 @@ require 'timeout' # For Timeout::Error
|
|
|
12
12
|
|
|
13
13
|
module Cosmos
|
|
14
14
|
|
|
15
|
-
#
|
|
16
|
-
# connected? and disconnect. Streams are simply data sources which
|
|
15
|
+
# Class that implments the following methods: read, write(data),
|
|
16
|
+
# connect, connected? and disconnect. Streams are simply data sources which
|
|
17
17
|
# {StreamProtocol} classes read and write to. This separation of concerns
|
|
18
18
|
# allows Streams to simply focus on getting and sending raw data while the
|
|
19
19
|
# higher level processing occurs in {StreamProtocol}.
|
|
@@ -42,12 +42,18 @@ module Cosmos
|
|
|
42
42
|
raise "write not defined by Stream"
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
# Connects the stream
|
|
46
|
+
def connect
|
|
47
|
+
raise "connect not defined by Stream"
|
|
48
|
+
end
|
|
49
|
+
|
|
45
50
|
# @return [Boolean] true if connected or false otherwise
|
|
46
51
|
def connected?
|
|
47
52
|
raise "connected? not defined by Stream"
|
|
48
53
|
end
|
|
49
54
|
|
|
50
55
|
# Disconnects the stream
|
|
56
|
+
# Note that streams are not designed to be reconnected and must be recreated
|
|
51
57
|
def disconnect
|
|
52
58
|
raise "disconnect not defined by Stream"
|
|
53
59
|
end
|
|
@@ -28,7 +28,7 @@ module Cosmos
|
|
|
28
28
|
# a write only stream.
|
|
29
29
|
# @param write_timeout (see TcpipSocketStream#initialize)
|
|
30
30
|
# @param read_timeout (see TcpipSocketStream#initialize)
|
|
31
|
-
def initialize(hostname, write_port, read_port, write_timeout, read_timeout)
|
|
31
|
+
def initialize(hostname, write_port, read_port, write_timeout, read_timeout, connect_timeout = 5.0)
|
|
32
32
|
@hostname = hostname
|
|
33
33
|
if (@hostname.to_s.upcase == 'LOCALHOST')
|
|
34
34
|
@hostname = '127.0.0.1'
|
|
@@ -41,8 +41,8 @@ module Cosmos
|
|
|
41
41
|
write_addr = nil
|
|
42
42
|
read_addr = nil
|
|
43
43
|
begin
|
|
44
|
-
write_addr = Socket.pack_sockaddr_in(@write_port, @hostname) if @write_port
|
|
45
|
-
read_addr
|
|
44
|
+
@write_addr = Socket.pack_sockaddr_in(@write_port, @hostname) if @write_port
|
|
45
|
+
@read_addr = Socket.pack_sockaddr_in(@read_port, @hostname) if @read_port
|
|
46
46
|
rescue => error
|
|
47
47
|
if error.message =~ /getaddrinfo/
|
|
48
48
|
raise "Invalid hostname: #{@hostname}"
|
|
@@ -52,26 +52,56 @@ module Cosmos
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
write_socket = nil
|
|
55
|
-
if write_addr
|
|
55
|
+
if @write_addr
|
|
56
56
|
write_socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
|
57
57
|
write_socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
|
58
|
-
write_socket.connect(write_addr)
|
|
59
58
|
end
|
|
60
59
|
|
|
61
60
|
read_socket = nil
|
|
62
|
-
if read_addr
|
|
61
|
+
if @read_addr
|
|
63
62
|
if @write_port != @read_port
|
|
64
63
|
read_socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
|
65
64
|
read_socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
|
66
|
-
read_socket.connect(read_addr)
|
|
67
65
|
else
|
|
68
66
|
read_socket = write_socket
|
|
69
67
|
end
|
|
70
68
|
end
|
|
71
69
|
|
|
70
|
+
@connect_timeout = ConfigParser.handle_nil(connect_timeout)
|
|
71
|
+
@connect_timeout = @connect_timeout.to_f if @connect_timeout
|
|
72
|
+
|
|
72
73
|
super(write_socket, read_socket, write_timeout, read_timeout)
|
|
73
74
|
end
|
|
74
75
|
|
|
76
|
+
# Connect the socket(s)
|
|
77
|
+
def connect
|
|
78
|
+
connect_nonblock(@write_socket, @write_addr) if @write_socket
|
|
79
|
+
connect_nonblock(@read_socket, @read_addr) if @read_socket and @read_socket != @write_socket
|
|
80
|
+
super()
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
protected
|
|
84
|
+
|
|
85
|
+
def connect_nonblock(socket, addr)
|
|
86
|
+
begin
|
|
87
|
+
socket.connect_nonblock(addr)
|
|
88
|
+
rescue IO::WaitWritable
|
|
89
|
+
begin
|
|
90
|
+
_, sockets, _ = IO.select(nil, [socket], nil, @connect_timeout) # wait 3-way handshake completion
|
|
91
|
+
rescue Errno::ENOTSOCK
|
|
92
|
+
raise "Connect canceled"
|
|
93
|
+
end
|
|
94
|
+
if sockets and !sockets.empty?
|
|
95
|
+
begin
|
|
96
|
+
socket.connect_nonblock(addr) # check connection failure
|
|
97
|
+
rescue Errno::EISCONN
|
|
98
|
+
end
|
|
99
|
+
else
|
|
100
|
+
raise "Connect timeout"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
75
105
|
end # class TcpipClientStream
|
|
76
106
|
|
|
77
107
|
end # module Cosmos
|
|
@@ -35,7 +35,6 @@ module Cosmos
|
|
|
35
35
|
@write_timeout = @write_timeout.to_f if @write_timeout
|
|
36
36
|
@read_timeout = ConfigParser.handle_nil(read_timeout)
|
|
37
37
|
@read_timeout = @read_timeout.to_f if @read_timeout
|
|
38
|
-
@connected = true
|
|
39
38
|
|
|
40
39
|
# Mutex on write is needed to protect from commands coming in from more
|
|
41
40
|
# than one tool
|
|
@@ -120,6 +119,12 @@ module Cosmos
|
|
|
120
119
|
end
|
|
121
120
|
end
|
|
122
121
|
|
|
122
|
+
# Connect the stream
|
|
123
|
+
def connect
|
|
124
|
+
# If called directly this class is acting as a server and does not need to connect the sockets
|
|
125
|
+
@connected = true
|
|
126
|
+
end
|
|
127
|
+
|
|
123
128
|
# @return [Boolean] Whether the sockets are connected
|
|
124
129
|
def connected?
|
|
125
130
|
@connected
|
|
@@ -127,11 +132,9 @@ module Cosmos
|
|
|
127
132
|
|
|
128
133
|
# Disconnect by closing the sockets
|
|
129
134
|
def disconnect
|
|
130
|
-
if @
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
@connected = false
|
|
134
|
-
end
|
|
135
|
+
@write_socket.close if @write_socket and !@write_socket.closed?
|
|
136
|
+
@read_socket.close if @read_socket and !@read_socket.closed?
|
|
137
|
+
@connected = false
|
|
135
138
|
end
|
|
136
139
|
|
|
137
140
|
end # class TcpipSocketStream
|
data/lib/cosmos/system/target.rb
CHANGED
|
@@ -135,12 +135,9 @@ module Cosmos
|
|
|
135
135
|
usage = "#{keyword} <FILENAME>"
|
|
136
136
|
parser.verify_num_parameters(1, 1, usage)
|
|
137
137
|
begin
|
|
138
|
-
|
|
139
|
-
rescue
|
|
140
|
-
|
|
141
|
-
"Ensure #{parameters[0]} is in the COSMOS lib directory."
|
|
142
|
-
Logger.instance.error msg
|
|
143
|
-
raise parser.error(msg)
|
|
138
|
+
Cosmos.require_file(parameters[0])
|
|
139
|
+
rescue Exception => err
|
|
140
|
+
raise parser.error(err.message)
|
|
144
141
|
end
|
|
145
142
|
@requires << parameters[0]
|
|
146
143
|
|
|
@@ -61,9 +61,9 @@ module Cosmos
|
|
|
61
61
|
# @param recursive [Boolean] Whether process_file is being called
|
|
62
62
|
# recursively
|
|
63
63
|
def process_file(filename, recursive = false)
|
|
64
|
-
|
|
64
|
+
current_interface_or_router = nil
|
|
65
|
+
current_type = nil
|
|
65
66
|
current_interface_log_added = false
|
|
66
|
-
current_router = nil
|
|
67
67
|
|
|
68
68
|
Logger.info "Processing CmdTlmServer configuration in file: #{File.expand_path(filename)}"
|
|
69
69
|
|
|
@@ -122,94 +122,103 @@ module Cosmos
|
|
|
122
122
|
parser.verify_num_parameters(2, nil, usage)
|
|
123
123
|
interface_class = Cosmos.require_class(params[1])
|
|
124
124
|
if params[2]
|
|
125
|
-
|
|
125
|
+
current_interface_or_router = interface_class.new(*params[2..-1])
|
|
126
126
|
else
|
|
127
|
-
|
|
127
|
+
current_interface_or_router = interface_class.new
|
|
128
128
|
end
|
|
129
|
+
current_type = :INTERFACE
|
|
129
130
|
current_interface_log_added = false
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
@interfaces[params[0].upcase] =
|
|
131
|
+
current_interface_or_router.packet_log_writer_pairs << @packet_log_writer_pairs['DEFAULT']
|
|
132
|
+
current_interface_or_router.name = params[0].upcase
|
|
133
|
+
@interfaces[params[0].upcase] = current_interface_or_router
|
|
133
134
|
|
|
134
|
-
when '
|
|
135
|
-
raise parser.error("No current interface for #{keyword}") unless
|
|
135
|
+
when 'LOG', 'DONT_LOG', 'TARGET'
|
|
136
|
+
raise parser.error("No current interface for #{keyword}") unless current_interface_or_router and current_type == :INTERFACE
|
|
136
137
|
|
|
137
138
|
case keyword
|
|
138
139
|
|
|
139
|
-
when 'DONT_CONNECT'
|
|
140
|
-
parser.verify_num_parameters(0, 0, "#{keyword}")
|
|
141
|
-
current_interface.connect_on_startup = false
|
|
142
|
-
|
|
143
|
-
when 'DONT_RECONNECT'
|
|
144
|
-
parser.verify_num_parameters(0, 0, "#{keyword}")
|
|
145
|
-
current_interface.auto_reconnect = false
|
|
146
|
-
|
|
147
|
-
when 'RECONNECT_DELAY'
|
|
148
|
-
parser.verify_num_parameters(1, 1, "#{keyword} <Delay in Seconds>")
|
|
149
|
-
current_interface.reconnect_delay = Float(params[0])
|
|
150
|
-
|
|
151
|
-
when 'DISABLE_DISCONNECT'
|
|
152
|
-
parser.verify_num_parameters(0, 0, "#{keyword}")
|
|
153
|
-
current_interface.disable_disconnect = true
|
|
154
|
-
|
|
155
140
|
when 'LOG'
|
|
156
141
|
parser.verify_num_parameters(1, 1, "#{keyword} <Packet Log Writer Name>")
|
|
157
142
|
packet_log_writer_pair = @packet_log_writer_pairs[params[0].upcase]
|
|
158
143
|
raise parser.error("Unknown packet log writer: #{params[0].upcase}") unless packet_log_writer_pair
|
|
159
|
-
|
|
144
|
+
current_interface_or_router.packet_log_writer_pairs.delete(@packet_log_writer_pairs['DEFAULT']) unless current_interface_log_added
|
|
160
145
|
current_interface_log_added = true
|
|
161
|
-
|
|
146
|
+
current_interface_or_router.packet_log_writer_pairs << packet_log_writer_pair unless current_interface_or_router.packet_log_writer_pairs.include?(packet_log_writer_pair)
|
|
162
147
|
|
|
163
148
|
when 'DONT_LOG'
|
|
164
149
|
parser.verify_num_parameters(0, 0, "#{keyword}")
|
|
165
|
-
|
|
150
|
+
current_interface_or_router.packet_log_writer_pairs = []
|
|
166
151
|
|
|
167
152
|
when 'TARGET'
|
|
168
153
|
parser.verify_num_parameters(1, 1, "#{keyword} <Target Name>")
|
|
169
154
|
target_name = params[0].upcase
|
|
170
155
|
target = System.targets[target_name]
|
|
171
156
|
if target
|
|
172
|
-
target.interface =
|
|
173
|
-
|
|
157
|
+
target.interface = current_interface_or_router
|
|
158
|
+
current_interface_or_router.target_names << target_name
|
|
174
159
|
else
|
|
175
|
-
raise parser.error("Unknown target #{target_name} mapped to interface #{
|
|
160
|
+
raise parser.error("Unknown target #{target_name} mapped to interface #{current_interface_or_router.name}")
|
|
176
161
|
end
|
|
177
162
|
|
|
178
|
-
|
|
163
|
+
end # end case keyword for all keywords that require a current interface
|
|
164
|
+
|
|
165
|
+
when 'DONT_CONNECT', 'DONT_RECONNECT', 'RECONNECT_DELAY', 'DISABLE_DISCONNECT', 'LOG_RAW', 'ROUTER_LOG_RAW', 'OPTION'
|
|
166
|
+
raise parser.error("No current interface or router for #{keyword}") unless current_interface_or_router
|
|
167
|
+
|
|
168
|
+
case keyword
|
|
169
|
+
|
|
170
|
+
when 'DONT_CONNECT'
|
|
171
|
+
parser.verify_num_parameters(0, 0, "#{keyword}")
|
|
172
|
+
current_interface_or_router.connect_on_startup = false
|
|
173
|
+
|
|
174
|
+
when 'DONT_RECONNECT'
|
|
175
|
+
parser.verify_num_parameters(0, 0, "#{keyword}")
|
|
176
|
+
current_interface_or_router.auto_reconnect = false
|
|
177
|
+
|
|
178
|
+
when 'RECONNECT_DELAY'
|
|
179
|
+
parser.verify_num_parameters(1, 1, "#{keyword} <Delay in Seconds>")
|
|
180
|
+
current_interface_or_router.reconnect_delay = Float(params[0])
|
|
181
|
+
|
|
182
|
+
when 'DISABLE_DISCONNECT'
|
|
183
|
+
parser.verify_num_parameters(0, 0, "#{keyword}")
|
|
184
|
+
current_interface_or_router.disable_disconnect = true
|
|
185
|
+
|
|
186
|
+
# TODO: Deprecate ROUTER_LOG_RAW
|
|
187
|
+
when 'LOG_RAW', 'ROUTER_LOG_RAW'
|
|
179
188
|
parser.verify_num_parameters(0, nil, "#{keyword} <Raw Logger Class File (optional)> <Raw Logger Parameters (optional)>")
|
|
180
|
-
|
|
189
|
+
current_interface_or_router.raw_logger_pair = RawLoggerPair.new(current_interface_or_router.name, params)
|
|
181
190
|
|
|
182
|
-
|
|
191
|
+
when 'OPTION'
|
|
192
|
+
parser.verify_num_parameters(2, nil, "#{keyword} <Option Name> <Option Value 1> <Option Value 2 (optional)> <etc>")
|
|
193
|
+
current_interface_or_router.set_option(params[0], params[1..-1])
|
|
194
|
+
|
|
195
|
+
end # end case keyword for all keywords that require a current interface or router
|
|
183
196
|
|
|
184
197
|
when 'ROUTER'
|
|
185
198
|
usage = "ROUTER <Name> <Filename> <Specific Parameters>"
|
|
186
199
|
parser.verify_num_parameters(2, nil, usage)
|
|
187
200
|
router_class = Cosmos.require_class(params[1])
|
|
188
201
|
if params[2]
|
|
189
|
-
|
|
202
|
+
current_interface_or_router = router_class.new(*params[2..-1])
|
|
190
203
|
else
|
|
191
|
-
|
|
204
|
+
current_interface_or_router = router_class.new
|
|
192
205
|
end
|
|
193
|
-
|
|
194
|
-
|
|
206
|
+
current_type = :ROUTER
|
|
207
|
+
current_interface_or_router.name = params[0].upcase
|
|
208
|
+
@routers[params[0].upcase] = current_interface_or_router
|
|
195
209
|
|
|
196
210
|
when 'ROUTE'
|
|
197
|
-
raise parser.error("No current router for #{keyword}") unless
|
|
211
|
+
raise parser.error("No current router for #{keyword}") unless current_interface_or_router and current_type == :ROUTER
|
|
198
212
|
usage = "ROUTE <Interface Name>"
|
|
199
213
|
parser.verify_num_parameters(1, 1, usage)
|
|
200
214
|
interface_name = params[0].upcase
|
|
201
215
|
interface = @interfaces[interface_name]
|
|
202
|
-
raise parser.error("Unknown interface #{interface_name} mapped to router #{
|
|
203
|
-
unless
|
|
204
|
-
|
|
205
|
-
interface.routers <<
|
|
216
|
+
raise parser.error("Unknown interface #{interface_name} mapped to router #{current_interface_or_router.name}") unless interface
|
|
217
|
+
unless current_interface_or_router.interfaces.include? interface
|
|
218
|
+
current_interface_or_router.interfaces << interface
|
|
219
|
+
interface.routers << current_interface_or_router
|
|
206
220
|
end
|
|
207
221
|
|
|
208
|
-
when 'ROUTER_LOG_RAW'
|
|
209
|
-
raise parser.error("No current router for #{keyword}") unless current_router
|
|
210
|
-
parser.verify_num_parameters(0, nil, "#{keyword} <Raw Logger Class File (optional)> <Raw Logger Parameters (optional)>")
|
|
211
|
-
current_router.raw_logger_pair = RawLoggerPair.new(current_router.name, params)
|
|
212
|
-
|
|
213
222
|
when 'BACKGROUND_TASK'
|
|
214
223
|
usage = "#{keyword} <Filename> <Specific Parameters>"
|
|
215
224
|
parser.verify_num_parameters(1, nil, usage)
|
|
@@ -183,12 +183,16 @@ module Cosmos
|
|
|
183
183
|
if @connection_failed_callback
|
|
184
184
|
@connection_failed_callback.call(connect_error)
|
|
185
185
|
else
|
|
186
|
-
Logger.error "#{@interface.name} Connection Failed: #{connect_error.
|
|
186
|
+
Logger.error "#{@interface.name} Connection Failed: #{connect_error.class}:#{connect_error.message}"
|
|
187
187
|
case connect_error
|
|
188
|
-
when Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ETIMEDOUT
|
|
188
|
+
when Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::ENOTSOCK
|
|
189
189
|
# Do not write an exception file for these extremely common cases
|
|
190
190
|
else
|
|
191
|
-
|
|
191
|
+
if RuntimeError === connect_error and (connect_error.message =~ /canceled/ or connect_error.message =~ /timeout/)
|
|
192
|
+
# Do not write an exception file for these extremely common cases
|
|
193
|
+
else
|
|
194
|
+
Cosmos.write_exception_file(connect_error)
|
|
195
|
+
end
|
|
192
196
|
end
|
|
193
197
|
end
|
|
194
198
|
disconnect()
|
|
@@ -64,7 +64,13 @@ module Cosmos
|
|
|
64
64
|
end # def kill
|
|
65
65
|
|
|
66
66
|
def graceful_kill
|
|
67
|
-
#
|
|
67
|
+
# Allow the callbacks a chance to update the GUI so that they can die gracefully
|
|
68
|
+
if defined? Qt and Thread.current == Thread.main
|
|
69
|
+
5.times do
|
|
70
|
+
Qt::CoreApplication.instance.processEvents
|
|
71
|
+
sleep(0.05)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
68
74
|
end
|
|
69
75
|
|
|
70
76
|
end # class TabbedPlotsRealtimeThread
|
|
@@ -433,9 +433,8 @@ module Cosmos
|
|
|
433
433
|
event.ignore()
|
|
434
434
|
else
|
|
435
435
|
# Close any open screens
|
|
436
|
-
script_disconnect()
|
|
437
|
-
Screen.close_all_screens(self)
|
|
438
436
|
shutdown_cmd_tlm()
|
|
437
|
+
Screen.close_all_screens(self)
|
|
439
438
|
@json_drb.stop_service if @json_drb
|
|
440
439
|
super(event)
|
|
441
440
|
end
|
data/lib/cosmos/top_level.rb
CHANGED
|
@@ -527,13 +527,7 @@ module Cosmos
|
|
|
527
527
|
def self.require_class(class_filename)
|
|
528
528
|
class_name = class_filename.filename_to_class_name
|
|
529
529
|
return class_name.to_class if class_name.to_class and defined? class_name.to_class
|
|
530
|
-
|
|
531
|
-
require class_filename
|
|
532
|
-
rescue LoadError => err
|
|
533
|
-
msg = "Unable to require #{class_filename} due to #{err.message}. Ensure #{class_filename} is in the COSMOS lib directory."
|
|
534
|
-
Logger.error msg
|
|
535
|
-
raise msg
|
|
536
|
-
end
|
|
530
|
+
self.require_file(class_filename)
|
|
537
531
|
klass = class_name.to_class
|
|
538
532
|
if klass
|
|
539
533
|
return klass
|
|
@@ -542,6 +536,19 @@ module Cosmos
|
|
|
542
536
|
end
|
|
543
537
|
end
|
|
544
538
|
|
|
539
|
+
# Requires a file with a standard error message if it fails
|
|
540
|
+
#
|
|
541
|
+
# @param filename [String] The name of the file to require
|
|
542
|
+
def self.require_file(filename)
|
|
543
|
+
begin
|
|
544
|
+
require filename
|
|
545
|
+
rescue Exception => err
|
|
546
|
+
msg = "Unable to require #{filename} due to #{err.message}. Ensure #{filename} is in the COSMOS lib directory."
|
|
547
|
+
Logger.error msg
|
|
548
|
+
raise msg
|
|
549
|
+
end
|
|
550
|
+
end
|
|
551
|
+
|
|
545
552
|
# @param filename [String] Name of the file to open in the editor
|
|
546
553
|
def self.open_in_text_editor(filename)
|
|
547
554
|
if filename
|
|
@@ -621,10 +628,14 @@ module Cosmos
|
|
|
621
628
|
def self.kill_thread(owner, thread, graceful_timeout = 1, timeout_interval = 0.01, hard_timeout = 1)
|
|
622
629
|
if thread
|
|
623
630
|
if owner and owner.respond_to? :graceful_kill
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
631
|
+
if Thread.current != thread
|
|
632
|
+
owner.graceful_kill
|
|
633
|
+
end_time = Time.now + graceful_timeout
|
|
634
|
+
while thread.alive? && ((end_time - Time.now) > 0)
|
|
635
|
+
sleep(timeout_interval)
|
|
636
|
+
end
|
|
637
|
+
else
|
|
638
|
+
Logger.warn "Threads cannot graceful_kill themselves"
|
|
628
639
|
end
|
|
629
640
|
elsif owner
|
|
630
641
|
Logger.info "Thread owner #{owner.class} does not support graceful_kill"
|