cosmos 4.0.3 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -5
  3. data/Manifest.txt +11 -1
  4. data/README.md +3 -2
  5. data/Rakefile +18 -4
  6. data/appveyor.yml +19 -0
  7. data/cosmos.gemspec +14 -3
  8. data/data/config/cmd_tlm_server.yaml +3 -0
  9. data/data/crc.txt +63 -60
  10. data/demo/config/targets/INST/cmd_tlm_server.txt +1 -0
  11. data/demo/config/targets/INST/cmd_tlm_server2.txt +7 -0
  12. data/demo/config/tools/cmd_sequence/cmd_sequence.txt +2 -0
  13. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +8 -12
  14. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +7 -9
  15. data/demo/lib/cmd_sequence_exporter.rb +52 -0
  16. data/demo/lib/example_background_task.rb +1 -0
  17. data/demo/procedures/replay_test.rb +32 -0
  18. data/ext/cosmos/ext/structure/structure.c +39 -3
  19. data/install/config/tools/cmd_tlm_server/cmd_tlm_server.txt +1 -0
  20. data/install/config/tools/launcher/launcher.txt +2 -0
  21. data/lib/cosmos/config/config_parser.rb +2 -0
  22. data/lib/cosmos/core_ext/io.rb +89 -60
  23. data/lib/cosmos/gui/qt.rb +5 -8
  24. data/lib/cosmos/gui/qt_tool.rb +8 -8
  25. data/lib/cosmos/gui/text/ruby_editor.rb +12 -12
  26. data/lib/cosmos/gui/utilities/script_module_gui.rb +9 -9
  27. data/lib/cosmos/gui/widgets/realtime_button_bar.rb +18 -17
  28. data/lib/cosmos/interfaces/protocols/fixed_protocol.rb +2 -2
  29. data/lib/cosmos/interfaces/protocols/template_protocol.rb +3 -0
  30. data/lib/cosmos/interfaces/udp_interface.rb +27 -14
  31. data/lib/cosmos/io/buffered_file.rb +0 -1
  32. data/lib/cosmos/io/json_drb.rb +134 -214
  33. data/lib/cosmos/io/json_drb_object.rb +22 -61
  34. data/lib/cosmos/io/json_drb_rack.rb +79 -0
  35. data/lib/cosmos/io/json_rpc.rb +27 -0
  36. data/lib/cosmos/io/udp_sockets.rb +102 -58
  37. data/lib/cosmos/packets/commands.rb +1 -1
  38. data/lib/cosmos/packets/structure.rb +1 -1
  39. data/lib/cosmos/packets/structure_item.rb +37 -5
  40. data/lib/cosmos/script/cmd_tlm_server.rb +76 -2
  41. data/lib/cosmos/script/replay.rb +60 -0
  42. data/lib/cosmos/script/script.rb +20 -2
  43. data/lib/cosmos/script/scripting.rb +9 -9
  44. data/lib/cosmos/script/tools.rb +14 -0
  45. data/lib/cosmos/system/system.rb +185 -92
  46. data/lib/cosmos/system/target.rb +1 -1
  47. data/lib/cosmos/tools/cmd_sequence/cmd_sequence.rb +44 -4
  48. data/lib/cosmos/tools/cmd_sequence/sequence_item.rb +4 -0
  49. data/lib/cosmos/tools/cmd_sequence/sequence_list.rb +7 -0
  50. data/lib/cosmos/tools/cmd_tlm_server/api.rb +347 -20
  51. data/lib/cosmos/tools/cmd_tlm_server/background_tasks.rb +3 -0
  52. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +329 -111
  53. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +13 -0
  54. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +261 -95
  55. data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +46 -35
  56. data/lib/cosmos/tools/cmd_tlm_server/gui/logging_tab.rb +18 -8
  57. data/lib/cosmos/tools/cmd_tlm_server/gui/packets_tab.rb +39 -28
  58. data/lib/cosmos/tools/cmd_tlm_server/gui/replay_tab.rb +242 -0
  59. data/lib/cosmos/tools/cmd_tlm_server/gui/status_tab.rb +24 -8
  60. data/lib/cosmos/tools/cmd_tlm_server/gui/targets_tab.rb +18 -6
  61. data/lib/cosmos/tools/cmd_tlm_server/limits_groups_background_task.rb +5 -4
  62. data/lib/cosmos/tools/cmd_tlm_server/replay_backend.rb +375 -0
  63. data/lib/cosmos/tools/cmd_tlm_server/routers.rb +10 -2
  64. data/lib/cosmos/tools/data_viewer/data_viewer.rb +40 -5
  65. data/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb +18 -20
  66. data/lib/cosmos/tools/launcher/launcher_config.rb +5 -16
  67. data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +65 -39
  68. data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +19 -0
  69. data/lib/cosmos/tools/replay/replay.rb +5 -505
  70. data/lib/cosmos/tools/script_runner/script_audit.rb +1 -0
  71. data/lib/cosmos/tools/script_runner/script_runner.rb +3 -4
  72. data/lib/cosmos/tools/script_runner/script_runner_config.rb +3 -4
  73. data/lib/cosmos/tools/script_runner/script_runner_frame.rb +44 -23
  74. data/lib/cosmos/tools/test_runner/results_writer.rb +4 -0
  75. data/lib/cosmos/tools/test_runner/test_runner.rb +0 -3
  76. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +6 -2
  77. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tool.rb +26 -1
  78. data/lib/cosmos/tools/tlm_viewer/screen.rb +24 -1
  79. data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +25 -0
  80. data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +24 -14
  81. data/lib/cosmos/top_level.rb +34 -24
  82. data/lib/cosmos/utilities/csv.rb +60 -8
  83. data/lib/cosmos/version.rb +5 -5
  84. data/spec/config/config_parser_spec.rb +10 -1
  85. data/spec/core_ext/socket_spec.rb +4 -2
  86. data/spec/gui/utilities/script_module_gui_spec.rb +102 -0
  87. data/spec/install/config/data/data.txt +1 -0
  88. data/spec/install/config/targets/INST/cmd_tlm/inst_cmds.txt +2 -0
  89. data/spec/interfaces/cmd_tlm_server_interface_spec.rb +1 -2
  90. data/spec/interfaces/protocols/template_protocol_spec.rb +72 -2
  91. data/spec/interfaces/serial_interface_spec.rb +1 -1
  92. data/spec/interfaces/udp_interface_spec.rb +14 -0
  93. data/spec/io/buffered_file_spec.rb +37 -0
  94. data/spec/io/json_drb_object_spec.rb +2 -15
  95. data/spec/io/json_drb_spec.rb +61 -121
  96. data/spec/io/udp_sockets_spec.rb +42 -2
  97. data/spec/packet_logs/packet_log_reader_spec.rb +5 -2
  98. data/spec/packets/binary_accessor_spec.rb +1 -1
  99. data/spec/packets/packet_item_spec.rb +1 -1
  100. data/spec/packets/structure_item_spec.rb +5 -6
  101. data/spec/script/cmd_tlm_server_spec.rb +39 -4
  102. data/spec/script/commands_disconnect_spec.rb +1 -1
  103. data/spec/script/commands_spec.rb +2 -1
  104. data/spec/script/scripting_spec.rb +18 -3
  105. data/spec/script/telemetry_spec.rb +5 -0
  106. data/spec/spec_helper.rb +43 -26
  107. data/spec/streams/tcpip_socket_stream_spec.rb +2 -2
  108. data/spec/system/system_spec.rb +11 -9
  109. data/spec/system/target_spec.rb +3 -0
  110. data/spec/tools/cmd_tlm_server/api_spec.rb +543 -29
  111. data/spec/tools/cmd_tlm_server/background_task_spec.rb +2 -2
  112. data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +31 -75
  113. data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +199 -66
  114. data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +85 -9
  115. data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +29 -127
  116. data/spec/tools/cmd_tlm_server/router_thread_spec.rb +10 -50
  117. data/spec/tools/launcher/launcher_config_spec.rb +1 -1
  118. data/spec/tools/table_manager/table_item_spec.rb +1 -1
  119. data/spec/tools/table_manager/tablemanager_core_spec.rb +4 -4
  120. data/spec/top_level/top_level_spec.rb +151 -3
  121. data/spec/utilities/csv_spec.rb +24 -5
  122. metadata +61 -9
  123. data/lib/cosmos/tools/replay/replay_server.rb +0 -91
