cosmos 4.0.3-java → 4.1.0-java

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.
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 +12 -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