cosmos 4.0.3 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +5 -5
- data/Manifest.txt +11 -1
- data/README.md +3 -2
- data/Rakefile +18 -4
- data/appveyor.yml +19 -0
- data/cosmos.gemspec +14 -3
- data/data/config/cmd_tlm_server.yaml +3 -0
- data/data/crc.txt +63 -60
- data/demo/config/targets/INST/cmd_tlm_server.txt +1 -0
- data/demo/config/targets/INST/cmd_tlm_server2.txt +7 -0
- data/demo/config/tools/cmd_sequence/cmd_sequence.txt +2 -0
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +8 -12
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +7 -9
- data/demo/lib/cmd_sequence_exporter.rb +52 -0
- data/demo/lib/example_background_task.rb +1 -0
- data/demo/procedures/replay_test.rb +32 -0
- data/ext/cosmos/ext/structure/structure.c +39 -3
- data/install/config/tools/cmd_tlm_server/cmd_tlm_server.txt +1 -0
- data/install/config/tools/launcher/launcher.txt +2 -0
- data/lib/cosmos/config/config_parser.rb +2 -0
- data/lib/cosmos/core_ext/io.rb +89 -60
- data/lib/cosmos/gui/qt.rb +5 -8
- data/lib/cosmos/gui/qt_tool.rb +8 -8
- data/lib/cosmos/gui/text/ruby_editor.rb +12 -12
- data/lib/cosmos/gui/utilities/script_module_gui.rb +9 -9
- data/lib/cosmos/gui/widgets/realtime_button_bar.rb +18 -17
- data/lib/cosmos/interfaces/protocols/fixed_protocol.rb +2 -2
- data/lib/cosmos/interfaces/protocols/template_protocol.rb +3 -0
- data/lib/cosmos/interfaces/udp_interface.rb +27 -14
- data/lib/cosmos/io/buffered_file.rb +0 -1
- data/lib/cosmos/io/json_drb.rb +134 -214
- data/lib/cosmos/io/json_drb_object.rb +22 -61
- data/lib/cosmos/io/json_drb_rack.rb +79 -0
- data/lib/cosmos/io/json_rpc.rb +27 -0
- data/lib/cosmos/io/udp_sockets.rb +102 -58
- data/lib/cosmos/packets/commands.rb +1 -1
- data/lib/cosmos/packets/structure.rb +1 -1
- data/lib/cosmos/packets/structure_item.rb +37 -5
- data/lib/cosmos/script/cmd_tlm_server.rb +76 -2
- data/lib/cosmos/script/replay.rb +60 -0
- data/lib/cosmos/script/script.rb +20 -2
- data/lib/cosmos/script/scripting.rb +9 -9
- data/lib/cosmos/script/tools.rb +14 -0
- data/lib/cosmos/system/system.rb +185 -92
- data/lib/cosmos/system/target.rb +1 -1
- data/lib/cosmos/tools/cmd_sequence/cmd_sequence.rb +44 -4
- data/lib/cosmos/tools/cmd_sequence/sequence_item.rb +4 -0
- data/lib/cosmos/tools/cmd_sequence/sequence_list.rb +7 -0
- data/lib/cosmos/tools/cmd_tlm_server/api.rb +347 -20
- data/lib/cosmos/tools/cmd_tlm_server/background_tasks.rb +3 -0
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +329 -111
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +13 -0
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +261 -95
- data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +46 -35
- data/lib/cosmos/tools/cmd_tlm_server/gui/logging_tab.rb +18 -8
- data/lib/cosmos/tools/cmd_tlm_server/gui/packets_tab.rb +39 -28
- data/lib/cosmos/tools/cmd_tlm_server/gui/replay_tab.rb +242 -0
- data/lib/cosmos/tools/cmd_tlm_server/gui/status_tab.rb +24 -8
- data/lib/cosmos/tools/cmd_tlm_server/gui/targets_tab.rb +18 -6
- data/lib/cosmos/tools/cmd_tlm_server/limits_groups_background_task.rb +5 -4
- data/lib/cosmos/tools/cmd_tlm_server/replay_backend.rb +375 -0
- data/lib/cosmos/tools/cmd_tlm_server/routers.rb +10 -2
- data/lib/cosmos/tools/data_viewer/data_viewer.rb +40 -5
- data/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb +18 -20
- data/lib/cosmos/tools/launcher/launcher_config.rb +5 -16
- data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +65 -39
- data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +19 -0
- data/lib/cosmos/tools/replay/replay.rb +5 -505
- data/lib/cosmos/tools/script_runner/script_audit.rb +1 -0
- data/lib/cosmos/tools/script_runner/script_runner.rb +3 -4
- data/lib/cosmos/tools/script_runner/script_runner_config.rb +3 -4
- data/lib/cosmos/tools/script_runner/script_runner_frame.rb +44 -23
- data/lib/cosmos/tools/test_runner/results_writer.rb +4 -0
- data/lib/cosmos/tools/test_runner/test_runner.rb +0 -3
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +6 -2
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tool.rb +26 -1
- data/lib/cosmos/tools/tlm_viewer/screen.rb +24 -1
- data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +25 -0
- data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +24 -14
- data/lib/cosmos/top_level.rb +34 -24
- data/lib/cosmos/utilities/csv.rb +60 -8
- data/lib/cosmos/version.rb +5 -5
- data/spec/config/config_parser_spec.rb +10 -1
- data/spec/core_ext/socket_spec.rb +4 -2
- data/spec/gui/utilities/script_module_gui_spec.rb +102 -0
- data/spec/install/config/data/data.txt +1 -0
- data/spec/install/config/targets/INST/cmd_tlm/inst_cmds.txt +2 -0
- data/spec/interfaces/cmd_tlm_server_interface_spec.rb +1 -2
- data/spec/interfaces/protocols/template_protocol_spec.rb +72 -2
- data/spec/interfaces/serial_interface_spec.rb +1 -1
- data/spec/interfaces/udp_interface_spec.rb +14 -0
- data/spec/io/buffered_file_spec.rb +37 -0
- data/spec/io/json_drb_object_spec.rb +2 -15
- data/spec/io/json_drb_spec.rb +61 -121
- data/spec/io/udp_sockets_spec.rb +42 -2
- data/spec/packet_logs/packet_log_reader_spec.rb +5 -2
- data/spec/packets/binary_accessor_spec.rb +1 -1
- data/spec/packets/packet_item_spec.rb +1 -1
- data/spec/packets/structure_item_spec.rb +5 -6
- data/spec/script/cmd_tlm_server_spec.rb +39 -4
- data/spec/script/commands_disconnect_spec.rb +1 -1
- data/spec/script/commands_spec.rb +2 -1
- data/spec/script/scripting_spec.rb +18 -3
- data/spec/script/telemetry_spec.rb +5 -0
- data/spec/spec_helper.rb +43 -26
- data/spec/streams/tcpip_socket_stream_spec.rb +2 -2
- data/spec/system/system_spec.rb +11 -9
- data/spec/system/target_spec.rb +3 -0
- data/spec/tools/cmd_tlm_server/api_spec.rb +543 -29
- data/spec/tools/cmd_tlm_server/background_task_spec.rb +2 -2
- data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +31 -75
- data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +199 -66
- data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +85 -9
- data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +29 -127
- data/spec/tools/cmd_tlm_server/router_thread_spec.rb +10 -50
- data/spec/tools/launcher/launcher_config_spec.rb +1 -1
- data/spec/tools/table_manager/table_item_spec.rb +1 -1
- data/spec/tools/table_manager/tablemanager_core_spec.rb +4 -4
- data/spec/top_level/top_level_spec.rb +151 -3
- data/spec/utilities/csv_spec.rb +24 -5
- metadata +61 -9
- data/lib/cosmos/tools/replay/replay_server.rb +0 -91
@@ -51,6 +51,13 @@ module Cosmos
|
|
51
51
|
|
52
52
|
protected
|
53
53
|
|
54
|
+
def get_target_interface_name(target_name)
|
55
|
+
@interfaces.each do |interface_name, interface|
|
56
|
+
return interface_name if interface.target_names.include?(target_name)
|
57
|
+
end
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
|
54
61
|
# Processes a file and adds in the configuration defined in the file
|
55
62
|
#
|
56
63
|
# @param filename [String] The name of the configuration file to parse
|
@@ -105,6 +112,8 @@ module Cosmos
|
|
105
112
|
System.targets.each do |target_name, target|
|
106
113
|
target_filename = File.join(target.dir, 'cmd_tlm_server.txt')
|
107
114
|
if File.exist?(target_filename)
|
115
|
+
# Skip this target if it's already been assigned an interface
|
116
|
+
next if get_target_interface_name(target.name)
|
108
117
|
raise parser.error("Cannot use #{keyword} with target name substitutions: #{target.name} != #{target.original_name}") if target.name != target.original_name
|
109
118
|
process_file(target_filename, true)
|
110
119
|
end
|
@@ -116,6 +125,8 @@ module Cosmos
|
|
116
125
|
parser.verify_num_parameters(1, 2, usage)
|
117
126
|
target = System.targets[params[0].upcase]
|
118
127
|
raise parser.error("Unknown target: #{params[0].upcase}") unless target
|
128
|
+
interface_name = get_target_interface_name(target.name)
|
129
|
+
raise parser.error("Target #{target.name} already mapped to interface #{interface_name}") if interface_name
|
119
130
|
target_filename = params[1]
|
120
131
|
target_filename = 'cmd_tlm_server.txt' unless target_filename
|
121
132
|
target_filename = File.join(target.dir, target_filename)
|
@@ -164,6 +175,8 @@ module Cosmos
|
|
164
175
|
target_name = params[0].upcase
|
165
176
|
target = System.targets[target_name]
|
166
177
|
if target
|
178
|
+
interface_name = get_target_interface_name(target.name)
|
179
|
+
raise parser.error("Target #{target.name} already mapped to interface #{interface_name}") if interface_name
|
167
180
|
target.interface = current_interface_or_router
|
168
181
|
current_interface_or_router.target_names << target_name
|
169
182
|
else
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
|
3
|
-
# Copyright
|
3
|
+
# Copyright 2017 Ball Aerospace & Technologies Corp.
|
4
4
|
# All Rights Reserved.
|
5
5
|
#
|
6
6
|
# This program is free software; you can modify and/or redistribute it
|
@@ -16,6 +16,7 @@ if RUBY_ENGINE == 'ruby'
|
|
16
16
|
require 'cosmos/tools/cmd_tlm_server/gui/packets_tab'
|
17
17
|
require 'cosmos/tools/cmd_tlm_server/gui/logging_tab'
|
18
18
|
require 'cosmos/tools/cmd_tlm_server/gui/status_tab'
|
19
|
+
require 'cosmos/tools/cmd_tlm_server/gui/replay_tab'
|
19
20
|
require 'cosmos/gui/qt_tool'
|
20
21
|
require 'cosmos/gui/dialogs/splash'
|
21
22
|
require 'cosmos/gui/dialogs/exception_dialog'
|
@@ -85,7 +86,8 @@ module Cosmos
|
|
85
86
|
RUNNING = 1
|
86
87
|
ERROR = 2
|
87
88
|
|
88
|
-
TOOL_NAME = "Command and Telemetry Server"
|
89
|
+
TOOL_NAME = "Command and Telemetry Server".freeze
|
90
|
+
BLANK = ''.freeze
|
89
91
|
|
90
92
|
attr_writer :no_prompt
|
91
93
|
|
@@ -109,69 +111,94 @@ module Cosmos
|
|
109
111
|
|
110
112
|
def initialize(options)
|
111
113
|
super(options) # MUST BE FIRST - All code before super is executed twice in RubyQt Based classes
|
112
|
-
Cosmos.load_cosmos_icon("cts.png")
|
113
114
|
|
115
|
+
@ready = false
|
116
|
+
@tabs_ready = false
|
117
|
+
if options.replay
|
118
|
+
@mode = :REPLAY
|
119
|
+
Cosmos.load_cosmos_icon("replay.png")
|
120
|
+
else
|
121
|
+
@mode = :CMD_TLM_SERVER
|
122
|
+
Cosmos.load_cosmos_icon("cts.png")
|
123
|
+
end
|
114
124
|
@production = options.production
|
115
125
|
@no_prompt = options.no_prompt
|
116
126
|
@message_log = nil
|
117
127
|
@output_sleeper = Sleeper.new
|
118
128
|
@first_output = 0
|
119
|
-
@
|
120
|
-
@targets_tab = TargetsTab.new
|
121
|
-
@packets_tab = PacketsTab.new(self)
|
122
|
-
@logging_tab = LoggingTab.new(@production)
|
123
|
-
@status_tab = StatusTab.new
|
129
|
+
@options = options
|
124
130
|
|
125
131
|
statusBar.showMessage(tr("")) # Show blank message to initialize status bar
|
126
132
|
|
127
133
|
initialize_actions()
|
128
134
|
initialize_menus()
|
129
135
|
initialize_central_widget()
|
130
|
-
configure_tabs(options)
|
131
|
-
complete_initialize()
|
132
|
-
end
|
133
|
-
|
134
|
-
def configure_tabs(options)
|
135
136
|
Splash.execute(self) do |splash|
|
136
137
|
ConfigParser.splash = splash
|
137
|
-
|
138
|
+
process_server_messages(@options)
|
139
|
+
start(splash)
|
140
|
+
ConfigParser.splash = nil
|
141
|
+
end
|
142
|
+
complete_initialize()
|
143
|
+
end
|
138
144
|
|
139
|
-
|
140
|
-
|
145
|
+
def start(splash)
|
146
|
+
splash.message = "Initializing #{@options.title}" if splash
|
141
147
|
|
148
|
+
if !CmdTlmServer.instance or @mode == :CMD_TLM_SERVER
|
142
149
|
CmdTlmServer.meta_callback = method(:meta_callback)
|
143
|
-
cts = CmdTlmServer.new(options.config_file, @production)
|
150
|
+
cts = CmdTlmServer.new(@options.config_file, @production, false, @mode)
|
151
|
+
CmdTlmServerGui.configure_signal_handlers()
|
144
152
|
cts.stop_callback = method(:stop_callback)
|
153
|
+
cts.reload_callback = method(:reload)
|
154
|
+
CmdTlmServer.replay_backend.config_change_callback = method(:config_change_callback) if @mode != :CMD_TLM_SERVER
|
145
155
|
@message_log = CmdTlmServer.message_log
|
156
|
+
@ready = true
|
157
|
+
end
|
146
158
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
@
|
156
|
-
|
157
|
-
@
|
158
|
-
splash.progress = 100/7 * 3
|
159
|
-
@packets_tab.populate_telemetry(@tab_widget)
|
160
|
-
splash.progress = 100/7 * 4
|
161
|
-
@interfaces_tab.populate_routers(@tab_widget)
|
162
|
-
splash.progress = 100/7 * 5
|
163
|
-
@logging_tab.populate(@tab_widget)
|
164
|
-
splash.progress = 100/7 * 6
|
165
|
-
@status_tab.populate(@tab_widget)
|
166
|
-
splash.progress = 100
|
159
|
+
# Now that we've started the server (CmdTlmServer.new) we can populate all the tabs
|
160
|
+
splash.message = "Populating Tabs" if splash
|
161
|
+
Qt.execute_in_main_thread(true) do
|
162
|
+
# Override the default title if one was given in the config file
|
163
|
+
self.window_title = CmdTlmServer.title if CmdTlmServer.title
|
164
|
+
splash.progress = 0 if splash
|
165
|
+
@tabs_ready = false
|
166
|
+
if @mode == :CMD_TLM_SERVER
|
167
|
+
@interfaces_tab.populate_interfaces
|
168
|
+
else
|
169
|
+
@replay_tab.populate
|
167
170
|
end
|
168
|
-
|
171
|
+
splash.progress = 100/7 * 1 if splash
|
172
|
+
@targets_tab.populate
|
173
|
+
splash.progress = 100/7 * 2 if splash
|
174
|
+
@commands_tab.populate_commands
|
175
|
+
splash.progress = 100/7 * 3 if splash
|
176
|
+
@telemetry_tab.populate_telemetry
|
177
|
+
splash.progress = 100/7 * 4 if splash
|
178
|
+
@routers_tab.populate_routers
|
179
|
+
if @mode == :CMD_TLM_SERVER
|
180
|
+
splash.progress = 100/7 * 5 if splash
|
181
|
+
@logging_tab.populate
|
182
|
+
end
|
183
|
+
splash.progress = 100/7 * 6 if splash
|
184
|
+
@status_tab.populate
|
185
|
+
splash.progress = 100 if splash
|
186
|
+
@tabs_ready = true
|
187
|
+
@tab_widget.setCurrentIndex(0)
|
188
|
+
handle_tab_change(0)
|
169
189
|
end
|
170
190
|
end
|
171
191
|
|
172
192
|
def initialize_actions
|
173
193
|
super()
|
174
194
|
|
195
|
+
# File actions
|
196
|
+
@file_reload = Qt::Action.new(tr('&Reload Configuration'), self)
|
197
|
+
@file_reload.statusTip = tr('Reload configuraton and reset')
|
198
|
+
@file_reload.connect(SIGNAL('triggered()')) do
|
199
|
+
CmdTlmServer.instance.reload()
|
200
|
+
end
|
201
|
+
|
175
202
|
# Edit actions
|
176
203
|
@edit_clear_counters = Qt::Action.new(tr('&Clear Counters'), self)
|
177
204
|
@edit_clear_counters.statusTip = tr('Clear counters for all interfaces and targets')
|
@@ -180,6 +207,7 @@ module Cosmos
|
|
180
207
|
|
181
208
|
def initialize_menus
|
182
209
|
@file_menu = menuBar.addMenu(tr('&File'))
|
210
|
+
@file_menu.addAction(@file_reload)
|
183
211
|
@file_menu.addAction(@exit_action)
|
184
212
|
|
185
213
|
# Do not allow clear counters in production mode
|
@@ -188,8 +216,12 @@ module Cosmos
|
|
188
216
|
@edit_menu.addAction(@edit_clear_counters)
|
189
217
|
end
|
190
218
|
|
191
|
-
@
|
192
|
-
|
219
|
+
if @mode == :CMD_TLM_SERVER
|
220
|
+
@about_string = "#{TOOL_NAME} is the heart of the COSMOS system. "
|
221
|
+
@about_string << "It connects to the target and processes command and telemetry requests from other tools."
|
222
|
+
else
|
223
|
+
@about_string = "Replay allows playing back data into the COSMOS realtime tools. "
|
224
|
+
end
|
193
225
|
|
194
226
|
initialize_help_menu()
|
195
227
|
end
|
@@ -221,30 +253,97 @@ module Cosmos
|
|
221
253
|
Logger.level = Logger::INFO
|
222
254
|
|
223
255
|
@tab_thread = nil
|
256
|
+
|
257
|
+
if @mode == :CMD_TLM_SERVER
|
258
|
+
@interfaces_tab = InterfacesTab.new(self, InterfacesTab::INTERFACES, @tab_widget)
|
259
|
+
else
|
260
|
+
@replay_tab = ReplayTab.new(@tab_widget)
|
261
|
+
end
|
262
|
+
@targets_tab = TargetsTab.new(@tab_widget)
|
263
|
+
@commands_tab = PacketsTab.new(self, PacketsTab::COMMANDS, @tab_widget)
|
264
|
+
@telemetry_tab = PacketsTab.new(self, PacketsTab::TELEMETRY, @tab_widget)
|
265
|
+
@routers_tab = InterfacesTab.new(self, InterfacesTab::ROUTERS, @tab_widget)
|
266
|
+
if @mode == :CMD_TLM_SERVER
|
267
|
+
@logging_tab = LoggingTab.new(@production, @tab_widget)
|
268
|
+
end
|
269
|
+
@status_tab = StatusTab.new(@tab_widget)
|
270
|
+
end
|
271
|
+
|
272
|
+
def config_change_callback
|
273
|
+
start(nil)
|
274
|
+
end
|
275
|
+
|
276
|
+
def reload(confirm = true)
|
277
|
+
Qt.execute_in_main_thread(true) do
|
278
|
+
if confirm
|
279
|
+
msg = Qt::MessageBox.new(self)
|
280
|
+
msg.setIcon(Qt::MessageBox::Question)
|
281
|
+
msg.setText("Are you sure? All connections will temporarily disconnect as the server restarts")
|
282
|
+
msg.setWindowTitle('Confirm Reload')
|
283
|
+
msg.setStandardButtons(Qt::MessageBox::Yes | Qt::MessageBox::No)
|
284
|
+
continue = false
|
285
|
+
continue = true if msg.exec() == Qt::MessageBox::Yes
|
286
|
+
msg.dispose
|
287
|
+
else
|
288
|
+
continue = true
|
289
|
+
end
|
290
|
+
|
291
|
+
if continue
|
292
|
+
Splash.execute(self) do |splash|
|
293
|
+
ConfigParser.splash = splash
|
294
|
+
Qt.execute_in_main_thread(true) do
|
295
|
+
@tab_widget.setCurrentIndex(0)
|
296
|
+
end
|
297
|
+
if @mode == :CMD_TLM_SERVER
|
298
|
+
Qt.execute_in_main_thread(true) do
|
299
|
+
splash.message = "Stopping Threads"
|
300
|
+
CmdTlmServer.instance.stop_callback = nil
|
301
|
+
stop_threads()
|
302
|
+
end
|
303
|
+
end
|
304
|
+
System.reset
|
305
|
+
start(splash)
|
306
|
+
Qt.execute_in_main_thread(true) do
|
307
|
+
@tab_widget.setCurrentIndex(0)
|
308
|
+
handle_tab_change(0)
|
309
|
+
end
|
310
|
+
ConfigParser.splash = nil
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
224
314
|
end
|
225
315
|
|
226
316
|
# Called when the user changes tabs in the Server application. It kills the
|
227
317
|
# currently executing tab and then creates a new thread to update the GUI
|
228
318
|
# for the selected tab.
|
229
319
|
def handle_tab_change(index)
|
320
|
+
return unless @tabs_ready
|
230
321
|
kill_tab_thread()
|
231
322
|
@tab_sleeper = Sleeper.new
|
232
323
|
|
233
324
|
case index
|
234
325
|
when 0
|
235
|
-
|
326
|
+
if @mode == :CMD_TLM_SERVER
|
327
|
+
handle_tab('Interfaces') { @interfaces_tab.update }
|
328
|
+
else
|
329
|
+
handle_tab('Replay', 0.5) { @replay_tab.update }
|
330
|
+
end
|
236
331
|
when 1
|
237
332
|
handle_tab('Targets') { @targets_tab.update }
|
238
333
|
when 2
|
239
|
-
handle_tab('Commands') { @
|
334
|
+
handle_tab('Commands') { @commands_tab.update }
|
240
335
|
when 3
|
241
|
-
handle_tab('Telemetry') { @
|
336
|
+
handle_tab('Telemetry') { @telemetry_tab.update }
|
242
337
|
when 4
|
243
|
-
handle_tab('Routers') { @
|
338
|
+
handle_tab('Routers') { @routers_tab.update }
|
244
339
|
when 5
|
245
|
-
|
340
|
+
if @mode == :CMD_TLM_SERVER
|
341
|
+
handle_tab('Logging') { @logging_tab.update }
|
342
|
+
else
|
343
|
+
handle_tab('Status') { @status_tab.update }
|
344
|
+
end
|
246
345
|
when 6
|
247
|
-
|
346
|
+
handle_tab('Status') { @status_tab.update }
|
248
347
|
end
|
249
348
|
end
|
250
349
|
|
@@ -252,7 +351,9 @@ module Cosmos
|
|
252
351
|
def kill_tab_thread
|
253
352
|
@tab_sleeper ||= nil
|
254
353
|
@tab_sleeper.cancel if @tab_sleeper
|
354
|
+
@tab_thread_shutdown = true
|
255
355
|
Qt::CoreApplication.instance.processEvents
|
356
|
+
Qt::RubyThreadFix.queue.pop.call until Qt::RubyThreadFix.queue.empty?
|
256
357
|
Cosmos.kill_thread(self, @tab_thread)
|
257
358
|
@tab_thread = nil
|
258
359
|
end
|
@@ -262,12 +363,18 @@ module Cosmos
|
|
262
363
|
# Finally it sleeps using a sleeper so it can be interrupted.
|
263
364
|
#
|
264
365
|
# @param name [String] Name of the tab
|
265
|
-
def handle_tab(name)
|
366
|
+
def handle_tab(name, period = 1.0)
|
367
|
+
@tab_thread_shutdown = false
|
266
368
|
@tab_thread = Thread.new do
|
267
369
|
begin
|
268
370
|
while true
|
371
|
+
start_time = Time.now.sys
|
372
|
+
break if @tab_thread_shutdown
|
269
373
|
Qt.execute_in_main_thread(true) { yield }
|
270
|
-
|
374
|
+
total_time = Time.now.sys - start_time
|
375
|
+
if total_time > 0.0 and total_time < period
|
376
|
+
break if @tab_sleeper.sleep(period - total_time)
|
377
|
+
end
|
271
378
|
end
|
272
379
|
rescue Exception => error
|
273
380
|
Qt.execute_in_main_thread(true) {|| ExceptionDialog.new(self, error, "COSMOS CTS : #{name} Tab Thread")}
|
@@ -275,22 +382,11 @@ module Cosmos
|
|
275
382
|
end
|
276
383
|
end
|
277
384
|
|
278
|
-
|
279
|
-
|
280
|
-
@
|
281
|
-
|
282
|
-
|
283
|
-
start_time = Time.now.sys
|
284
|
-
Qt.execute_in_main_thread(true) { @status_tab.update }
|
285
|
-
total_time = Time.now.sys - start_time
|
286
|
-
if total_time > 0.0 and total_time < 1.0
|
287
|
-
break if @tab_sleeper.sleep(1.0 - total_time)
|
288
|
-
end
|
289
|
-
end
|
290
|
-
rescue Exception => error
|
291
|
-
Qt.execute_in_main_thread(true) {|| ExceptionDialog.new(self, error, "COSMOS CTS : Status Tab Thread")}
|
292
|
-
end
|
293
|
-
end
|
385
|
+
def stop_threads
|
386
|
+
kill_tab_thread()
|
387
|
+
@replay_tab.shutdown if @replay_tab
|
388
|
+
CmdTlmServer.instance.stop_logging('ALL') if @mode == :CMD_TLM_SERVER
|
389
|
+
CmdTlmServer.instance.stop
|
294
390
|
end
|
295
391
|
|
296
392
|
# Called when the user tries to close the server application. Popup a
|
@@ -303,7 +399,11 @@ module Cosmos
|
|
303
399
|
else
|
304
400
|
msg = Qt::MessageBox.new(self)
|
305
401
|
msg.setIcon(Qt::MessageBox::Question)
|
306
|
-
|
402
|
+
if @mode == :CMD_TLM_SERVER
|
403
|
+
msg.setText("Are you sure? All tools connected to this CmdTlmServer will lose connections and cease to function if the CmdTlmServer is closed.")
|
404
|
+
else
|
405
|
+
msg.setText("Are you sure? All tools connected to this Replay will lose connections and cease to function if the Replay is closed.")
|
406
|
+
end
|
307
407
|
msg.setWindowTitle('Confirm Close')
|
308
408
|
msg.setStandardButtons(Qt::MessageBox::Yes | Qt::MessageBox::No)
|
309
409
|
continue = false
|
@@ -312,9 +412,7 @@ module Cosmos
|
|
312
412
|
end
|
313
413
|
|
314
414
|
if continue
|
315
|
-
|
316
|
-
CmdTlmServer.instance.stop_logging('ALL')
|
317
|
-
CmdTlmServer.instance.stop
|
415
|
+
stop_threads()
|
318
416
|
super(event)
|
319
417
|
else
|
320
418
|
event.ignore()
|
@@ -327,7 +425,7 @@ module Cosmos
|
|
327
425
|
# Start thread to read server messages
|
328
426
|
@output_thread = Thread.new do
|
329
427
|
begin
|
330
|
-
while !@
|
428
|
+
while !@ready
|
331
429
|
sleep(1)
|
332
430
|
end
|
333
431
|
while true
|
@@ -347,10 +445,10 @@ module Cosmos
|
|
347
445
|
def handle_string_output
|
348
446
|
if @string_output.string[-1..-1] == "\n"
|
349
447
|
Qt.execute_in_main_thread(true) do
|
350
|
-
lines_to_write =
|
448
|
+
lines_to_write = []
|
351
449
|
string = @string_output.string.clone
|
352
450
|
@string_output.string = @string_output.string[string.length..-1]
|
353
|
-
string.each_line {|out_line| @output.add_formatted_text(out_line)
|
451
|
+
string.each_line {|out_line| lines_to_write << out_line; @output.add_formatted_text(out_line) }
|
354
452
|
@output.flush
|
355
453
|
if @first_output < 2
|
356
454
|
# Scroll to the bottom on the first two outputs for Linux
|
@@ -358,7 +456,9 @@ module Cosmos
|
|
358
456
|
@output.verticalScrollBar.value = @output.verticalScrollBar.maximum
|
359
457
|
@first_output += 1
|
360
458
|
end
|
361
|
-
|
459
|
+
clean_lines, messages = CmdTlmServerGui.process_output_colors(lines_to_write)
|
460
|
+
@message_log.write(clean_lines) if @message_log
|
461
|
+
messages.each {|msg| CmdTlmServer.instance.post_server_message(msg) }
|
362
462
|
end
|
363
463
|
end
|
364
464
|
end
|
@@ -366,11 +466,13 @@ module Cosmos
|
|
366
466
|
# CmdTlmServer stop callback called by CmdTlmServer.stop. Ensures all the
|
367
467
|
# output is written to the message logs.
|
368
468
|
def stop_callback
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
469
|
+
Qt.execute_in_main_thread(true) do
|
470
|
+
handle_string_output()
|
471
|
+
@output_sleeper.cancel
|
472
|
+
Qt::CoreApplication.processEvents()
|
473
|
+
Cosmos.kill_thread(self, @output_thread)
|
474
|
+
handle_string_output()
|
475
|
+
end
|
374
476
|
end
|
375
477
|
|
376
478
|
def graceful_kill
|
@@ -383,12 +485,14 @@ module Cosmos
|
|
383
485
|
|
384
486
|
def self.no_gui_handle_string_output
|
385
487
|
if @string_output.string[-1..-1] == "\n"
|
386
|
-
lines_to_write =
|
488
|
+
lines_to_write = []
|
387
489
|
string = @string_output.string.clone
|
388
490
|
@string_output.string = @string_output.string[string.length..-1]
|
389
491
|
string.each_line {|out_line| lines_to_write << out_line }
|
390
|
-
|
391
|
-
|
492
|
+
clean_lines, messages = CmdTlmServerGui.process_output_colors(lines_to_write)
|
493
|
+
@message_log.write(clean_lines) if @mode == :CMD_TLM_SERVER
|
494
|
+
messages.each {|msg| CmdTlmServer.instance.post_server_message(msg) }
|
495
|
+
STDOUT.print clean_lines if STDIN.isatty # Have a console
|
392
496
|
end
|
393
497
|
end
|
394
498
|
|
@@ -399,7 +503,47 @@ module Cosmos
|
|
399
503
|
no_gui_handle_string_output()
|
400
504
|
end
|
401
505
|
|
506
|
+
def self.no_gui_reload_callback(confirm = false)
|
507
|
+
CmdTlmServer.instance.stop_logging('ALL') if @mode == :CMD_TLM_SERVER
|
508
|
+
CmdTlmServer.instance.stop_callback = nil
|
509
|
+
CmdTlmServer.instance.stop
|
510
|
+
System.reset
|
511
|
+
cts = CmdTlmServer.new(@options.config_file, @options.production, false, @mode)
|
512
|
+
|
513
|
+
# Signal catching needs to be repeated here because Puma interferes
|
514
|
+
["TERM", "INT"].each {|sig| Signal.trap(sig) {exit}}
|
515
|
+
|
516
|
+
@message_log = CmdTlmServer.message_log
|
517
|
+
cts.stop_callback = method(:no_gui_stop_callback)
|
518
|
+
cts.reload_callback = method(:no_gui_reload_callback)
|
519
|
+
end
|
520
|
+
|
521
|
+
def self.process_output_colors(lines)
|
522
|
+
clean_lines = ''
|
523
|
+
messages = []
|
524
|
+
lines.each do |line|
|
525
|
+
if line =~ /<G>/
|
526
|
+
line.gsub!(/<G>/, BLANK)
|
527
|
+
messages << [line.strip, 'GREEN']
|
528
|
+
elsif line =~ /<Y>/
|
529
|
+
line.gsub!(/<Y>/, BLANK)
|
530
|
+
messages << [line.strip, 'YELLOW']
|
531
|
+
elsif line =~ /<R>/
|
532
|
+
line.gsub!(/<R>/, BLANK)
|
533
|
+
messages << [line.strip, 'RED']
|
534
|
+
elsif line =~ /<B>/
|
535
|
+
line.gsub!(/<B>/, BLANK)
|
536
|
+
messages << [line.strip, 'BLUE']
|
537
|
+
else
|
538
|
+
messages << [line.strip, 'BLACK']
|
539
|
+
end
|
540
|
+
clean_lines << line
|
541
|
+
end
|
542
|
+
return [clean_lines, messages]
|
543
|
+
end
|
544
|
+
|
402
545
|
def self.post_options_parsed_hook(options)
|
546
|
+
@options = options
|
403
547
|
if options.no_gui
|
404
548
|
["TERM", "INT"].each {|sig| Signal.trap(sig) {exit}}
|
405
549
|
|
@@ -408,8 +552,18 @@ module Cosmos
|
|
408
552
|
@string_output = StringIO.new("", "r+")
|
409
553
|
$stdout = @string_output
|
410
554
|
Logger.level = Logger::INFO
|
411
|
-
|
555
|
+
if options.replay
|
556
|
+
@mode = :REPLAY
|
557
|
+
else
|
558
|
+
@mode = :CMD_TLM_SERVER
|
559
|
+
end
|
560
|
+
cts = CmdTlmServer.new(options.config_file, options.production, false, @mode)
|
561
|
+
|
562
|
+
# Signal catching needs to be repeated here because Puma interferes
|
563
|
+
["TERM", "INT"].each {|sig| Signal.trap(sig) {exit}}
|
564
|
+
|
412
565
|
@message_log = CmdTlmServer.message_log
|
566
|
+
@ready = true
|
413
567
|
@output_thread = Thread.new do
|
414
568
|
while true
|
415
569
|
no_gui_handle_string_output()
|
@@ -417,29 +571,34 @@ module Cosmos
|
|
417
571
|
end
|
418
572
|
end
|
419
573
|
cts.stop_callback = method(:no_gui_stop_callback)
|
574
|
+
cts.reload_callback = method(:no_gui_reload_callback)
|
420
575
|
sleep # Sleep until waked by signal
|
421
576
|
ensure
|
422
|
-
if
|
423
|
-
|
424
|
-
|
577
|
+
if CmdTlmServer.instance
|
578
|
+
CmdTlmServer.instance.stop_logging('ALL') if @mode == :CMD_TLM_SERVER
|
579
|
+
CmdTlmServer.instance.stop
|
425
580
|
end
|
426
581
|
end
|
427
582
|
return false
|
428
583
|
else
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
584
|
+
CmdTlmServerGui.configure_signal_handlers()
|
585
|
+
return true
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
def self.configure_signal_handlers
|
590
|
+
["TERM", "INT"].each do |sig|
|
591
|
+
Signal.trap(sig) do
|
592
|
+
# No synchronization is allowed in trap context, so we have
|
593
|
+
# to spawn a thread here to send the close event.
|
594
|
+
Thread.new do
|
595
|
+
Qt.execute_in_main_thread(true) do
|
596
|
+
@@window.no_prompt = true
|
597
|
+
@@window.closeEvent(Qt::CloseEvent.new())
|
598
|
+
exit
|
439
599
|
end
|
440
600
|
end
|
441
601
|
end
|
442
|
-
return true
|
443
602
|
end
|
444
603
|
end
|
445
604
|
|
@@ -457,6 +616,13 @@ module Cosmos
|
|
457
616
|
options.production = false
|
458
617
|
options.no_prompt = false
|
459
618
|
options.no_gui = false
|
619
|
+
if self.name == "Cosmos::Replay"
|
620
|
+
options.replay = true
|
621
|
+
options.title = "Replay"
|
622
|
+
else
|
623
|
+
options.replay = false
|
624
|
+
end
|
625
|
+
|
460
626
|
option_parser.separator "CTS Specific Options:"
|
461
627
|
option_parser.on("-c", "--config FILE", "Use the specified configuration file") do |arg|
|
462
628
|
options.config_file = arg
|