@@ -38,7 +38,11 @@ module Cosmos
38
38
  router = TcpipServerInterface.new(port, port, 10.0, nil, 'PREIDENTIFIED')
39
39
  router.name = router_name
40
40
  router.disable_disconnect = true
41
- router.set_option('LISTEN_ADDRESS', [System.listen_hosts['CTS_PREIDENTIFIED']])
41
+ if CmdTlmServer.mode == :CMD_TLM_SERVER
42
+ router.set_option('LISTEN_ADDRESS', [System.listen_hosts['CTS_PREIDENTIFIED']])
43
+ else
44
+ router.set_option('LISTEN_ADDRESS', [System.listen_hosts['REPLAY_PREIDENTIFIED']])
45
+ end
42
46
  router.set_option('AUTO_SYSTEM_META', [true])
43
47
  @config.routers[router_name] = router
44
48
  @config.interfaces.each do |interface_name, interface|
@@ -58,7 +62,11 @@ module Cosmos
58
62
  cmd_router = TcpipServerInterface.new(port, nil, 10.0, nil, 'PREIDENTIFIED')
59
63
  cmd_router.name = cmd_router_name
60
64
  cmd_router.disable_disconnect = true
61
- cmd_router.set_option('LISTEN_ADDRESS', [System.listen_hosts['CTS_CMD_ROUTER']])
65
+ if CmdTlmServer.mode == :CMD_TLM_SERVER
66
+ cmd_router.set_option('LISTEN_ADDRESS', [System.listen_hosts['CTS_CMD_ROUTER']])
67
+ else
68
+ cmd_router.set_option('LISTEN_ADDRESS', [System.listen_hosts['REPLAY_CMD_ROUTER']])
69
+ end
62
70
  cmd_router.set_option('AUTO_SYSTEM_META', [true])
