cosmos 3.1.1 → 3.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/Manifest.txt +6 -0
  3. data/autohotkey/config/tools/handbook_creator/templates/command_packets.html.erb +1 -1
  4. data/autohotkey/config/tools/handbook_creator/templates/footer.html.erb +2 -2
  5. data/autohotkey/config/tools/handbook_creator/templates/header.html.erb +4 -4
  6. data/autohotkey/tools/autohotkey.rb +1 -1
  7. data/autohotkey/tools/cmd_tlm_server.ahk +1 -0
  8. data/autohotkey/tools/packet_viewer.ahk +45 -2
  9. data/data/crc.txt +20 -15
  10. data/demo/Rakefile +16 -0
  11. data/demo/config/data/crc.txt +3 -3
  12. data/demo/config/tools/handbook_creator/templates/footer.html.erb +2 -2
  13. data/demo/config/tools/handbook_creator/templates/header.html.erb +4 -4
  14. data/demo/procedures/example_test.rb +1 -1
  15. data/install/Rakefile +16 -0
  16. data/install/config/data/crc.txt +2 -2
  17. data/install/config/tools/handbook_creator/templates/footer.html.erb +2 -2
  18. data/install/config/tools/handbook_creator/templates/header.html.erb +4 -4
  19. data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +64 -57
  20. data/lib/cosmos/gui/line_graph/line_graph_scaling.rb +0 -9
  21. data/lib/cosmos/gui/qt.rb +22 -18
  22. data/lib/cosmos/packet_logs/packet_log_writer.rb +6 -2
  23. data/lib/cosmos/script/script.rb +1 -1
  24. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +0 -1
  25. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +99 -784
  26. data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +189 -0
  27. data/lib/cosmos/tools/cmd_tlm_server/gui/logging_tab.rb +176 -0
  28. data/lib/cosmos/tools/cmd_tlm_server/gui/packets_tab.rb +144 -0
  29. data/lib/cosmos/tools/cmd_tlm_server/gui/status_tab.rb +240 -0
  30. data/lib/cosmos/tools/cmd_tlm_server/gui/targets_tab.rb +90 -0
  31. data/lib/cosmos/tools/launcher/launcher_config.rb +142 -110
  32. data/lib/cosmos/tools/test_runner/results_writer.rb +1 -1
  33. data/lib/cosmos/tools/test_runner/test_runner.rb +3 -2
  34. data/lib/cosmos/tools/tlm_grapher/data_objects/data_object.rb +18 -2
  35. data/lib/cosmos/tools/tlm_grapher/data_objects/housekeeping_data_object.rb +4 -9
  36. data/lib/cosmos/tools/tlm_grapher/data_objects/xy_data_object.rb +5 -5
  37. data/lib/cosmos/top_level.rb +1 -1
  38. data/lib/cosmos/version.rb +4 -4
  39. data/run_gui_tests.bat +33 -31
  40. data/spec/core_ext/time_spec.rb +51 -0
  41. data/spec/script/script_spec.rb +96 -0
  42. data/spec/tools/cmd_tlm_server/commanding_spec.rb +28 -0
  43. data/spec/tools/cmd_tlm_server/connections_spec.rb +88 -0
  44. data/spec/tools/cmd_tlm_server/router_thread_spec.rb +78 -25
  45. data/spec/tools/launcher/launcher_config_spec.rb +460 -0
  46. data/spec/top_level/top_level_spec.rb +1 -1
  47. 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
 
@@ -670,44 +670,46 @@ end
670
670
 
671
671
  class Qt::Painter
672
672
  def addLineColor(x, y, w, h, color = Cosmos::BLACK)
673
- color = Cosmos::getColor(color)
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
- color = Cosmos::getColor(color)
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
- color = Cosmos::getColor(color)
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
- color = Cosmos::getColor(color)
694
- setPen(color)
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
- color = Cosmos::getColor(color)
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
- color = Cosmos::getColor(color)
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
- @col += 1 if @col < @num_columns
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
- if @logging_enabled and @cycle_time and (Time.now - @start_time) > @cycle_time
282
- close_file()
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)
@@ -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 displayed"
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
- CMD = "Command"
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 #{CMD} and #{TLM} Server"
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('Interfaces')
95
+ @interfaces_tab.populate_interfaces(@tab_widget)
85
96
  splash.progress = 100/7 * 1
86
- populate_targets()
97
+ @targets_tab.populate(@tab_widget)
87
98
  splash.progress = 100/7 * 2
88
- populate_packets(CMD)
99
+ @packets_tab.populate_commands(@tab_widget)
89
100
  splash.progress = 100/7 * 3
90
- populate_packets(TLM)
101
+ @packets_tab.populate_telemetry(@tab_widget)
91
102
  splash.progress = 100/7 * 4
92
- populate_interfaces('Routers')
103
+ @interfaces_tab.populate_routers(@tab_widget)
93
104
  splash.progress = 100/7 * 5
94
- populate_logging()
105
+ @logging_tab.populate(@tab_widget)
95
106
  splash.progress = 100/7 * 6
96
- populate_status()
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()')) { edit_clear_counters() }
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 = "#{CMD} and #{TLM} Server is the heart of the COSMOS system. "
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
- @tabbook = Qt::TabWidget.new
143
- connect(@tabbook, SIGNAL('currentChanged(int)'), self, SLOT('handle_tab_change(int)'))
144
- @splitter.addWidget(@tabbook)
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 tabbook (index 0) instead of the output (index 1)
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
- def kill_tab_thread
165
- @tab_sleeper ||= nil
166
- @tab_sleeper.cancel if @tab_sleeper
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
- handle_interfaces_tab('Interfaces')
175
+ handle_tab('Interfaces') { @interfaces_tab.update(InterfacesTab::INTERFACES) }
177
176
  when 1
178
- handle_targets_tab()
177
+ handle_tab('Targets') { @targets_tab.update }
179
178
  when 2
180
- handle_packets_tab(CMD)
179
+ handle_tab('Packets') { @packets_tab.update(PacketsTab::COMMANDS) }
181
180
  when 3
182
- handle_packets_tab(TLM)
181
+ handle_tab('Telemetry') { @packets_tab.update(PacketsTab::TELEMETRY) }
183
182
  when 4
184
- handle_interfaces_tab('Routers')
183
+ handle_tab('Routers') { @interfaces_tab.update(InterfacesTab::ROUTERS) }
185
184
  when 5
186
- handle_logging_tab()
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
- def populate_interfaces(name)
193
- @interfaces_table ||= {}
194
-
195
- if name == 'Routers'
196
- interfaces = CmdTlmServer.routers
197
- else
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
- def handle_logging_tab
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) do
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 : Logging Tab Thread")}
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
- def populate_status
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) do
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 : Settings Tab Thread")}
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
- def self.run(option_parser = nil, options = nil)
961
- Cosmos.catch_fatal_exception do
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