cosmos 3.1.1 → 3.1.2
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/Manifest.txt +6 -0
- data/autohotkey/config/tools/handbook_creator/templates/command_packets.html.erb +1 -1
- data/autohotkey/config/tools/handbook_creator/templates/footer.html.erb +2 -2
- data/autohotkey/config/tools/handbook_creator/templates/header.html.erb +4 -4
- data/autohotkey/tools/autohotkey.rb +1 -1
- data/autohotkey/tools/cmd_tlm_server.ahk +1 -0
- data/autohotkey/tools/packet_viewer.ahk +45 -2
- data/data/crc.txt +20 -15
- data/demo/Rakefile +16 -0
- data/demo/config/data/crc.txt +3 -3
- data/demo/config/tools/handbook_creator/templates/footer.html.erb +2 -2
- data/demo/config/tools/handbook_creator/templates/header.html.erb +4 -4
- data/demo/procedures/example_test.rb +1 -1
- data/install/Rakefile +16 -0
- data/install/config/data/crc.txt +2 -2
- data/install/config/tools/handbook_creator/templates/footer.html.erb +2 -2
- data/install/config/tools/handbook_creator/templates/header.html.erb +4 -4
- data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +64 -57
- data/lib/cosmos/gui/line_graph/line_graph_scaling.rb +0 -9
- data/lib/cosmos/gui/qt.rb +22 -18
- data/lib/cosmos/packet_logs/packet_log_writer.rb +6 -2
- data/lib/cosmos/script/script.rb +1 -1
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +0 -1
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +99 -784
- data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +189 -0
- data/lib/cosmos/tools/cmd_tlm_server/gui/logging_tab.rb +176 -0
- data/lib/cosmos/tools/cmd_tlm_server/gui/packets_tab.rb +144 -0
- data/lib/cosmos/tools/cmd_tlm_server/gui/status_tab.rb +240 -0
- data/lib/cosmos/tools/cmd_tlm_server/gui/targets_tab.rb +90 -0
- data/lib/cosmos/tools/launcher/launcher_config.rb +142 -110
- data/lib/cosmos/tools/test_runner/results_writer.rb +1 -1
- data/lib/cosmos/tools/test_runner/test_runner.rb +3 -2
- data/lib/cosmos/tools/tlm_grapher/data_objects/data_object.rb +18 -2
- data/lib/cosmos/tools/tlm_grapher/data_objects/housekeeping_data_object.rb +4 -9
- data/lib/cosmos/tools/tlm_grapher/data_objects/xy_data_object.rb +5 -5
- data/lib/cosmos/top_level.rb +1 -1
- data/lib/cosmos/version.rb +4 -4
- data/run_gui_tests.bat +33 -31
- data/spec/core_ext/time_spec.rb +51 -0
- data/spec/script/script_spec.rb +96 -0
- data/spec/tools/cmd_tlm_server/commanding_spec.rb +28 -0
- data/spec/tools/cmd_tlm_server/connections_spec.rb +88 -0
- data/spec/tools/cmd_tlm_server/router_thread_spec.rb +78 -25
- data/spec/tools/launcher/launcher_config_spec.rb +460 -0
- data/spec/top_level/top_level_spec.rb +1 -1
- metadata +8 -2
@@ -275,14 +275,6 @@ module Cosmos
|
|
275
275
|
@x_grid_lines = []
|
276
276
|
|
277
277
|
@x_grid_line_scale = determine_grid_line_scale(@manual_x_grid_line_scale, @x_min, @x_max)
|
278
|
-
if @manual_x_grid_line_scale
|
279
|
-
@x_grid_line_scale = @manual_x_grid_line_scale
|
280
|
-
else
|
281
|
-
diff = @x_max - @x_min
|
282
|
-
@x_grid_line_scale = calculate_base(diff)
|
283
|
-
end
|
284
|
-
@x_grid_line_scale = 1.0 if @x_grid_line_scale < 1
|
285
|
-
|
286
278
|
if @show_x_grid_lines
|
287
279
|
states = @lines.single_line_with_x_states
|
288
280
|
if states
|
@@ -451,7 +443,6 @@ module Cosmos
|
|
451
443
|
diff = max - min
|
452
444
|
scale = calculate_base(diff)
|
453
445
|
end
|
454
|
-
scale = 1.0 if scale < 1
|
455
446
|
return scale
|
456
447
|
end
|
457
448
|
|
data/lib/cosmos/gui/qt.rb
CHANGED
@@ -670,44 +670,46 @@ end
|
|
670
670
|
|
671
671
|
class Qt::Painter
|
672
672
|
def addLineColor(x, y, w, h, color = Cosmos::BLACK)
|
673
|
-
|
674
|
-
setPen(color)
|
673
|
+
setPenColor(color)
|
675
674
|
drawLine(x,y,w,h)
|
676
675
|
end
|
677
676
|
|
678
677
|
def addRectColor(x, y, w, h, color = Cosmos::BLACK)
|
679
|
-
|
680
|
-
setPen(color)
|
678
|
+
setPenColor(color)
|
681
679
|
setBrush(nil)
|
682
680
|
drawRect(x,y,w,h)
|
683
681
|
end
|
684
682
|
|
685
683
|
def addRectColorFill(x, y, w, h, color = Cosmos::BLACK)
|
686
|
-
|
687
|
-
setPen(color)
|
684
|
+
setPenColor(color)
|
688
685
|
setBrush(Cosmos.getBrush(color))
|
689
686
|
drawRect(x,y,w,h)
|
690
687
|
end
|
691
688
|
|
692
689
|
def addSimpleTextAt(text, x, y, color = Cosmos::BLACK)
|
693
|
-
|
694
|
-
|
695
|
-
drawText(x, y, text)
|
690
|
+
setPenColor(color)
|
691
|
+
drawText(x,y,text)
|
696
692
|
end
|
697
693
|
|
698
694
|
def addEllipseColor(x, y, w, h, color = Cosmos::BLACK)
|
699
|
-
|
700
|
-
setPen(color)
|
695
|
+
setPenColor(color)
|
701
696
|
setBrush(nil)
|
702
697
|
drawEllipse(x,y,w,h)
|
703
698
|
end
|
704
699
|
|
705
700
|
def addEllipseColorFill(x, y, w, h, color = Cosmos::BLACK)
|
706
|
-
|
707
|
-
setPen(color)
|
701
|
+
setPenColor(color)
|
708
702
|
setBrush(Cosmos.getBrush(color))
|
709
703
|
drawEllipse(x,y,w,h)
|
710
704
|
end
|
705
|
+
|
706
|
+
private
|
707
|
+
|
708
|
+
def setPenColor(color)
|
709
|
+
color = Cosmos::getColor(color)
|
710
|
+
setPen(color)
|
711
|
+
end
|
712
|
+
|
711
713
|
end
|
712
714
|
|
713
715
|
class Qt::MatrixLayout < Qt::GridLayout
|
@@ -720,15 +722,17 @@ class Qt::MatrixLayout < Qt::GridLayout
|
|
720
722
|
|
721
723
|
def addWidget(widget)
|
722
724
|
super(widget, @row, @col)
|
723
|
-
|
724
|
-
if @col == @num_columns
|
725
|
-
@row += 1
|
726
|
-
@col = 0
|
727
|
-
end
|
725
|
+
increment_row_col()
|
728
726
|
end
|
729
727
|
|
730
728
|
def addLayout(layout)
|
731
729
|
super(layout, @row, @col)
|
730
|
+
increment_row_col()
|
731
|
+
end
|
732
|
+
|
733
|
+
private
|
734
|
+
|
735
|
+
def increment_row_col
|
732
736
|
@col += 1 if @col < @num_columns
|
733
737
|
if @col == @num_columns
|
734
738
|
@row += 1
|
@@ -278,8 +278,12 @@ module Cosmos
|
|
278
278
|
|
279
279
|
def cycle_thread_body
|
280
280
|
while true
|
281
|
-
|
282
|
-
|
281
|
+
# The check against start_time needs to be mutex protected to prevent a packet coming in between the check
|
282
|
+
# and closing the file
|
283
|
+
@mutex.synchronize do
|
284
|
+
if @logging_enabled and @cycle_time and (Time.now - @start_time) > @cycle_time
|
285
|
+
close_file(false)
|
286
|
+
end
|
283
287
|
end
|
284
288
|
# Only check whether to cycle at a set interval
|
285
289
|
break if @cycle_sleeper.sleep(CYCLE_TIME_INTERVAL)
|
data/lib/cosmos/script/script.rb
CHANGED
@@ -926,7 +926,7 @@ module Cosmos
|
|
926
926
|
tlm_viewer.clear(display_name)
|
927
927
|
tlm_viewer.disconnect
|
928
928
|
rescue DRb::DRbConnError
|
929
|
-
raise "Unable to Successfully Start Listening Telemetry Viewer: #{display_name} could not be
|
929
|
+
raise "Unable to Successfully Start Listening Telemetry Viewer: #{display_name} could not be cleared"
|
930
930
|
rescue Errno::ENOENT
|
931
931
|
raise "Display Screen File: #{display_name}.txt does not exist"
|
932
932
|
end
|
@@ -108,7 +108,6 @@ module Cosmos
|
|
108
108
|
parser.verify_num_parameters(1, 2, usage)
|
109
109
|
target = System.targets[params[0].upcase]
|
110
110
|
raise parser.error("Unknown target: #{params[0].upcase}") unless target
|
111
|
-
raise parser.error("Cannot use #{keyword} with target name substitutions: #{target.name} != #{target.original_name}") if target.name != target.original_name
|
112
111
|
target_filename = params[1]
|
113
112
|
target_filename = 'cmd_tlm_server.txt' unless target_filename
|
114
113
|
target_filename = File.join(target.dir, target_filename)
|
@@ -10,9 +10,13 @@
|
|
10
10
|
|
11
11
|
require 'cosmos'
|
12
12
|
require 'cosmos/tools/cmd_tlm_server/cmd_tlm_server'
|
13
|
+
require 'cosmos/tools/cmd_tlm_server/gui/interfaces_tab'
|
14
|
+
require 'cosmos/tools/cmd_tlm_server/gui/targets_tab'
|
15
|
+
require 'cosmos/tools/cmd_tlm_server/gui/packets_tab'
|
16
|
+
require 'cosmos/tools/cmd_tlm_server/gui/logging_tab'
|
17
|
+
require 'cosmos/tools/cmd_tlm_server/gui/status_tab'
|
13
18
|
require 'cosmos/gui/qt_tool'
|
14
19
|
require 'cosmos/gui/dialogs/splash'
|
15
|
-
require 'cosmos/gui/dialogs/cmd_tlm_raw_dialog'
|
16
20
|
require 'cosmos/gui/dialogs/exception_dialog'
|
17
21
|
require 'cosmos/gui/dialogs/set_tlm_dialog'
|
18
22
|
|
@@ -28,8 +32,7 @@ module Cosmos
|
|
28
32
|
RUNNING = 1
|
29
33
|
ERROR = 2
|
30
34
|
|
31
|
-
|
32
|
-
TLM = "Telemetry"
|
35
|
+
TOOL_NAME = "Command and Telemetry Server"
|
33
36
|
|
34
37
|
# For the CTS we display all the tables as full size
|
35
38
|
# Thus we don't want the table to absorb the scroll wheel events but
|
@@ -55,17 +58,25 @@ module Cosmos
|
|
55
58
|
@no_prompt = options.no_prompt
|
56
59
|
@message_log = nil
|
57
60
|
@output_sleeper = Sleeper.new
|
61
|
+
@interfaces_tab = InterfacesTab.new
|
62
|
+
@targets_tab = TargetsTab.new
|
63
|
+
@packets_tab = PacketsTab.new(self)
|
64
|
+
@logging_tab = LoggingTab.new(@production)
|
65
|
+
@status_tab = StatusTab.new
|
58
66
|
|
59
67
|
statusBar.showMessage(tr("")) # Show blank message to initialize status bar
|
60
68
|
|
61
69
|
initialize_actions()
|
62
70
|
initialize_menus()
|
63
71
|
initialize_central_widget()
|
72
|
+
configure_tabs(options)
|
64
73
|
complete_initialize()
|
74
|
+
end
|
65
75
|
|
76
|
+
def configure_tabs(options)
|
66
77
|
Splash.execute(self) do |splash|
|
67
78
|
ConfigParser.splash = splash
|
68
|
-
splash.message = "Initializing #{
|
79
|
+
splash.message = "Initializing #{TOOL_NAME}"
|
69
80
|
|
70
81
|
# Start the thread that will process server messages and add them to the output text
|
71
82
|
process_server_messages(options)
|
@@ -81,19 +92,19 @@ module Cosmos
|
|
81
92
|
# Override the default title if one was given in the config file
|
82
93
|
self.window_title = CmdTlmServer.title if CmdTlmServer.title
|
83
94
|
splash.progress = 0
|
84
|
-
populate_interfaces(
|
95
|
+
@interfaces_tab.populate_interfaces(@tab_widget)
|
85
96
|
splash.progress = 100/7 * 1
|
86
|
-
|
97
|
+
@targets_tab.populate(@tab_widget)
|
87
98
|
splash.progress = 100/7 * 2
|
88
|
-
|
99
|
+
@packets_tab.populate_commands(@tab_widget)
|
89
100
|
splash.progress = 100/7 * 3
|
90
|
-
|
101
|
+
@packets_tab.populate_telemetry(@tab_widget)
|
91
102
|
splash.progress = 100/7 * 4
|
92
|
-
|
103
|
+
@interfaces_tab.populate_routers(@tab_widget)
|
93
104
|
splash.progress = 100/7 * 5
|
94
|
-
|
105
|
+
@logging_tab.populate(@tab_widget)
|
95
106
|
splash.progress = 100/7 * 6
|
96
|
-
|
107
|
+
@status_tab.populate(@tab_widget)
|
97
108
|
splash.progress = 100
|
98
109
|
end
|
99
110
|
ConfigParser.splash = nil
|
@@ -106,7 +117,7 @@ module Cosmos
|
|
106
117
|
# Edit actions
|
107
118
|
@edit_clear_counters = Qt::Action.new(tr('&Clear Counters'), self)
|
108
119
|
@edit_clear_counters.statusTip = tr('Clear counters for all interfaces and targets')
|
109
|
-
@edit_clear_counters.connect(SIGNAL('triggered()')) {
|
120
|
+
@edit_clear_counters.connect(SIGNAL('triggered()')) { CmdTlmServer.clear_counters }
|
110
121
|
end
|
111
122
|
|
112
123
|
def initialize_menus
|
@@ -119,29 +130,20 @@ module Cosmos
|
|
119
130
|
@edit_menu.addAction(@edit_clear_counters)
|
120
131
|
end
|
121
132
|
|
122
|
-
@about_string = "#{
|
133
|
+
@about_string = "#{TOOL_NAME} is the heart of the COSMOS system. "
|
123
134
|
@about_string << "It connects to the target and processes command and telemetry requests from other tools."
|
124
135
|
|
125
136
|
initialize_help_menu()
|
126
137
|
end
|
127
138
|
|
128
|
-
###########################################
|
129
|
-
# Edit Menu Options
|
130
|
-
###########################################
|
131
|
-
|
132
|
-
# Edit->Clear Counters
|
133
|
-
def edit_clear_counters
|
134
|
-
CmdTlmServer.clear_counters
|
135
|
-
end
|
136
|
-
|
137
139
|
def initialize_central_widget
|
138
140
|
# Create the central widget
|
139
141
|
@splitter = Qt::Splitter.new(Qt::Vertical, central_widget)
|
140
142
|
setCentralWidget(@splitter)
|
141
143
|
|
142
|
-
@
|
143
|
-
connect(@
|
144
|
-
@splitter.addWidget(@
|
144
|
+
@tab_widget = Qt::TabWidget.new
|
145
|
+
connect(@tab_widget, SIGNAL('currentChanged(int)'), self, SLOT('handle_tab_change(int)'))
|
146
|
+
@splitter.addWidget(@tab_widget)
|
145
147
|
|
146
148
|
# Add the message output
|
147
149
|
@output = Qt::PlainTextEdit.new
|
@@ -149,7 +151,7 @@ module Cosmos
|
|
149
151
|
@output.setMaximumBlockCount(10000) # 10000 lines of history will be displayed
|
150
152
|
|
151
153
|
@splitter.addWidget(@output)
|
152
|
-
# Set the stretch factor to give priority to the
|
154
|
+
# Set the stretch factor to give priority to the tab_widget (index 0) instead of the output (index 1)
|
153
155
|
@splitter.setStretchFactor(0, 1) # (index, stretch)
|
154
156
|
|
155
157
|
# Override stdout to the message window
|
@@ -161,777 +163,83 @@ module Cosmos
|
|
161
163
|
@tab_thread = nil
|
162
164
|
end
|
163
165
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
Cosmos.kill_thread(self, @tab_thread)
|
168
|
-
@tab_thread = nil
|
169
|
-
end
|
170
|
-
|
166
|
+
# Called when the user changes tabs in the Server application. It kills the
|
167
|
+
# currently executing tab and then creates a new thread to update the GUI
|
168
|
+
# for the selected tab.
|
171
169
|
def handle_tab_change(index)
|
172
170
|
kill_tab_thread()
|
173
171
|
@tab_sleeper = Sleeper.new
|
172
|
+
|
174
173
|
case index
|
175
174
|
when 0
|
176
|
-
|
175
|
+
handle_tab('Interfaces') { @interfaces_tab.update(InterfacesTab::INTERFACES) }
|
177
176
|
when 1
|
178
|
-
|
177
|
+
handle_tab('Targets') { @targets_tab.update }
|
179
178
|
when 2
|
180
|
-
|
179
|
+
handle_tab('Packets') { @packets_tab.update(PacketsTab::COMMANDS) }
|
181
180
|
when 3
|
182
|
-
|
181
|
+
handle_tab('Telemetry') { @packets_tab.update(PacketsTab::TELEMETRY) }
|
183
182
|
when 4
|
184
|
-
|
183
|
+
handle_tab('Routers') { @interfaces_tab.update(InterfacesTab::ROUTERS) }
|
185
184
|
when 5
|
186
|
-
|
185
|
+
handle_tab('Logging') { @logging_tab.update }
|
187
186
|
when 6
|
188
187
|
handle_status_tab()
|
189
188
|
end
|
190
189
|
end
|
191
190
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
if
|
196
|
-
|
197
|
-
|
198
|
-
interfaces = CmdTlmServer.interfaces
|
199
|
-
end
|
200
|
-
|
201
|
-
num_interfaces = interfaces.names.length
|
202
|
-
if interfaces.names.length > 0
|
203
|
-
scroll = Qt::ScrollArea.new
|
204
|
-
scroll.setMinimumSize(800, 150)
|
205
|
-
widget = Qt::Widget.new
|
206
|
-
layout = Qt::VBoxLayout.new(widget)
|
207
|
-
# Since the layout will be inside a scroll area make sure it respects the sizes we set
|
208
|
-
layout.setSizeConstraint(Qt::Layout::SetMinAndMaxSize)
|
209
|
-
|
210
|
-
interfaces_table = Qt::TableWidget.new()
|
211
|
-
interfaces_table.verticalHeader.hide()
|
212
|
-
interfaces_table.setRowCount(num_interfaces)
|
213
|
-
interfaces_table.setColumnCount(10)
|
214
|
-
if name == 'Routers'
|
215
|
-
interfaces_table.setHorizontalHeaderLabels(["Router", "Connect/Disconnect", "Connected?", "Clients", "Tx Q Size", "Rx Q Size", " Bytes Tx ", " Bytes Rx ", " Cmd Pkts ", " Tlm Pkts "])
|
216
|
-
else
|
217
|
-
interfaces_table.setHorizontalHeaderLabels(["Interface", "Connect/Disconnect", "Connected?", "Clients", "Tx Q Size", "Rx Q Size", " Bytes Tx ", " Bytes Rx ", " Cmd Pkts ", " Tlm Pkts "])
|
218
|
-
end
|
219
|
-
|
220
|
-
row = 0
|
221
|
-
interfaces.all.each do |interface_name, interface|
|
222
|
-
item = Qt::TableWidgetItem.new(tr(interface_name))
|
223
|
-
item.setTextAlignment(Qt::AlignCenter)
|
224
|
-
interfaces_table.setItem(row, 0, item)
|
225
|
-
|
226
|
-
if interface.connected?
|
227
|
-
button_text = 'Disconnect'
|
228
|
-
elsif interface.thread.nil?
|
229
|
-
button_text = 'Connect'
|
230
|
-
else
|
231
|
-
button_text = 'Cancel Connect'
|
232
|
-
end
|
233
|
-
button = Qt::PushButton.new(button_text)
|
234
|
-
if name == 'Routers'
|
235
|
-
button.connect(SIGNAL('clicked()')) do
|
236
|
-
if interface.thread
|
237
|
-
Logger.info "User disconnecting router #{interface_name}"
|
238
|
-
CmdTlmServer.instance.disconnect_router(interface_name)
|
239
|
-
else
|
240
|
-
Logger.info "User connecting router #{interface_name}"
|
241
|
-
CmdTlmServer.instance.connect_router(interface_name)
|
242
|
-
end
|
243
|
-
end
|
244
|
-
else
|
245
|
-
button.connect(SIGNAL('clicked()')) do
|
246
|
-
if interface.thread
|
247
|
-
Logger.info "User disconnecting interface #{interface_name}"
|
248
|
-
CmdTlmServer.instance.disconnect_interface(interface_name)
|
249
|
-
else
|
250
|
-
Logger.info "User connecting interface #{interface_name}"
|
251
|
-
CmdTlmServer.instance.connect_interface(interface_name)
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|
255
|
-
button.setDisabled(true) if interface.disable_disconnect
|
256
|
-
interfaces_table.setCellWidget(row, 1, button)
|
257
|
-
|
258
|
-
state = Qt::TableWidgetItem.new
|
259
|
-
if interface.connected?
|
260
|
-
state.setText('true')
|
261
|
-
state.textColor = Cosmos::GREEN
|
262
|
-
elsif interface.thread
|
263
|
-
state.setText('attempting')
|
264
|
-
state.textColor = Cosmos::YELLOW
|
265
|
-
else
|
266
|
-
state.setText('false')
|
267
|
-
state.textColor = Cosmos::BLACK
|
268
|
-
end
|
269
|
-
state.setTextAlignment(Qt::AlignCenter)
|
270
|
-
interfaces_table.setItem(row, 2, state)
|
271
|
-
|
272
|
-
num_clients = Qt::TableWidgetItem.new(tr(interface.num_clients.to_s))
|
273
|
-
num_clients.setTextAlignment(Qt::AlignCenter)
|
274
|
-
interfaces_table.setItem(row, 3, num_clients)
|
275
|
-
|
276
|
-
write_queue_size = Qt::TableWidgetItem.new(tr(interface.write_queue_size.to_s))
|
277
|
-
write_queue_size.setTextAlignment(Qt::AlignCenter)
|
278
|
-
interfaces_table.setItem(row, 4, write_queue_size)
|
279
|
-
|
280
|
-
read_queue_size = Qt::TableWidgetItem.new(tr(interface.read_queue_size.to_s))
|
281
|
-
read_queue_size.setTextAlignment(Qt::AlignCenter)
|
282
|
-
interfaces_table.setItem(row, 5, read_queue_size)
|
283
|
-
|
284
|
-
bytes_written = Qt::TableWidgetItem.new(tr(interface.bytes_written.to_s))
|
285
|
-
bytes_written.setTextAlignment(Qt::AlignCenter)
|
286
|
-
interfaces_table.setItem(row, 6, bytes_written)
|
287
|
-
|
288
|
-
bytes_read = Qt::TableWidgetItem.new(tr(interface.bytes_read.to_s))
|
289
|
-
bytes_read.setTextAlignment(Qt::AlignCenter)
|
290
|
-
interfaces_table.setItem(row, 7, bytes_read)
|
291
|
-
|
292
|
-
write_count = Qt::TableWidgetItem.new(tr(interface.write_count.to_s))
|
293
|
-
write_count.setTextAlignment(Qt::AlignCenter)
|
294
|
-
interfaces_table.setItem(row, 8, write_count)
|
295
|
-
|
296
|
-
read_count = Qt::TableWidgetItem.new(tr(interface.read_count.to_s))
|
297
|
-
read_count.setTextAlignment(Qt::AlignCenter)
|
298
|
-
interfaces_table.setItem(row, 9, read_count)
|
299
|
-
|
300
|
-
row += 1
|
301
|
-
end
|
302
|
-
interfaces_table.displayFullSize
|
303
|
-
|
304
|
-
layout.addWidget(interfaces_table)
|
305
|
-
scroll.setWidget(widget)
|
306
|
-
if name == 'Routers'
|
307
|
-
@tabbook.addTab(scroll, "Routers")
|
308
|
-
@interfaces_table['Routers'] = interfaces_table
|
309
|
-
else
|
310
|
-
@tabbook.addTab(scroll, "Interfaces")
|
311
|
-
@interfaces_table['Interfaces'] = interfaces_table
|
312
|
-
end
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
def handle_interfaces_tab(name)
|
317
|
-
@tab_thread = Thread.new do
|
318
|
-
if @interfaces_table[name]
|
319
|
-
begin
|
320
|
-
while true
|
321
|
-
Qt.execute_in_main_thread(true) do
|
322
|
-
row = 0
|
323
|
-
if name == 'Routers'
|
324
|
-
interfaces = CmdTlmServer.routers
|
325
|
-
else
|
326
|
-
interfaces = CmdTlmServer.interfaces
|
327
|
-
end
|
328
|
-
interfaces.all.each do |interface_name, interface|
|
329
|
-
button = @interfaces_table[name].cellWidget(row,1)
|
330
|
-
state = @interfaces_table[name].item(row,2)
|
331
|
-
if interface.connected?
|
332
|
-
button.setText('Disconnect')
|
333
|
-
button.setDisabled(true) if interface.disable_disconnect
|
334
|
-
state.setText('true')
|
335
|
-
state.textColor = Cosmos::GREEN
|
336
|
-
elsif interface.thread
|
337
|
-
button.text = 'Cancel Connect'
|
338
|
-
button.setDisabled(false)
|
339
|
-
state.text = 'attempting'
|
340
|
-
state.textColor = Cosmos::RED
|
341
|
-
else
|
342
|
-
button.setText('Connect')
|
343
|
-
button.setDisabled(false)
|
344
|
-
state.setText('false')
|
345
|
-
state.textColor = Cosmos::BLACK
|
346
|
-
end
|
347
|
-
@interfaces_table[name].item(row,3).setText(interface.num_clients.to_s)
|
348
|
-
@interfaces_table[name].item(row,4).setText(interface.write_queue_size.to_s)
|
349
|
-
@interfaces_table[name].item(row,5).setText(interface.read_queue_size.to_s)
|
350
|
-
@interfaces_table[name].item(row,6).setText(interface.bytes_written.to_s)
|
351
|
-
@interfaces_table[name].item(row,7).setText(interface.bytes_read.to_s)
|
352
|
-
if name == 'Routers'
|
353
|
-
@interfaces_table[name].item(row,8).setText(interface.read_count.to_s)
|
354
|
-
@interfaces_table[name].item(row,9).setText(interface.write_count.to_s)
|
355
|
-
else
|
356
|
-
@interfaces_table[name].item(row,8).setText(interface.write_count.to_s)
|
357
|
-
@interfaces_table[name].item(row,9).setText(interface.read_count.to_s)
|
358
|
-
end
|
359
|
-
row += 1
|
360
|
-
end
|
361
|
-
end
|
362
|
-
break if @tab_sleeper.sleep(1)
|
363
|
-
end
|
364
|
-
rescue Exception => error
|
365
|
-
Qt.execute_in_main_thread(true) {|| ExceptionDialog.new(self, error, "COSMOS CTS : #{name} Tab Thread")}
|
366
|
-
end
|
367
|
-
end
|
368
|
-
end
|
369
|
-
end
|
370
|
-
|
371
|
-
def populate_targets
|
372
|
-
num_targets = System.targets.length
|
373
|
-
if num_targets > 0
|
374
|
-
return if num_targets == 1 and System.targets['SYSTEM']
|
375
|
-
num_targets -= 1 if System.targets['SYSTEM']
|
376
|
-
|
377
|
-
scroll = Qt::ScrollArea.new
|
378
|
-
widget = Qt::Widget.new
|
379
|
-
layout = Qt::VBoxLayout.new(widget)
|
380
|
-
# Since the layout will be inside a scroll area make sure it respects the sizes we set
|
381
|
-
layout.setSizeConstraint(Qt::Layout::SetMinAndMaxSize)
|
382
|
-
|
383
|
-
@targets_table = Qt::TableWidget.new()
|
384
|
-
@targets_table.verticalHeader.hide()
|
385
|
-
@targets_table.setRowCount(num_targets)
|
386
|
-
@targets_table.setColumnCount(4)
|
387
|
-
@targets_table.setHorizontalHeaderLabels(["Target Name", "Interface", "#{CMD} Count", "#{TLM} Count"])
|
388
|
-
|
389
|
-
row = 0
|
390
|
-
System.targets.sort.each do |target_name, target|
|
391
|
-
next if target_name == 'SYSTEM'
|
392
|
-
target_name_widget = Qt::TableWidgetItem.new(tr(target_name))
|
393
|
-
target_name_widget.setTextAlignment(Qt::AlignCenter)
|
394
|
-
@targets_table.setItem(row, 0, target_name_widget)
|
395
|
-
if target.interface
|
396
|
-
interface_name_widget = Qt::TableWidgetItem.new(tr(target.interface.name.to_s))
|
397
|
-
else
|
398
|
-
interface_name_widget = Qt::TableWidgetItem.new(tr(''))
|
399
|
-
end
|
400
|
-
interface_name_widget.setTextAlignment(Qt::AlignCenter)
|
401
|
-
@targets_table.setItem(row, 1, interface_name_widget)
|
402
|
-
cmd_cnt = Qt::TableWidgetItem.new(tr(target.cmd_cnt.to_s))
|
403
|
-
cmd_cnt.setTextAlignment(Qt::AlignCenter)
|
404
|
-
@targets_table.setItem(row, 2, cmd_cnt)
|
405
|
-
|
406
|
-
tlm_cnt = Qt::TableWidgetItem.new(tr(target.tlm_cnt.to_s))
|
407
|
-
tlm_cnt.setTextAlignment(Qt::AlignCenter)
|
408
|
-
@targets_table.setItem(row, 3, tlm_cnt)
|
409
|
-
|
410
|
-
row += 1
|
411
|
-
end
|
412
|
-
@targets_table.displayFullSize
|
413
|
-
|
414
|
-
layout.addWidget(@targets_table)
|
415
|
-
scroll.setWidget(widget)
|
416
|
-
@tabbook.addTab(scroll, "Targets")
|
417
|
-
end
|
418
|
-
end
|
419
|
-
|
420
|
-
def handle_targets_tab
|
421
|
-
@tab_thread = Thread.new do
|
422
|
-
begin
|
423
|
-
while true
|
424
|
-
Qt.execute_in_main_thread(true) do
|
425
|
-
row = 0
|
426
|
-
System.targets.sort.each do |target_name, target|
|
427
|
-
next if target_name == 'SYSTEM'
|
428
|
-
@targets_table.item(row,2).setText(target.cmd_cnt.to_s)
|
429
|
-
@targets_table.item(row,3).setText(target.tlm_cnt.to_s)
|
430
|
-
row += 1
|
431
|
-
end
|
432
|
-
end
|
433
|
-
break if @tab_sleeper.sleep(1)
|
434
|
-
end
|
435
|
-
rescue Exception => error
|
436
|
-
Qt.execute_in_main_thread(true) {|| ExceptionDialog.new(self, error, "COSMOS CTS : Targets Tab Thread")}
|
437
|
-
end
|
438
|
-
end
|
439
|
-
end
|
440
|
-
|
441
|
-
def get_cmd_tlm_def(name)
|
442
|
-
case name
|
443
|
-
when CMD
|
444
|
-
return System.commands
|
445
|
-
when TLM
|
446
|
-
return System.telemetry
|
447
|
-
end
|
448
|
-
end
|
449
|
-
|
450
|
-
def populate_packets(name)
|
451
|
-
cmd_tlm = get_cmd_tlm_def(name)
|
452
|
-
|
453
|
-
unless cmd_tlm.target_names.empty?
|
454
|
-
count = 0
|
455
|
-
cmd_tlm.target_names.sort.each do |target_name|
|
456
|
-
packets = cmd_tlm.packets(target_name)
|
457
|
-
packets.each do |packet_name, packet|
|
458
|
-
count += 1 unless packet.hidden
|
459
|
-
end
|
460
|
-
end
|
461
|
-
|
462
|
-
scroll = Qt::ScrollArea.new
|
463
|
-
widget = Qt::Widget.new
|
464
|
-
layout = Qt::VBoxLayout.new(widget)
|
465
|
-
# Since the layout will be inside a scroll area
|
466
|
-
# make sure it respects the sizes we set
|
467
|
-
layout.setSizeConstraint(Qt::Layout::SetMinAndMaxSize)
|
468
|
-
|
469
|
-
table = Qt::TableWidget.new()
|
470
|
-
table.verticalHeader.hide()
|
471
|
-
table.setRowCount(count)
|
472
|
-
column_cnt = 4
|
473
|
-
column_cnt += 1 if name == TLM
|
474
|
-
table.setColumnCount(column_cnt)
|
475
|
-
# Force the last section to fill all available space in the frame
|
476
|
-
#~ table.horizontalHeader.setStretchLastSection(true)
|
477
|
-
headers = ["Target Name", "Packet Name", "Packet Count", "View Raw"]
|
478
|
-
headers << "View in Packet Viewer" if name == TLM
|
479
|
-
table.setHorizontalHeaderLabels(headers)
|
480
|
-
|
481
|
-
row = 0
|
482
|
-
cmd_tlm.target_names.sort.each do |target_name|
|
483
|
-
packets = cmd_tlm.packets(target_name)
|
484
|
-
packets.sort.each do |packet_name, packet|
|
485
|
-
packet.received_count ||= 0
|
486
|
-
next if packet.hidden
|
487
|
-
target_name_widget = Qt::TableWidgetItem.new(tr(target_name))
|
488
|
-
target_name_widget.setTextAlignment(Qt::AlignRight | Qt::AlignVCenter)
|
489
|
-
table.setItem(row, 0, target_name_widget)
|
490
|
-
table.setItem(row, 1, Qt::TableWidgetItem.new(tr(packet_name)))
|
491
|
-
packet_count = Qt::TableWidgetItem.new(tr(packet.received_count.to_s))
|
492
|
-
packet_count.setTextAlignment(Qt::AlignCenter)
|
493
|
-
table.setItem(row, 2, packet_count)
|
494
|
-
view_raw = Qt::PushButton.new("View Raw")
|
495
|
-
view_raw.connect(SIGNAL('clicked()')) do
|
496
|
-
@raw_dialogs ||= []
|
497
|
-
@raw_dialogs << CmdRawDialog.new(self, target_name, packet_name) if name == CMD
|
498
|
-
@raw_dialogs << TlmRawDialog.new(self, target_name, packet_name) if name == TLM
|
499
|
-
end
|
500
|
-
table.setCellWidget(row, 3, view_raw)
|
501
|
-
|
502
|
-
if name == TLM
|
503
|
-
if target_name != 'UNKNOWN' and packet_name != 'UNKNOWN'
|
504
|
-
view_pv = Qt::PushButton.new("View in Packet Viewer")
|
505
|
-
view_pv.connect(SIGNAL('clicked()')) do
|
506
|
-
if Kernel.is_windows?
|
507
|
-
Cosmos.run_process("rubyw tools/PacketViewer -p \"#{target_name} #{packet_name}\" --system #{File.basename(System.initial_filename)}")
|
508
|
-
elsif Kernel.is_mac? and File.exist?("tools/mac/PacketViewer.app")
|
509
|
-
Cosmos.run_process("open tools/mac/PacketViewer.app --args -p \"#{target_name} #{packet_name}\" --system #{File.basename(System.initial_filename)}")
|
510
|
-
else
|
511
|
-
Cosmos.run_process("ruby tools/PacketViewer -p \"#{target_name} #{packet_name}\" --system #{File.basename(System.initial_filename)}")
|
512
|
-
end
|
513
|
-
end
|
514
|
-
table.setCellWidget(row, 4, view_pv)
|
515
|
-
else
|
516
|
-
table_widget = Qt::TableWidgetItem.new(tr('N/A'))
|
517
|
-
table_widget.setTextAlignment(Qt::AlignCenter)
|
518
|
-
table.setItem(row, 4, table_widget)
|
519
|
-
end
|
520
|
-
end
|
521
|
-
|
522
|
-
row += 1
|
523
|
-
end
|
524
|
-
end
|
525
|
-
table.displayFullSize
|
526
|
-
|
527
|
-
layout.addWidget(table)
|
528
|
-
scroll.setWidget(widget)
|
529
|
-
tab_name = "Cmd Packets" if name == CMD
|
530
|
-
tab_name = "Tlm Packets" if name == TLM
|
531
|
-
@tabbook.addTab(scroll, tab_name)
|
532
|
-
|
533
|
-
@packets_table ||= {}
|
534
|
-
@packets_table[name] = table
|
535
|
-
end
|
536
|
-
end
|
537
|
-
|
538
|
-
def handle_packets_tab(name)
|
539
|
-
cmd_tlm = get_cmd_tlm_def(name)
|
540
|
-
|
541
|
-
@tab_thread = Thread.new do
|
542
|
-
begin
|
543
|
-
unless cmd_tlm.target_names.empty?
|
544
|
-
while true
|
545
|
-
Qt.execute_in_main_thread(true) do
|
546
|
-
row = 0
|
547
|
-
cmd_tlm.target_names.sort.each do |target_name|
|
548
|
-
packets = cmd_tlm.packets(target_name)
|
549
|
-
packets.sort.each do |packet_name, packet|
|
550
|
-
next if packet.hidden
|
551
|
-
@packets_table[name].item(row, 2).setText(packet.received_count.to_s)
|
552
|
-
row += 1
|
553
|
-
end
|
554
|
-
end
|
555
|
-
end
|
556
|
-
break if @tab_sleeper.sleep(1)
|
557
|
-
end
|
558
|
-
end
|
559
|
-
rescue Exception => error
|
560
|
-
Qt.execute_in_main_thread(true) {|| ExceptionDialog.new(self, error, "COSMOS CTS : #{name} Packets Tab Thread")}
|
561
|
-
end
|
562
|
-
end
|
563
|
-
end
|
564
|
-
|
565
|
-
def populate_logging_actions(layout)
|
566
|
-
# Add all the action buttons
|
567
|
-
actions = Qt::GroupBox.new(tr("Actions"))
|
568
|
-
actions_layout = Qt::VBoxLayout.new(actions)
|
569
|
-
button_layout = Qt::GridLayout.new
|
570
|
-
|
571
|
-
log_buttons = [
|
572
|
-
["Start Logging on All", [0,0], :start_logging],
|
573
|
-
["Stop Logging on All", [0,1], :stop_logging],
|
574
|
-
["Start #{TLM} Logging on All", [1,0], :start_tlm_log],
|
575
|
-
["Stop #{TLM} Logging on All", [1,1], :stop_tlm_log],
|
576
|
-
["Start #{CMD} Logging on All", [2,0], :start_cmd_log],
|
577
|
-
["Stop #{CMD} Logging on All", [2,1], :stop_cmd_log]
|
578
|
-
]
|
579
|
-
|
580
|
-
log_buttons.each do |text, location, method|
|
581
|
-
next if text =~ /Stop/ and @production
|
582
|
-
button = Qt::PushButton.new(tr(text))
|
583
|
-
button_layout.addWidget(button, location[0], location[1])
|
584
|
-
button.connect(SIGNAL('clicked()')) do
|
585
|
-
begin
|
586
|
-
CmdTlmServer.instance.send(method, 'ALL')
|
587
|
-
rescue Exception => error
|
588
|
-
statusBar.showMessage(tr(error.message))
|
589
|
-
end
|
590
|
-
end
|
591
|
-
end
|
592
|
-
|
593
|
-
actions_layout.addLayout(button_layout)
|
594
|
-
|
595
|
-
layout.addWidget(actions)
|
596
|
-
end
|
597
|
-
|
598
|
-
def create_log_layout(form_layout, log_writer, label_prefix)
|
599
|
-
label = Qt::Label.new(tr(log_writer.logging_enabled.to_s))
|
600
|
-
label.setTextInteractionFlags(Qt::TextSelectableByMouse)
|
601
|
-
form_layout.addRow("#{label_prefix} Logging:", label)
|
602
|
-
label = Qt::Label.new(tr(log_writer.queue.size.to_s))
|
603
|
-
label.setTextInteractionFlags(Qt::TextSelectableByMouse)
|
604
|
-
form_layout.addRow("#{label_prefix} Queue Size:", label)
|
605
|
-
label = Qt::Label.new(tr(log_writer.filename))
|
606
|
-
label.setTextInteractionFlags(Qt::TextSelectableByMouse)
|
607
|
-
form_layout.addRow("#{label_prefix} Filename:", label)
|
608
|
-
file_size = 0
|
609
|
-
begin
|
610
|
-
file_size = File.size(log_writer.filename) if log_writer.filename
|
611
|
-
rescue Exception
|
612
|
-
# Do nothing on error
|
613
|
-
end
|
614
|
-
label = Qt::Label.new(tr(file_size.to_s))
|
615
|
-
label.setTextInteractionFlags(Qt::TextSelectableByMouse)
|
616
|
-
form_layout.addRow("#{label_prefix} File Size:", label)
|
617
|
-
end
|
618
|
-
|
619
|
-
def populate_log_file_info(layout)
|
620
|
-
CmdTlmServer.packet_logging.all.sort.each do |packet_log_writer_pair_name, packet_log_writer_pair|
|
621
|
-
log = Qt::GroupBox.new("#{packet_log_writer_pair_name} Packet Log Writer")
|
622
|
-
log_layout = Qt::VBoxLayout.new(log)
|
623
|
-
interfaces = []
|
624
|
-
CmdTlmServer.interfaces.all.each do |interface_name, interface|
|
625
|
-
if interface.packet_log_writer_pairs.include?(packet_log_writer_pair)
|
626
|
-
interfaces << interface.name
|
627
|
-
end
|
628
|
-
end
|
629
|
-
|
630
|
-
form_layout = Qt::FormLayout.new
|
631
|
-
@logging_layouts[packet_log_writer_pair_name] = form_layout
|
632
|
-
label = Qt::Label.new(tr(interfaces.join(", ")))
|
633
|
-
label.setTextInteractionFlags(Qt::TextSelectableByMouse)
|
634
|
-
form_layout.addRow("Interfaces:", label)
|
635
|
-
create_log_layout(form_layout, packet_log_writer_pair.cmd_log_writer, 'Cmd')
|
636
|
-
create_log_layout(form_layout, packet_log_writer_pair.tlm_log_writer, 'Tlm')
|
637
|
-
|
638
|
-
button_layout = Qt::HBoxLayout.new
|
639
|
-
start_button = Qt::PushButton.new(tr('Start Cmd Logging'))
|
640
|
-
button_layout.addWidget(start_button)
|
641
|
-
start_button.connect(SIGNAL('clicked()')) do
|
642
|
-
CmdTlmServer.instance.start_cmd_log(packet_log_writer_pair_name)
|
643
|
-
end
|
644
|
-
start_button = Qt::PushButton.new(tr('Start Tlm Logging'))
|
645
|
-
button_layout.addWidget(start_button)
|
646
|
-
start_button.connect(SIGNAL('clicked()')) do
|
647
|
-
CmdTlmServer.instance.start_tlm_log(packet_log_writer_pair_name)
|
648
|
-
end
|
649
|
-
if @production == false
|
650
|
-
stop_button = Qt::PushButton.new(tr('Stop Cmd Logging'))
|
651
|
-
button_layout.addWidget(stop_button)
|
652
|
-
stop_button.connect(SIGNAL('clicked()')) do
|
653
|
-
CmdTlmServer.instance.stop_cmd_log(packet_log_writer_pair_name)
|
654
|
-
end
|
655
|
-
stop_button = Qt::PushButton.new(tr('Stop Tlm Logging'))
|
656
|
-
button_layout.addWidget(stop_button)
|
657
|
-
stop_button.connect(SIGNAL('clicked()')) do
|
658
|
-
CmdTlmServer.instance.stop_tlm_log(packet_log_writer_pair_name)
|
659
|
-
end
|
660
|
-
end
|
661
|
-
form_layout.addRow("Actions:", button_layout)
|
662
|
-
log_layout.addLayout(form_layout)
|
663
|
-
layout.addWidget(log)
|
664
|
-
end
|
665
|
-
layout.addWidget(Qt::Label.new(tr("Note: Buffered IO operations cause file size to not reflect total logged data size until the log file is closed.")))
|
666
|
-
end
|
667
|
-
|
668
|
-
def populate_logging
|
669
|
-
scroll = Qt::ScrollArea.new
|
670
|
-
widget = Qt::Widget.new
|
671
|
-
layout = Qt::VBoxLayout.new(widget)
|
672
|
-
# Since the layout will be inside a scroll area
|
673
|
-
# make sure it respects the sizes we set
|
674
|
-
layout.setSizeConstraint(Qt::Layout::SetMinAndMaxSize)
|
675
|
-
|
676
|
-
populate_logging_actions(layout)
|
677
|
-
|
678
|
-
# Create the hash which will hold the logging layouts
|
679
|
-
@logging_layouts = {}
|
680
|
-
|
681
|
-
# Add the cmd/tlm log files information
|
682
|
-
populate_log_file_info(layout)
|
683
|
-
|
684
|
-
# Set the scroll area widget last now that all the items have been layed out
|
685
|
-
scroll.setWidget(widget)
|
686
|
-
@tabbook.addTab(scroll, "Logging")
|
687
|
-
end
|
688
|
-
|
689
|
-
def update_filename_and_logging_state
|
690
|
-
CmdTlmServer.packet_logging.all.each do |packet_log_writer_pair_name, packet_log_writer_pair|
|
691
|
-
@logging_layouts[packet_log_writer_pair_name].itemAt(1, Qt::FormLayout::FieldRole).widget.setText(packet_log_writer_pair.cmd_log_writer.logging_enabled.to_s)
|
692
|
-
@logging_layouts[packet_log_writer_pair_name].itemAt(2, Qt::FormLayout::FieldRole).widget.setText(packet_log_writer_pair.cmd_log_writer.queue.size.to_s)
|
693
|
-
@logging_layouts[packet_log_writer_pair_name].itemAt(3, Qt::FormLayout::FieldRole).widget.setText(packet_log_writer_pair.cmd_log_writer.filename)
|
694
|
-
file_size = 0
|
695
|
-
begin
|
696
|
-
file_size = File.size(packet_log_writer_pair.cmd_log_writer.filename) if packet_log_writer_pair.cmd_log_writer.filename
|
697
|
-
rescue Exception
|
698
|
-
# Do nothing on error
|
699
|
-
end
|
700
|
-
@logging_layouts[packet_log_writer_pair_name].itemAt(4, Qt::FormLayout::FieldRole).widget.setText(file_size.to_s)
|
701
|
-
@logging_layouts[packet_log_writer_pair_name].itemAt(5, Qt::FormLayout::FieldRole).widget.setText(packet_log_writer_pair.tlm_log_writer.logging_enabled.to_s)
|
702
|
-
@logging_layouts[packet_log_writer_pair_name].itemAt(6, Qt::FormLayout::FieldRole).widget.setText(packet_log_writer_pair.tlm_log_writer.queue.size.to_s)
|
703
|
-
@logging_layouts[packet_log_writer_pair_name].itemAt(7, Qt::FormLayout::FieldRole).widget.setText(packet_log_writer_pair.tlm_log_writer.filename)
|
704
|
-
file_size = 0
|
705
|
-
begin
|
706
|
-
file_size = File.size(packet_log_writer_pair.tlm_log_writer.filename) if packet_log_writer_pair.tlm_log_writer.filename
|
707
|
-
rescue Exception
|
708
|
-
# Do nothing on error
|
709
|
-
end
|
710
|
-
@logging_layouts[packet_log_writer_pair_name].itemAt(8, Qt::FormLayout::FieldRole).widget.setText(file_size.to_s)
|
711
|
-
end
|
191
|
+
# Cancel the tab sleeper and kill the tab thread so we can create a new one
|
192
|
+
def kill_tab_thread
|
193
|
+
@tab_sleeper ||= nil
|
194
|
+
@tab_sleeper.cancel if @tab_sleeper
|
195
|
+
Cosmos.kill_thread(self, @tab_thread)
|
196
|
+
@tab_thread = nil
|
712
197
|
end
|
713
198
|
|
714
|
-
|
199
|
+
# Wrapper method that starts a new thread and then loops. It ensures we are
|
200
|
+
# executing in the main thread and then yields to allow updates to the GUI.
|
201
|
+
# Finally it sleeps using a sleeper so it can be interrupted.
|
202
|
+
#
|
203
|
+
# @param name [String] Name of the tab
|
204
|
+
def handle_tab(name)
|
715
205
|
@tab_thread = Thread.new do
|
716
206
|
begin
|
717
207
|
while true
|
718
|
-
Qt.execute_in_main_thread(true)
|
719
|
-
update_filename_and_logging_state()
|
720
|
-
end
|
208
|
+
Qt.execute_in_main_thread(true) { yield }
|
721
209
|
break if @tab_sleeper.sleep(1)
|
722
210
|
end
|
723
211
|
rescue Exception => error
|
724
|
-
Qt.execute_in_main_thread(true) {|| ExceptionDialog.new(self, error, "COSMOS CTS :
|
212
|
+
Qt.execute_in_main_thread(true) {|| ExceptionDialog.new(self, error, "COSMOS CTS : #{name} Tab Thread")}
|
725
213
|
end
|
726
214
|
end
|
727
215
|
end
|
728
216
|
|
729
|
-
|
730
|
-
scroll = Qt::ScrollArea.new
|
731
|
-
widget = Qt::Widget.new
|
732
|
-
layout = Qt::VBoxLayout.new(widget)
|
733
|
-
|
734
|
-
limits = Qt::GroupBox.new(tr("Limits Status"))
|
735
|
-
limits_layout = Qt::FormLayout.new(limits)
|
736
|
-
current_limits_set = System.limits_set.to_s
|
737
|
-
|
738
|
-
known_limits_sets = System.limits.sets
|
739
|
-
known_limits_sets = known_limits_sets.map {|x| x.to_s}.sort
|
740
|
-
current_index = known_limits_sets.index(current_limits_set.to_s)
|
741
|
-
|
742
|
-
@limits_set_combo = Qt::ComboBox.new
|
743
|
-
limits_layout.addRow("Limits Set:", @limits_set_combo)
|
744
|
-
layout.addWidget(limits)
|
745
|
-
|
746
|
-
known_limits_sets.sort.each do |limits_set|
|
747
|
-
@limits_set_combo.addItem(limits_set.to_s)
|
748
|
-
end
|
749
|
-
@limits_set_combo.setMaxVisibleItems(6)
|
750
|
-
@limits_set_combo.setCurrentIndex(current_index)
|
751
|
-
# Only connect to the signal that is sent when the user chooses an item.
|
752
|
-
# If the limits set is changed programatically the code in
|
753
|
-
# handle_status_tab will pick up the change.
|
754
|
-
@limits_set_combo.connect(SIGNAL('activated(int)')) do
|
755
|
-
selected_limits_set = @limits_set_combo.currentText
|
756
|
-
if selected_limits_set
|
757
|
-
System.limits_set = selected_limits_set.intern if System.limits_set != selected_limits_set.intern
|
758
|
-
end
|
759
|
-
end
|
760
|
-
|
761
|
-
api = Qt::GroupBox.new(tr("API Status"))
|
762
|
-
api_layout = Qt::VBoxLayout.new(api)
|
763
|
-
@api_table = Qt::TableWidget.new()
|
764
|
-
@api_table.verticalHeader.hide()
|
765
|
-
@api_table.setRowCount(1)
|
766
|
-
@api_table.setColumnCount(6)
|
767
|
-
@api_table.setHorizontalHeaderLabels(["Port", "Num Clients", "Requests", "Requests/Sec", "Avg Request Time", "Estimated Utilization"])
|
768
|
-
|
769
|
-
@api_table.setItem(0, 0, Qt::TableWidgetItem.new(tr(System.ports['CTS_API'].to_s)))
|
770
|
-
item0 = Qt::TableWidgetItem.new(tr(CmdTlmServer.json_drb.num_clients.to_s))
|
771
|
-
item0.setTextAlignment(Qt::AlignCenter)
|
772
|
-
@api_table.setItem(0, 1, item0)
|
773
|
-
item = Qt::TableWidgetItem.new(tr(CmdTlmServer.json_drb.request_count.to_s))
|
774
|
-
item.setTextAlignment(Qt::AlignCenter)
|
775
|
-
@api_table.setItem(0, 2, item)
|
776
|
-
item2 = Qt::TableWidgetItem.new("0.0")
|
777
|
-
item2.setTextAlignment(Qt::AlignCenter)
|
778
|
-
@api_table.setItem(0, 3, item2)
|
779
|
-
item3 = Qt::TableWidgetItem.new("0.0")
|
780
|
-
item3.setTextAlignment(Qt::AlignCenter)
|
781
|
-
@api_table.setItem(0, 4, item3)
|
782
|
-
item4 = Qt::TableWidgetItem.new("0.0")
|
783
|
-
item4.setTextAlignment(Qt::AlignCenter)
|
784
|
-
@api_table.setItem(0, 5, item4)
|
785
|
-
@api_table.displayFullSize
|
786
|
-
api_layout.addWidget(@api_table)
|
787
|
-
layout.addWidget(api)
|
788
|
-
|
789
|
-
system = Qt::GroupBox.new(tr("System Status"))
|
790
|
-
system_layout = Qt::VBoxLayout.new(system)
|
791
|
-
@system_table = Qt::TableWidget.new()
|
792
|
-
@system_table.verticalHeader.hide()
|
793
|
-
@system_table.setRowCount(1)
|
794
|
-
@system_table.setColumnCount(4)
|
795
|
-
@system_table.setHorizontalHeaderLabels(["Threads", "Total Objs", "Free Objs", "Allocated Objs"])
|
796
|
-
|
797
|
-
item0 = Qt::TableWidgetItem.new("0")
|
798
|
-
item0.setTextAlignment(Qt::AlignCenter)
|
799
|
-
@system_table.setItem(0, 0, item0)
|
800
|
-
item1 = Qt::TableWidgetItem.new("0.0")
|
801
|
-
item1.setTextAlignment(Qt::AlignCenter)
|
802
|
-
@system_table.setItem(0, 1, item1)
|
803
|
-
item2 = Qt::TableWidgetItem.new("0.0")
|
804
|
-
item2.setTextAlignment(Qt::AlignCenter)
|
805
|
-
@system_table.setItem(0, 2, item2)
|
806
|
-
item3 = Qt::TableWidgetItem.new("0.0")
|
807
|
-
item3.setTextAlignment(Qt::AlignCenter)
|
808
|
-
@system_table.setItem(0, 3, item3)
|
809
|
-
@system_table.displayFullSize
|
810
|
-
system_layout.addWidget(@system_table)
|
811
|
-
layout.addWidget(system)
|
812
|
-
|
813
|
-
background_tasks_groupbox = Qt::GroupBox.new(tr("Background Tasks"))
|
814
|
-
background_tasks_layout = Qt::VBoxLayout.new(background_tasks_groupbox)
|
815
|
-
@background_tasks_table = Qt::TableWidget.new()
|
816
|
-
@background_tasks_table.verticalHeader.hide()
|
817
|
-
@background_tasks_table.setRowCount(CmdTlmServer.background_tasks.all.length)
|
818
|
-
@background_tasks_table.setColumnCount(3)
|
819
|
-
@background_tasks_table.setHorizontalHeaderLabels(["Name", "State", "Status"])
|
820
|
-
|
821
|
-
background_tasks = CmdTlmServer.background_tasks.all
|
822
|
-
if background_tasks.length > 0
|
823
|
-
row = 0
|
824
|
-
background_tasks.each_with_index do |background_task, index|
|
825
|
-
background_task_name = background_task.name
|
826
|
-
background_task_name = "Background Task ##{index + 1}" unless background_task_name
|
827
|
-
background_task_name_widget = Qt::TableWidgetItem.new(background_task_name)
|
828
|
-
background_task_name_widget.setTextAlignment(Qt::AlignCenter)
|
829
|
-
@background_tasks_table.setItem(row, 0, background_task_name_widget)
|
830
|
-
if background_task.thread
|
831
|
-
status = background_task.thread.status
|
832
|
-
status = 'complete' if status == false
|
833
|
-
background_task_state_widget = Qt::TableWidgetItem.new(status.to_s)
|
834
|
-
else
|
835
|
-
background_task_state_widget = Qt::TableWidgetItem.new('no thread')
|
836
|
-
end
|
837
|
-
background_task_state_widget.setTextAlignment(Qt::AlignCenter)
|
838
|
-
background_task_state_widget.setSizeHint(Qt::Size.new(80, 30))
|
839
|
-
@background_tasks_table.setItem(row, 1, background_task_state_widget)
|
840
|
-
background_task_status_widget = Qt::TableWidgetItem.new(background_task.status.to_s)
|
841
|
-
background_task_status_widget.setTextAlignment(Qt::AlignCenter)
|
842
|
-
background_task_status_widget.setSizeHint(Qt::Size.new(500, 30))
|
843
|
-
@background_tasks_table.setItem(row, 2, background_task_status_widget)
|
844
|
-
|
845
|
-
row += 1
|
846
|
-
end
|
847
|
-
end
|
848
|
-
@background_tasks_table.displayFullSize
|
849
|
-
background_tasks_layout.addWidget(@background_tasks_table)
|
850
|
-
layout.addWidget(background_tasks_groupbox)
|
851
|
-
|
852
|
-
# Set the scroll area widget last now that all the items have been layed out
|
853
|
-
scroll.setWidget(widget)
|
854
|
-
@tabbook.addTab(scroll, "Status")
|
855
|
-
end
|
856
|
-
|
217
|
+
# Update the status tab of the server
|
857
218
|
def handle_status_tab
|
219
|
+
if CmdTlmServer.json_drb
|
220
|
+
previous_request_count = CmdTlmServer.json_drb.request_count
|
221
|
+
else
|
222
|
+
previous_request_count = 0
|
223
|
+
end
|
858
224
|
@tab_thread = Thread.new do
|
859
225
|
begin
|
860
|
-
if CmdTlmServer.json_drb
|
861
|
-
previous_request_count = CmdTlmServer.json_drb.request_count
|
862
|
-
else
|
863
|
-
previous_request_count = 0
|
864
|
-
end
|
865
226
|
while true
|
866
227
|
start_time = Time.now
|
867
|
-
Qt.execute_in_main_thread(true)
|
868
|
-
# Update limits set
|
869
|
-
current_limits_set = System.limits_set.to_s
|
870
|
-
if @limits_set_combo.currentText != current_limits_set
|
871
|
-
known_limits_sets = System.limits.sets
|
872
|
-
known_limits_sets = known_limits_sets.map {|x| x.to_s}.sort
|
873
|
-
current_index = known_limits_sets.index(current_limits_set.to_s)
|
874
|
-
@limits_set_combo.clear
|
875
|
-
known_limits_sets.sort.each do |limits_set|
|
876
|
-
@limits_set_combo.addItem(limits_set.to_s)
|
877
|
-
end
|
878
|
-
@limits_set_combo.setCurrentIndex(current_index)
|
879
|
-
end
|
880
|
-
|
881
|
-
# Update API status
|
882
|
-
if CmdTlmServer.json_drb
|
883
|
-
@api_table.item(0,1).setText(CmdTlmServer.json_drb.num_clients.to_s)
|
884
|
-
@api_table.item(0,2).setText(CmdTlmServer.json_drb.request_count.to_s)
|
885
|
-
request_count = CmdTlmServer.json_drb.request_count
|
886
|
-
requests_per_second = request_count - previous_request_count
|
887
|
-
@api_table.item(0,3).setText(requests_per_second.to_s)
|
888
|
-
previous_request_count = request_count
|
889
|
-
average_request_time = CmdTlmServer.json_drb.average_request_time
|
890
|
-
@api_table.item(0,4).setText(sprintf("%0.6f s", average_request_time))
|
891
|
-
estimated_utilization = requests_per_second * average_request_time * 100.0
|
892
|
-
@api_table.item(0,5).setText(sprintf("%0.2f %", estimated_utilization))
|
893
|
-
end
|
894
|
-
|
895
|
-
# Update system status
|
896
|
-
@system_table.item(0,0).setText(Thread.list.length.to_s)
|
897
|
-
objs = ObjectSpace.count_objects
|
898
|
-
@system_table.item(0,1).setText(objs[:TOTAL].to_s)
|
899
|
-
@system_table.item(0,2).setText(objs[:FREE].to_s)
|
900
|
-
total = 0
|
901
|
-
objs.each do |key, val|
|
902
|
-
next if key == :TOTAL || key == :FREE
|
903
|
-
total += val
|
904
|
-
end
|
905
|
-
@system_table.item(0,3).setText(total.to_s)
|
906
|
-
|
907
|
-
# Update background task status
|
908
|
-
background_tasks = CmdTlmServer.background_tasks.all
|
909
|
-
if background_tasks.length > 0
|
910
|
-
row = 0
|
911
|
-
background_tasks.each_with_index do |background_task, index|
|
912
|
-
if background_task.thread
|
913
|
-
status = background_task.thread.status
|
914
|
-
status = 'complete' if status == false
|
915
|
-
@background_tasks_table.item(row, 1).setText(status.to_s)
|
916
|
-
else
|
917
|
-
@background_tasks_table.item(row, 1).setText('no thread')
|
918
|
-
end
|
919
|
-
@background_tasks_table.item(row, 2).setText(background_task.status.to_s)
|
920
|
-
row += 1
|
921
|
-
end
|
922
|
-
end
|
923
|
-
end
|
228
|
+
Qt.execute_in_main_thread(true) { @status_tab.update(previous_request_count) }
|
924
229
|
total_time = Time.now - start_time
|
925
230
|
if total_time > 0.0 and total_time < 1.0
|
926
231
|
break if @tab_sleeper.sleep(1.0 - total_time)
|
927
232
|
end
|
928
233
|
end
|
929
234
|
rescue Exception => error
|
930
|
-
Qt.execute_in_main_thread(true) {|| ExceptionDialog.new(self, error, "COSMOS CTS :
|
235
|
+
Qt.execute_in_main_thread(true) {|| ExceptionDialog.new(self, error, "COSMOS CTS : Status Tab Thread")}
|
931
236
|
end
|
932
237
|
end
|
933
238
|
end
|
934
239
|
|
240
|
+
# Called when the user tries to close the server application. Popup a
|
241
|
+
# dialog to warn them about the consequences and then gracefully shut
|
242
|
+
# everything down.
|
935
243
|
def closeEvent(event)
|
936
244
|
# Create are you sure dialog
|
937
245
|
if @no_prompt
|
@@ -957,34 +265,8 @@ module Cosmos
|
|
957
265
|
end
|
958
266
|
end
|
959
267
|
|
960
|
-
|
961
|
-
|
962
|
-
unless option_parser and options
|
963
|
-
option_parser, options = create_default_options()
|
964
|
-
options.width = 800
|
965
|
-
options.height = 500
|
966
|
-
# Set the default title which can be overridden in the config file
|
967
|
-
options.title = "#{CMD} and #{TLM} Server"
|
968
|
-
options.auto_size = false
|
969
|
-
options.config_file = CmdTlmServer::DEFAULT_CONFIG_FILE
|
970
|
-
options.production = false
|
971
|
-
options.no_prompt = false
|
972
|
-
option_parser.separator "CTS Specific Options:"
|
973
|
-
option_parser.on("-c", "--config FILE", "Use the specified configuration file") do |arg|
|
974
|
-
options.config_file = arg
|
975
|
-
end
|
976
|
-
option_parser.on("-p", "--production", "Run the server in production mode which disables the ability to stop logging.") do |arg|
|
977
|
-
options.production = true
|
978
|
-
end
|
979
|
-
option_parser.on("-n", "--no-prompt", "Don't prompt with Are You Sure dialog on close.") do |arg|
|
980
|
-
options.no_prompt = true
|
981
|
-
end
|
982
|
-
end
|
983
|
-
|
984
|
-
super(option_parser, options)
|
985
|
-
end
|
986
|
-
end
|
987
|
-
|
268
|
+
# Thread to process server messages. Uses handle_string_output to process
|
269
|
+
# the output.
|
988
270
|
def process_server_messages(options)
|
989
271
|
# Start thread to read server messages
|
990
272
|
@output_thread = Thread.new do
|
@@ -1004,6 +286,8 @@ module Cosmos
|
|
1004
286
|
end
|
1005
287
|
end
|
1006
288
|
|
289
|
+
# Write any available messages to the output pane in the server GUI
|
290
|
+
# as well as to the server message log.
|
1007
291
|
def handle_string_output
|
1008
292
|
if @string_output.string[-1..-1] == "\n"
|
1009
293
|
Qt.execute_in_main_thread(true) do
|
@@ -1017,6 +301,8 @@ module Cosmos
|
|
1017
301
|
end
|
1018
302
|
end
|
1019
303
|
|
304
|
+
# CmdTlmServer stop callback called by CmdTlmServer.stop. Ensures all the
|
305
|
+
# output is written to the message logs.
|
1020
306
|
def stop_callback
|
1021
307
|
handle_string_output()
|
1022
308
|
@output_sleeper.cancel
|
@@ -1028,6 +314,35 @@ module Cosmos
|
|
1028
314
|
def graceful_kill
|
1029
315
|
# Just to avoid warning
|
1030
316
|
end
|
1031
|
-
end # class CmdTlmServerGui
|
1032
317
|
|
318
|
+
# Entry point to the server application
|
319
|
+
def self.run(option_parser = nil, options = nil)
|
320
|
+
Cosmos.catch_fatal_exception do
|
321
|
+
unless option_parser and options
|
322
|
+
option_parser, options = create_default_options()
|
323
|
+
options.width = 800
|
324
|
+
options.height = 500
|
325
|
+
# Set the default title which can be overridden in the config file
|
326
|
+
options.title = TOOL_NAME
|
327
|
+
options.auto_size = false
|
328
|
+
options.config_file = CmdTlmServer::DEFAULT_CONFIG_FILE
|
329
|
+
options.production = false
|
330
|
+
options.no_prompt = false
|
331
|
+
option_parser.separator "CTS Specific Options:"
|
332
|
+
option_parser.on("-c", "--config FILE", "Use the specified configuration file") do |arg|
|
333
|
+
options.config_file = arg
|
334
|
+
end
|
335
|
+
option_parser.on("-p", "--production", "Run the server in production mode which disables the ability to stop logging.") do |arg|
|
336
|
+
options.production = true
|
337
|
+
end
|
338
|
+
option_parser.on("-n", "--no-prompt", "Don't prompt with Are You Sure dialog on close.") do |arg|
|
339
|
+
options.no_prompt = true
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
super(option_parser, options)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
end # class CmdTlmServerGui
|
1033
348
|
end # module Cosmos
|