63
71
  @config.routers[cmd_router_name] = cmd_router
64
72
  @config.interfaces.each do |interface_name, interface|
@@ -103,6 +103,10 @@ module Cosmos
103
103
  @handle_reset.statusTip = tr('Reset Components')
104
104
  @handle_reset.connect(SIGNAL('triggered()')) { handle_reset() }
105
105
 
106
+ @replay_action = Qt::Action.new(tr('Toggle Replay Mode'), self)
107
+ @replay_action.statusTip = tr('Toggle Replay Mode')
108
+ @replay_action.connect(SIGNAL('triggered()')) { toggle_replay_mode() }
109
+
106
110
  # Search Actions
107
111
  @search_find = Qt::Action.new(Cosmos.get_icon('search.png'), tr('&Find'), self)
108
112
  @search_find_keyseq = Qt::KeySequence.new(tr('Ctrl+F'))
@@ -139,6 +143,7 @@ module Cosmos
139
143
  file_menu = menuBar.addMenu(tr('&File'))
140
144
  file_menu.addAction(@open_log)
141
145
  file_menu.addAction(@handle_reset)
146
+ file_menu.addAction(@replay_action)
142
147
  file_menu.addSeparator()
143
148
  file_menu.addAction(@exit_action)
144
149
 
@@ -167,6 +172,11 @@ module Cosmos
167
172
  # Create the top level vertical layout
168
173
  @top_layout = Qt::VBoxLayout.new(@central_widget)
169
174
 
175
+ @replay_flag = Qt::Label.new("Replay Mode")
176
+ @replay_flag.setStyleSheet("background:green;color:white;padding:5px;font-weight:bold;")
177
+ @top_layout.addWidget(@replay_flag)
178
+ @replay_flag.hide
179
+
170
180
  # Realtime Button Bar
171
181
  @realtime_button_bar = RealtimeButtonBar.new(self)
172
182
  @realtime_button_bar.start_callback = method(:handle_start)
@@ -196,6 +206,19 @@ module Cosmos
196
206
  end
197
207
  end
198
208
 
209
+ def toggle_replay_mode
210
+ running = (@realtime_button_bar.state == 'Running')
211
+ handle_stop()
212
+ handle_reset()
213
+ set_replay_mode(!get_replay_mode())
214
+ if get_replay_mode()
215
+ @replay_flag.show
216
+ else
217
+ @replay_flag.hide
218
+ end
219
+ handle_start if running
220
+ end
221
+
199
222
  def handle_tab_change(index)
200
223
  # Remove existing actions
201
224
  @tab_menu_actions.each do |action|
@@ -246,6 +269,15 @@ module Cosmos
246
269
  @cancel_thread = false
247
270
  @sleeper = Sleeper.new
248
271
  if !@packets.empty?
272
+ need_meta = true
273
+ @packets.each do |target_name, packet_name|
274
+ if target_name == 'SYSTEM' and packet_name == 'META'
275
+ need_meta = false
276
+ break
277
+ end
278
+ end
279
+ @packets << ['SYSTEM', 'META'] if need_meta
280
+
249
281
  begin
250
282
  while true
251
283
  break if @cancel_thread
@@ -274,6 +306,7 @@ module Cosmos
274
306
  begin
275
307
  # Get a subscribed to packet
276
308
  packet_data, target_name, packet_name, received_time, received_count = get_packet_data(@subscription_id)
309
+ break unless packet_data
277
310
 
278
311
  # Put packet data into its packet
279
312
  packet = System.telemetry.packet(target_name, packet_name)
@@ -281,6 +314,11 @@ module Cosmos
281
314
  packet.received_time = received_time
282
315
  packet.received_count = received_count
283
316
 
317
+ # Make sure we are on the right configuration
318
+ if target_name == 'SYSTEM' and packet_name == 'META'
319
+ System.load_configuration(packet.read('CONFIG'))
320
+ end
321
+
284
322
  # Route packet to its component(s)
285
323
  index = packet.target_name + ' ' + packet.packet_name
286
324
  @component_mutex.synchronize do
@@ -337,6 +375,8 @@ module Cosmos
337
375
 
338
376
  def handle_start
339
377
  if windowTitle() != 'Data Viewer'
378
+ # Switch from log back to realtime/replay
379
+
340
380
  # Clear Title
341
381
  setWindowTitle('Data Viewer')
342
382
 
@@ -492,11 +532,6 @@ module Cosmos
492
532
  end
493
533
 
494
534
  def process_config(filename)
495
- # ensure the file exists
496
- unless test ?f, filename
497
- raise "Configuration File Does not Exist: #{filename}"
498
- end
499
-
500
535
  parser = ConfigParser.new
501
536
  parser.parse_file(filename) do |keyword, params|
502
537
  case keyword
@@ -14,13 +14,13 @@ require 'tempfile'
14
14
  require 'open3'
15
15
 
16
16
  module Cosmos
17
-
18
17
  # Reads an ascii file that defines the configuration settings used to
19
18
  # configure the Handbook Creator
20
19
  class HandbookCreatorConfig
21
-
22
20
  attr_reader :pages
23
21
 
22
+ # Builds a page for the handbook. Pages can be either :NORMAL or :TARGETS.
23
+ # :TARGETS page builds pages for each of the targets in the system.
24
24
  class Page
25
25
  attr_reader :filename
26
26
  attr_reader :type
@@ -103,7 +103,7 @@ module Cosmos
103
103
  protected
104
104
 
105
105
  def create_pdf_file(progress_dialog, target_name = nil)
106
- tmp_html_file = Tempfile.new(['pdf', '.html'])
106
+ tmp_html_file = Tempfile.new(['pdf', '.html'], System.paths['HANDBOOKS'])
107
107
  if target_name
108
108
  filename = File.join(System.paths['HANDBOOKS'], target_name.downcase + @filename)
109
109
  create_file(tmp_html_file, [target_name], true, :PDF)
@@ -118,13 +118,15 @@ module Cosmos
118
118
  system_call = "wkhtmltopdf -L #{@pdf_side_margin} -R #{@pdf_side_margin} -T #{@pdf_top_margin} -B #{@pdf_bottom_margin} -s Letter #{header} #{footer} #{cover} #{@pdf_toc} \"#{tmp_html_file.path}\" \"#{File.dirname(filename)}/#{File.basename(filename, '.*')}.pdf\""
119
119
  status = nil
120
120
  begin
121
- Open3.popen2e(system_call) do |stdin, stdout_and_stderr, wait_thr|
122
- while wait_thr.alive?
123
- stdout_and_stderr.each_line do |line|
124
- progress_dialog.append_text(line.chomp) if progress_dialog
121
+ Cosmos.set_working_dir(System.paths['HANDBOOKS']) do
122
+ Open3.popen2e(system_call) do |stdin, stdout_and_stderr, wait_thr|
123
+ while wait_thr.alive?
124
+ stdout_and_stderr.each_line do |line|
125
+ progress_dialog.append_text(line.chomp) if progress_dialog
126
+ end
125
127
  end
128
+ status = wait_thr.value
126
129
  end
127
- status = wait_thr.value
128
130
  end
129
131
  rescue Errno::ENOENT
130
132
  status = nil
@@ -138,7 +140,7 @@ module Cosmos
138
140
 
139
141
  def make_pdf_detail(tag, filename, title, target_name = nil)
140
142
  if filename
141
- file = Tempfile.new(['pdf', '.html'])
143
+ file = Tempfile.new(['pdf', '.html'], System.paths['HANDBOOKS'])
142
144
  if target_name
143
145
  title = target_name + ' ' + title
144
146
  else
@@ -228,9 +230,9 @@ module Cosmos
228
230
  end
229
231
  packets
230
232
  end
233
+ end
231
234
 
232
- end # class Page
233
-
235
+ # Encapsulates a section of the PDF or webpage which can be :CMD, :TLM, or :NONE.
234
236
  class Section
235
237
  attr_reader :filename
236
238
  attr_reader :type
@@ -248,8 +250,7 @@ module Cosmos
248
250
  def create(file, title, packets = [], ignored = {})
249
251
  file.puts ERB.new(File.read(@filename)).result(binding)
250
252
  end
251
-
252
- end # class Section
253
+ end
253
254
 
254
255
  # Parses the configuration file.
255
256
  #
@@ -372,11 +373,8 @@ module Cosmos
372
373
  else
373
374
  # blank lines will have a nil keyword and should not raise an exception
374
375
  raise parser.error("Unknown keyword: #{keyword}") unless keyword.nil?
375
- end # case
376
- end # loop
377
-
376
+ end
377
+ end # loop
378
378
  end
379
-
380
- end # class HandbookCreatorConfig
381
-
382
- end # module Cosmos
379
+ end
380
+ end
@@ -14,10 +14,8 @@ require 'ostruct'
14
14
  require 'bundler'
15
15
 
16
16
  module Cosmos
17
-
18
17
  # Reads and interprets the Launcher configuration file
19
18
  class LauncherConfig
20
-
21
19
  # Launcher title
22
20
  attr_reader :title
23
21
 
@@ -43,13 +41,8 @@ module Cosmos
43
41
  @label_font_settings = ['Arial', 16]
44
42
  @num_columns = 4
45
43
  @items = []
46
-
47
- if File.exist?(filename.to_s)
48
- parse_file(filename)
49
- else
50
- raise "Launcher configuration file does not exist: #{filename}"
51
- end
52
- end # def initialize
44
+ parse_file(filename)
45
+ end
53
46
 
54
47
  # Create a ConfigParser and parse all the lines in the configuration file
55
48
  #
@@ -57,10 +50,8 @@ module Cosmos
57
50
  def parse_file(filename)
58
51
  multitool = nil
59
52
 
60
- # Loop over each line of the configuration file
61
53
  parser = ConfigParser.new("http://cosmosrb.com/docs/tools/#launcher-configuration")
62
54
  parser.parse_file(filename) do |keyword, params|
63
- # Handle each keyword
64
55
  case keyword
65
56
 
66
57
  when 'AUTO_GEM_TOOLS'
@@ -138,7 +129,7 @@ module Cosmos
138
129
 
139
130
  else # UNKNOWN
140
131
  raise parser.error("Unknown keyword '#{keyword}'.") if keyword
141
- end # case keyword
132
+ end
142
133
  end # parser.parse_file
143
134
  end
144
135
 
@@ -250,7 +241,5 @@ module Cosmos
250
241
 
251
242
  raise "Could not find gem containing tool: #{split[1]} - Make sure the appropriate gem is in your Gemfile"
252
243
  end
253
-
254
- end # class LauncherConfig
255
-
256
- end # module Cosmos
244
+ end
245
+ end
@@ -63,7 +63,7 @@ class Array
63
63
  end
64
64
 
65
65
  module Cosmos
66
-
66
+ # Handles the low level processing of limits event for LimitsMonitor.
67
67
  class LimitsItems
68
68
  # @return [Array<String,String,String>] Target name, packet name, item name
69
69
  attr_reader :ignored
@@ -102,7 +102,8 @@ module Cosmos
102
102
  end
103
103
 
104
104
  # Request that the limits items be refreshed from the server
105
- def request_reset
105
+ def request_reset(toggle_mode = false)
106
+ @toggle_mode = toggle_mode
106
107
  @initialized = false
107
108
  end
108
109
 
@@ -128,7 +129,7 @@ module Cosmos
128
129
  end
129
130
  end
130
131
 
131
- # Ignore a stale packet. Don't display it in the GUI and don't have it
132
+ # Ignore a stale packet. Don't display it in the GUI and don't have it
132
133
  # count towards the overall limit state.
133
134
  #
134
135
  # @param item [Array<String,String>] Target name, packet name
@@ -161,7 +162,7 @@ module Cosmos
161
162
  # Remove an item from the ignored_stale list to have it be displayed and
162
163
  # count towards the overall limits state.
163
164
  #
164
- # @param item [Array<String,String>] Target name, packet name to remove
165
+ # @param item [Array<String,String>] Target name, packet name to remove
165
166
  # from ignored list
166
167
  def remove_ignored_stale(item)
167
168
  index = @ignored_stale.delete_item(item)
@@ -249,7 +250,6 @@ module Cosmos
249
250
 
250
251
  # Update the values for all the out of limits items being tracked.
251
252
  def update_values
252
-
253
253
  values, limits_states, limits_settings, limits_set = get_tlm_values(@out_of_limits, :WITH_UNITS)
254
254
  index = 0
255
255
  @out_of_limits.each do |target_name, packet_name, item_name|
@@ -279,34 +279,27 @@ module Cosmos
279
279
  # expanded to find a file in the config/tools/limits_monitor dir.
280
280
  # @return [String] Message indicating success or fail
281
281
  def open_config(filename)
282
- return "" unless filename
283
- return "Configuration file #{filename} not found!" unless File.exist?(filename)
284
-
285
282
  @ignored = []
286
283
  @ignored_stale = []
287
- begin
288
- parser = ConfigParser.new("http://cosmosrb.com/docs/tools/#limits-monitor-configuration")
289
- parser.parse_file(filename) do |keyword, params|
290
- case keyword
291
- # TODO: Eventually we can deprecate 'IGNORE' in favor
292
- # of 'IGNORE_ITEM' now that we also have 'IGNORE_PACKET'
293
- when 'IGNORE', 'IGNORE_ITEM'
294
- @ignored << ([params[0], params[1], params[2]])
295
- when 'IGNORE_PACKET'
296
- @ignored << ([params[0], params[1], nil])
297
- when 'IGNORE_STALE'
298
- @ignored_stale << ([params[0], params[1], nil])
299
- when 'COLOR_BLIND'
300
- @colorblind = true
301
- when 'IGNORE_OPERATIONAL_LIMITS'
302
- @monitor_operational = false
303
- end
284
+ parser = ConfigParser.new("http://cosmosrb.com/docs/tools/#limits-monitor-configuration")
285
+ parser.parse_file(filename) do |keyword, params|
286
+ case keyword
287
+ # TODO: Eventually we can deprecate 'IGNORE' in favor
288
+ # of 'IGNORE_ITEM' now that we also have 'IGNORE_PACKET'
289
+ when 'IGNORE', 'IGNORE_ITEM'
290
+ @ignored << ([params[0], params[1], params[2]])
291
+ when 'IGNORE_PACKET'
292
+ @ignored << ([params[0], params[1], nil])
293
+ when 'IGNORE_STALE'
294
+ @ignored_stale << ([params[0], params[1], nil])
295
+ when 'COLOR_BLIND'
296
+ @colorblind = true
297
+ when 'IGNORE_OPERATIONAL_LIMITS'
298
+ @monitor_operational = false
304
299
  end
305
- result = "#{filename} loaded. "
306
- result << "Warning: Some items ignored" if ignored_items?
307
- rescue => e
308
- result = "Error loading configuration : #{e.message}"
309
300
  end
301
+ result = "#{filename} loaded. "
302
+ result << "Warning: Some items ignored" if ignored_items?
310
303
  # Since we may have loaded new ignored items we need to reset
311
304
  request_reset()
312
305
  result
@@ -356,6 +349,8 @@ module Cosmos
356
349
  @stale = []
357
350
  @limits_set = get_limits_set()
358
351
  unsubscribe_limits_events(@queue_id) if @queue_id
352
+ set_replay_mode(!get_replay_mode()) if @toggle_mode
353
+ @toggle_mode = false
359
354
  @queue_id = subscribe_limits_events(100000)
360
355
  @clear_items_callback.call
361
356
  get_out_of_limits().each do |target, packet, item, state|
@@ -405,7 +400,7 @@ module Cosmos
405
400
  item = [target_name, packet_name, nil]
406
401
  unless (@stale.includes_item?(item) || @ignored_stale.includes_item?(item) || UNKNOWN_ARRAY.includes_item?(item))
407
402
  @stale << item
408
- @items["#{item[0]} #{item[1]}"] = @new_item_callback.call(*item)
403
+ @items["#{item[0]} #{item[1]}"] = @new_item_callback.call(*item)
409
404
  end
410
405
  return ["INFO: Packet #{target_name} #{packet_name} is STALE\n", :BLACK]
411
406
  end
@@ -466,7 +461,7 @@ module Cosmos
466
461
  @ignore_button = Qt::PushButton.new('Ignore Item')
467
462
  @ignore_button.connect(SIGNAL('clicked()')) { parent.ignore(self, item) }
468
463
  @layout.addWidget(@ignore_button)
469
-
464
+
470
465
  @ignore_packet_button = Qt::PushButton.new('Ignore Packet')
471
466
  @ignore_packet_button.connect(SIGNAL('clicked()')) { parent.ignore(self, packet) }
472
467
  @layout.addWidget(@ignore_packet_button)
@@ -476,7 +471,7 @@ module Cosmos
476
471
  @layout.addStretch(1)
477
472
  @ignore_button = Qt::PushButton.new('Ignore Stale Packet')
478
473
  @ignore_button.connect(SIGNAL('clicked()')) { parent.ignore(self, packet) }
479
- @layout.addWidget(@ignore_button)
474
+ @layout.addWidget(@ignore_button)
480
475
  end
481
476
  end
482
477
 
@@ -528,8 +523,14 @@ module Cosmos
528
523
 
529
524
  @limits_items = LimitsItems.new(
530
525
  method(:new_gui_item), method(:update_gui_item), method(:clear_gui_items), method(:remove_gui_item))
531
- result = @limits_items.open_config(options.config_file)
532
- statusBar.showMessage(tr(result))
526
+ if options.config_file
527
+ begin
528
+ result = @limits_items.open_config(options.config_file)
529
+ statusBar.showMessage(tr(result))
530
+ rescue => error
531
+ ExceptionDialog.new(self, error, "Error parsing #{@options.config_file}")
532
+ end
533
+ end
533
534
 
534
535
  limits_thread()
535
536
  value_thread()
@@ -549,6 +550,10 @@ module Cosmos
549
550
  @reset_action.statusTip = tr('Reset connection and clear all items. This does not modify the ignored items.')
550
551
  @reset_action.connect(SIGNAL('triggered()')) { @limits_items.request_reset() }
551
552
 
553
+ @replay_action = Qt::Action.new(tr('Toggle Replay Mode'), self)
554
+ @replay_action.statusTip = tr('Toggle Replay Mode')
555
+ @replay_action.connect(SIGNAL('triggered()')) { toggle_replay_mode() }
556
+
552
557
  @open_ignored_action = Qt::Action.new(Cosmos.get_icon('open.png'),
553
558
  tr('&Open Config'), self)
554
559
  @open_ignored_action_keyseq = Qt::KeySequence.new(tr('Ctrl+O'))
@@ -579,6 +584,7 @@ module Cosmos
579
584
  @file_menu.addSeparator()
580
585
  @file_menu.addAction(@reset_action)
581
586
  @file_menu.addAction(@options_action)
587
+ @file_menu.addAction(@replay_action)
582
588
  @file_menu.addSeparator()
583
589
  @file_menu.addAction(@exit_action)
584
590
 
@@ -591,8 +597,18 @@ module Cosmos
591
597
  # Layout the main GUI tab widget with a view of all the out of limits items
592
598
  # in one tab and a log tab showing all limits events.
593
599
  def initialize_central_widget
600
+
601
+ widget = Qt::Widget.new
602
+ layout = Qt::VBoxLayout.new(widget)
603
+ setCentralWidget(widget)
604
+
605
+ @replay_flag = Qt::Label.new("Replay Mode")
606
+ @replay_flag.setStyleSheet("background:green;color:white;padding:5px;font-weight:bold;")
607
+ layout.addWidget(@replay_flag)
608
+ @replay_flag.hide
609
+
594
610
  @tabbook = Qt::TabWidget.new(self)
595
- setCentralWidget(@tabbook)
611
+ layout.addWidget(@tabbook)
596
612
  @widget = Qt::Widget.new
597
613
  @layout = Qt::VBoxLayout.new(@widget)
598
614
 
@@ -677,6 +693,10 @@ module Cosmos
677
693
  end
678
694
  end
679
695
 
696
+ def toggle_replay_mode
697
+ @limits_items.request_reset(true)
698
+ end
699
+
680
700
  # @return [String] Fully qualified path to the configuration file
681
701
  def default_config_path
682
702
  # If the config file has been set then just return it
@@ -834,7 +854,14 @@ module Cosmos
834
854
 
835
855
  # Reset the GUI by clearing all items
836
856
  def clear_gui_items
837
- Qt.execute_in_main_thread(true) { @scroll_layout.removeAll }
857
+ Qt.execute_in_main_thread(true) do
858
+ if get_replay_mode()
859
+ @replay_flag.show
860
+ else
861
+ @replay_flag.hide
862
+ end
863
+ @scroll_layout.removeAll
864
+ end
838
865
  end
839
866
 
840
867
  # Update front panel to ignore an item when the corresponding button is pressed.
@@ -967,6 +994,5 @@ module Cosmos
967
994
  super(option_parser, options)
968
995
  end
969
996
  end
970
-
971
- end # class LimitsMonitor
972
- end # module Cosmos
997
+ end
998
+ end