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
@@ -131,6 +131,7 @@ module Cosmos
131
131
  file.puts "#{tlm},#{total}"
132
132
  end
133
133
  end
134
+ File.chmod(0444, output_filename)
134
135
  end
135
136
  rescue => error
136
137
  progress.append_text("Error processing:\n#{error.formatted}\n")
@@ -49,10 +49,10 @@ module Cosmos
49
49
  @running_icon = Cosmos.get_icon('running.png')
50
50
  @no_icon = Qt::Icon.new
51
51
 
52
- if File.exist?(options.config_file)
52
+ begin
53
53
  ScriptRunnerConfig.new(options.config_file)
54
- else
55
- raise "Could not find config file #{options.config_file}"
54
+ rescue => error
55
+ ExceptionDialog.new(self, error, "Error parsing #{options.config_file}")
56
56
  end
57
57
 
58
58
  @procedure_dir = System.paths['PROCEDURES'][0]
@@ -955,7 +955,6 @@ module Cosmos
955
955
  options.height = 600
956
956
  options.title = "Script Runner : Untitled"
957
957
  options.auto_size = false
958
- options.config_file = "script_runner.txt"
959
958
  options.server_config_file = CmdTlmServer::DEFAULT_CONFIG_FILE
960
959
  options.run_procedure = nil
961
960
 
@@ -11,11 +11,11 @@
11
11
  require 'cosmos'
12
12
 
13
13
  module Cosmos
14
-
15
14
  # This class reads the Script Runner configuration file
16
15
  class ScriptRunnerConfig
17
16
  # Processes the config file
18
17
  def initialize(filename)
18
+ return unless filename
19
19
  parser = ConfigParser.new("http://cosmosrb.com/docs/tools/#script-runner-configuration")
20
20
  parser.parse_file(filename) do |keyword, params|
21
21
  case keyword
@@ -35,6 +35,5 @@ module Cosmos
35
35
  end
36
36
  end
37
37
  end
38
- end # class ScriptRunnerConfig
39
-
40
- end # module Cosmos
38
+ end
39
+ end
@@ -140,6 +140,7 @@ module Cosmos
140
140
  # Add Realtime Button Bar
141
141
  @realtime_button_bar = RealtimeButtonBar.new(self)
142
142
  @realtime_button_bar.state = 'Stopped'
143
+ @realtime_button_bar.step_callback = method(:handle_step_button)
143
144
  @realtime_button_bar.start_callback = method(:handle_start_go_button)
144
145
  @realtime_button_bar.pause_callback = method(:handle_pause_retry_button)
145
146
  @realtime_button_bar.stop_callback = method(:handle_stop_button)
@@ -549,13 +550,20 @@ module Cosmos
549
550
  return nil if @cancel_instrumentation
550
551
  instrumented_line = ''
551
552
  if instrumentable
553
+ # Skip the segment if it's empty. Note that the segment could have
554
+ # originally had comments but they were stripped in
555
+ # ruby_lex_utils.remove_comments
556
+ next if segment.strip.empty?
552
557
  # If not inside a begin block then create one to catch exceptions
553
558
  unless inside_begin
554
559
  instrumented_line << 'begin; '
555
560
  end
556
561
 
557
562
  # Add preline instrumentation
558
- instrumented_line << "ScriptRunnerFrame.instance.script_binding = binding(); if ScriptRunnerFrame.instance.inline_return then ScriptRunnerFrame.instance.inline_return = nil; return ScriptRunnerFrame.instance.inline_return_params; end; ScriptRunnerFrame.instance.pre_line_instrumentation('#{filename}', #{line_no}); "
563
+ instrumented_line << "ScriptRunnerFrame.instance.script_binding = binding(); "\
564
+ "if ScriptRunnerFrame.instance.inline_return then ScriptRunnerFrame.instance.inline_return = nil; "\
565
+ "return ScriptRunnerFrame.instance.inline_return_params; end; "\
566
+ "ScriptRunnerFrame.instance.pre_line_instrumentation('#{filename}', #{line_no}); "
559
567
 
560
568
  # Add the actual line
561
569
  instrumented_line << segment
@@ -566,7 +574,8 @@ module Cosmos
566
574
 
567
575
  # Complete begin block to catch exceptions
568
576
  unless inside_begin
569
- instrumented_line << "; rescue Exception => eval_error; retry if ScriptRunnerFrame.instance.exception_instrumentation(eval_error, '#{filename}', #{line_no}); end"
577
+ instrumented_line << "; rescue Exception => eval_error; "\
578
+ "retry if ScriptRunnerFrame.instance.exception_instrumentation(eval_error, '#{filename}', #{line_no}); end"
570
579
  end
571
580
 
572
581
  instrumented_line << "\n"
@@ -682,7 +691,16 @@ module Cosmos
682
691
  # Implement the breakpoint callbacks from the RubyEditor
683
692
  ######################################
684
693
  def breakpoint_set(line)
685
- ScriptRunnerFrame.set_breakpoint(current_tab_filename(), line)
694
+ # Check for blank and comment lines which can't have a breakpoint.
695
+ # There are other un-instrumentable lines which don't support breakpoints
696
+ # but this is the most common and is an easy check.
697
+ # Note: line is 1 based but @script.get_line is zero based so subtract 1
698
+ text = @script.get_line(line - 1)
699
+ if text.strip.empty? || text.strip[0] == '#'
700
+ @script.clear_breakpoint(line) # Immediately clear it
701
+ else
702
+ ScriptRunnerFrame.set_breakpoint(current_tab_filename(), line)
703
+ end
686
704
  end
687
705
 
688
706
  def breakpoint_cleared(line)
@@ -874,6 +892,7 @@ module Cosmos
874
892
 
875
893
  def show_debug
876
894
  unless @debug_frame
895
+ @realtime_button_bar.step_button.setHidden(false)
877
896
  @script.enable_breakpoints = true
878
897
  if @tab_book_shown
879
898
  if @tab_book.count > 0
@@ -946,20 +965,6 @@ module Cosmos
946
965
 
947
966
  @debug_frame.addWidget(@debug_text)
948
967
 
949
- @toggle_button = Qt::PushButton.new('Toggle Run/Step')
950
- @debug_frame.addWidget(@toggle_button)
951
- @toggle_button.connect(SIGNAL('clicked(bool)')) do
952
- if @@step_mode
953
- scriptrunner_puts "Debug: run_mode"
954
- handle_output_io()
955
- self.class.step_mode = false
956
- else
957
- scriptrunner_puts "Debug: step_mode"
958
- handle_output_io()
959
- self.class.step_mode = true
960
- end
961
- end
962
-
963
968
  @return_button = Qt::PushButton.new('Insert Return')
964
969
  @debug_frame.addWidget(@return_button)
965
970
  @return_button.connect(SIGNAL('clicked(bool)')) do
@@ -985,11 +990,19 @@ module Cosmos
985
990
  end
986
991
  end
987
992
  end
993
+ @realtime_button_bar.step_button.setHidden(true)
988
994
  # Remove the debug frame
989
995
  @bottom_frame.layout.takeAt(@bottom_frame.layout.count - 1) if @debug_frame
990
996
  @debug_frame.removeAll
991
997
  @debug_frame.dispose
992
998
  @debug_frame = nil
999
+
1000
+ # If step mode was previously active then pause the script so it doesn't
1001
+ # just take off when we end the debugging session
1002
+ if @@step_mode
1003
+ pause()
1004
+ @@step_mode = false
1005
+ end
993
1006
  end
994
1007
 
995
1008
  def self.set_breakpoint(filename, line_number)
@@ -1442,8 +1455,18 @@ module Cosmos
1442
1455
  true
1443
1456
  end
1444
1457
 
1445
- def handle_start_go_button
1446
- scriptrunner_puts "User pressed #{@realtime_button_bar.start_button.text.strip}"
1458
+ def handle_step_button
1459
+ scriptrunner_puts "User pressed #{@realtime_button_bar.step_button.text.strip}"
1460
+ pause()
1461
+ @@step_mode = true
1462
+ handle_start_go_button(step = true)
1463
+ end
1464
+
1465
+ def handle_start_go_button(step = false)
1466
+ unless step
1467
+ scriptrunner_puts "User pressed #{@realtime_button_bar.start_button.text.strip}"
1468
+ @@step_mode = false
1469
+ end
1447
1470
  handle_output_io()
1448
1471
  @realtime_button_bar.start_button.clear_focus()
1449
1472
 
@@ -1832,7 +1855,5 @@ module Cosmos
1832
1855
  # Oh Well
1833
1856
  end
1834
1857
  end
1835
-
1836
- end # class ScriptRunnerFrame
1837
-
1838
- end # module Cosmos
1858
+ end
1859
+ end
@@ -116,6 +116,9 @@ module Cosmos
116
116
  footer()
117
117
  ensure
118
118
  @file.close if @file and not @file.closed?
119
+ Cosmos.set_working_dir do
120
+ File.chmod(0444, @filename)
121
+ end
119
122
  end
120
123
 
121
124
  def header
@@ -166,6 +169,7 @@ module Cosmos
166
169
  end
167
170
  end
168
171
  end
172
+ File.chmod(0444, @data_package_filename)
169
173
  end
170
174
  progress_dialog.close_done if progress_dialog
171
175
  rescue => error
@@ -971,12 +971,9 @@ module Cosmos
971
971
 
972
972
  def process_config(filename)
973
973
  ScriptRunnerFrame.instance = @script_runner_frame
974
-
975
974
  # Remember all the requires that fail and warn the user
976
975
  require_errors = []
977
976
 
978
- # Ensure the file exists
979
- raise "Configuration File: #{filename} does not exist" unless test(?f, filename)
980
977
  parser = ConfigParser.new("http://cosmosrb.com/docs/tools/#test-runner-configuration")
981
978
  parser.parse_file(filename) do |keyword, params|
982
979
  case keyword
@@ -18,8 +18,12 @@ module Cosmos
18
18
  class TabbedPlotsRealtimeThread < InterfaceThread
19
19
 
20
20
  # Create a new TabbedPlotsRealtimeThread
21
- def initialize(tabbed_plots_config, connection_success_callback = nil, connection_failed_callback = nil, connection_lost_callback = nil, fatal_exception_callback = nil)
22
- interface = TcpipClientInterface.new(System.connect_hosts['CTS_PREIDENTIFIED'], nil, System.ports['CTS_PREIDENTIFIED'], nil, tabbed_plots_config.cts_timeout, 'PREIDENTIFIED')
21
+ def initialize(tabbed_plots_config, connection_success_callback = nil, connection_failed_callback = nil, connection_lost_callback = nil, fatal_exception_callback = nil, replay_mode = false)
22
+ if replay_mode
23
+ interface = TcpipClientInterface.new(System.connect_hosts['REPLAY_PREIDENTIFIED'], nil, System.ports['REPLAY_PREIDENTIFIED'], nil, tabbed_plots_config.cts_timeout, 'PREIDENTIFIED')
24
+ else
25
+ interface = TcpipClientInterface.new(System.connect_hosts['CTS_PREIDENTIFIED'], nil, System.ports['CTS_PREIDENTIFIED'], nil, tabbed_plots_config.cts_timeout, 'PREIDENTIFIED')
26
+ end
23
27
  super(interface)
24
28
 
25
29
  @queue = Queue.new
@@ -63,6 +63,7 @@ module Cosmos
63
63
  @tabbed_plots = nil
64
64
  @realtime_thread = nil
65
65
  @config_modified = false
66
+ @replay_mode = false
66
67
 
67
68
  # Bring up slash screen for long duration tasks after creation
68
69
  Splash.execute(self) do |splash|
@@ -107,6 +108,10 @@ module Cosmos
107
108
  @file_screenshot.statusTip = tr('Screenshot of Application')
108
109
  @file_screenshot.connect(SIGNAL('triggered()')) { on_file_screenshot() }
109
110
 
111
+ @replay_action = Qt::Action.new(tr('Toggle Replay Mode'), self)
112
+ @replay_action.statusTip = tr('Toggle Replay Mode')
113
+ @replay_action.connect(SIGNAL('triggered()')) { toggle_replay_mode() }
114
+
110
115
  # Tab Menu Actions
111
116
  @tab_add = Qt::Action.new(Cosmos.get_icon('add_tab.png'), tr('&Add Tab'), self)
112
117
  @tab_add.statusTip = tr('Add New Tab')
@@ -209,6 +214,8 @@ module Cosmos
209
214
  @file_menu.addSeparator()
210
215
  @file_menu.addAction(@file_screenshot)
211
216
  @file_menu.addSeparator()
217
+ @file_menu.addAction(@replay_action)
218
+ @file_menu.addSeparator()
212
219
  @file_menu.addAction(@exit_action)
213
220
 
214
221
  @tab_menu = menuBar.addMenu(tr('&Tab'))
@@ -265,6 +272,10 @@ module Cosmos
265
272
  # Create a Vertical Frame for the right contents
266
273
  @right_widget = Qt::Widget.new(self)
267
274
  @right_frame = Qt::VBoxLayout.new
275
+ @replay_flag = Qt::Label.new("Replay Mode")
276
+ @replay_flag.setStyleSheet("background:green;color:white;padding:5px;font-weight:bold;height:30px;")
277
+ @right_frame.addWidget(@replay_flag)
278
+ @replay_flag.hide
268
279
  @right_widget.setLayout(@right_frame)
269
280
  @splitter.addWidget(@right_widget)
270
281
  @splitter.setStretchFactor(0,0) # Set the left side stretch factor to 0
@@ -581,6 +592,20 @@ module Cosmos
581
592
  @tabbed_plots.resume unless paused
582
593
  end # def on_file_screenshot
583
594
 
595
+ def toggle_replay_mode
596
+ running = @realtime_thread ? true : false
597
+ handle_stop()
598
+ System.telemetry.reset
599
+ @tabbed_plots.reset_all_data_objects
600
+ @replay_mode = !@replay_mode
601
+ if @replay_mode
602
+ @replay_flag.show
603
+ else
604
+ @replay_flag.hide
605
+ end
606
+ handle_start() if running
607
+ end
608
+
584
609
  ###############################################################################
585
610
  # Tab Menu Handlers
586
611
  ###############################################################################
@@ -921,7 +946,7 @@ module Cosmos
921
946
  # Startup realtime thread
922
947
  @realtime_button_bar.state = 'Connecting'
923
948
  statusBar.showMessage(tr("Connecting to COSMOS Server"))
924
- @realtime_thread = TabbedPlotsRealtimeThread.new(@tabbed_plots_config, method(:realtime_thread_connection_success_callback), method(:realtime_thread_connection_failed_callback), method(:realtime_thread_connection_lost_callback), method(:realtime_thread_fatal_exception_callback))
949
+ @realtime_thread = TabbedPlotsRealtimeThread.new(@tabbed_plots_config, method(:realtime_thread_connection_success_callback), method(:realtime_thread_connection_failed_callback), method(:realtime_thread_connection_lost_callback), method(:realtime_thread_fatal_exception_callback), @replay_mode)
925
950
  end
926
951
  end # def handle_start
927
952
 
@@ -21,7 +21,7 @@ module Cosmos
21
21
  # close_all_screens is called
22
22
  @@open_screens = []
23
23
 
24
- attr_accessor :full_name, :width, :height, :window
24
+ attr_accessor :full_name, :width, :height, :window, :replay_flag
25
25
 
26
26
  class Widgets
27
27
  # Flag to indicate all screens should close
@@ -229,6 +229,7 @@ module Cosmos
229
229
  app_style = File.join(Cosmos::USERPATH, 'config', 'tools', 'application.css')
230
230
  setStyleSheet(File.read(app_style)) if File.exist? app_style
231
231
 
232
+ @replay_flag = nil
232
233
  @widgets = Widgets.new(self, mode)
233
234
  @window = process(filename)
234
235
  @@open_screens << self if @window
@@ -277,6 +278,12 @@ module Cosmos
277
278
  setCentralWidget(top_widget)
278
279
  frame = Qt::VBoxLayout.new()
279
280
  top_widget.setLayout(frame)
281
+
282
+ @replay_flag = Qt::Label.new("Replay Mode")
283
+ @replay_flag.setStyleSheet("background:green;color:white;padding:5px;font-weight:bold;")
284
+ frame.addWidget(@replay_flag)
285
+ @replay_flag.hide unless get_replay_mode()
286
+
280
287
  layout_stack[0] = frame
281
288
  Cosmos.load_cosmos_icon if @single_screen
282
289
  when 'END'
@@ -498,5 +505,21 @@ module Cosmos
498
505
  Widgets.closing_all = false
499
506
  end
500
507
 
508
+ def self.update_replay_mode
509
+ screens = @@open_screens.clone
510
+ replay_mode = get_replay_mode()
511
+ screens.each do |screen|
512
+ begin
513
+ if replay_mode
514
+ screen.replay_flag.show if screen.replay_flag
515
+ else
516
+ screen.replay_flag.hide if screen.replay_flag
517
+ end
518
+ rescue
519
+ # Oh well
520
+ end
521
+ end
522
+ end
523
+
501
524
  end
502
525
  end
@@ -57,6 +57,8 @@ module Cosmos
57
57
  end
58
58
 
59
59
  def self.load_config(filename)
60
+ raise "Configuration file #{filename} does not exist." unless filename && File.exist?(filename)
61
+
60
62
  # Find all screen files so we can calculate MD5
61
63
  tlmviewer_files = [filename, System.initial_filename]
62
64
  additional_data = ''
@@ -179,6 +181,10 @@ module Cosmos
179
181
  @file_audit.shortcut = @file_audit_keyseq
180
182
  @file_audit.statusTip = tr('Create a report listing which telemetry points are not on screens')
181
183
  @file_audit.connect(SIGNAL('triggered()')) { file_audit() }
184
+
185
+ @replay_action = Qt::Action.new(tr('Toggle Replay Mode'), self)
186
+ @replay_action.statusTip = tr('Toggle Replay Mode')
187
+ @replay_action.connect(SIGNAL('triggered()')) { toggle_replay_mode() }
182
188
  end
183
189
 
184
190
  def initialize_menus(options)
@@ -187,6 +193,7 @@ module Cosmos
187
193
  @file_menu.addAction(@file_save)
188
194
  @file_menu.addAction(@file_generate)
189
195
  @file_menu.addAction(@file_audit)
196
+ @file_menu.addAction(@replay_action)
190
197
  @file_menu.addSeparator()
191
198
  @file_menu.addAction(@exit_action)
192
199
 
@@ -202,6 +209,11 @@ module Cosmos
202
209
  setCentralWidget(central_widget)
203
210
  top_layout = Qt::VBoxLayout.new
204
211
 
212
+ @replay_flag = Qt::Label.new("Replay Mode")
213
+ @replay_flag.setStyleSheet("background:green;color:white;padding:5px;font-weight:bold;")
214
+ top_layout.addWidget(@replay_flag)
215
+ @replay_flag.hide
216
+
205
217
  @search_box = FullTextSearchLineEdit.new(self)
206
218
  top_layout.addWidget(@search_box)
207
219
 
@@ -406,6 +418,16 @@ module Cosmos
406
418
  Cosmos.open_in_text_editor(output_filename) if output_filename
407
419
  end
408
420
 
421
+ def toggle_replay_mode
422
+ set_replay_mode(!get_replay_mode())
423
+ if get_replay_mode()
424
+ @replay_flag.show
425
+ else
426
+ @replay_flag.hide
427
+ end
428
+ Screen.update_replay_mode
429
+ end
430
+
409
431
  # Method called by screens to notify that they have been closed
410
432
  def notify(closed_screen)
411
433
  screen_full_name = closed_screen.full_name
@@ -447,6 +469,9 @@ module Cosmos
447
469
 
448
470
  def display(screen_full_name, x_pos = nil, y_pos = nil)
449
471
  return unless screen_full_name
472
+ x_pos = x_pos.to_i if x_pos
473
+ y_pos = y_pos.to_i if y_pos
474
+
450
475
  # Find the specified screen
451
476
  screen_info = find_screen_info(screen_full_name)
452
477
 
@@ -46,6 +46,21 @@ module Cosmos
46
46
  @invalid_items = []
47
47
  end
48
48
 
49
+ def as_json(options = nil) #:nodoc:
50
+ {group: @group,
51
+ target_name: @target_name,
52
+ original_target_name:
53
+ @original_target_name,
54
+ name: @name,
55
+ filename: @filename,
56
+ x_pos: @x_pos,
57
+ y_pos: @y_pos,
58
+ substitute: @substitute,
59
+ force_substitute: @force_substitute,
60
+ show_on_startup: @show_on_startup
61
+ }
62
+ end
63
+
49
64
  def full_name
50
65
  @group ? @name : "#{@target_name} #{@name}"
51
66
  end
@@ -96,15 +111,10 @@ module Cosmos
96
111
  attr_accessor :completion_list
97
112
  attr_accessor :tlm_to_screen_mapping
98
113
 
99
- def initialize(filename = nil)
114
+ def initialize(filename = nil, skip_read_items = false)
100
115
  # Handle nil filename
101
116
  filename = File.join(Cosmos::USERPATH, 'config', 'tools', 'tlm_viewer', 'tlm_viewer.txt') unless filename
102
117
  @filename = filename
103
-
104
- # Ensure the file exists
105
- raise "Telemetry Viewer configuration file #{filename} does not exist" unless test ?f, filename
106
-
107
- # Initialize instance variables
108
118
  @columns = []
109
119
  @columns << {}
110
120
  @screen_infos = {}
@@ -129,7 +139,7 @@ module Cosmos
129
139
  screen_dir = File.join(target.dir, 'screens')
130
140
  if File.exist?(screen_dir) and num_screens(screen_dir) > 0
131
141
  start_target(target.name, parser)
132
- auto_screens()
142
+ auto_screens(skip_read_items)
133
143
  end
134
144
  end
135
145
 
@@ -141,7 +151,7 @@ module Cosmos
141
151
  screen_dir = File.join(target.dir, 'screens')
142
152
  if File.exist?(screen_dir) and num_screens(screen_dir) > 0
143
153
  start_target(target.name, parser)
144
- auto_screens()
154
+ auto_screens(skip_read_items)
145
155
  end
146
156
 
147
157
  when 'TARGET'
@@ -153,7 +163,7 @@ module Cosmos
153
163
  raise parser.error("No target defined. SCREEN must follow TARGET.") unless @current_target
154
164
  parser.verify_num_parameters(1, 3, 'SCREEN <Filename> <X Position (optional)> <Y Position (optional)>')
155
165
  screen_filename = File.join(@current_target.dir, 'screens', parameters[0])
156
- start_screen(screen_filename, parameters[1], parameters[2])
166
+ start_screen(screen_filename, parameters[1], parameters[2], skip_read_items)
157
167
 
158
168
  when 'SHOW_ON_STARTUP'
159
169
  raise parser.error("No screen defined. SHOW_ON_STARTUP must follow SCREEN or GROUP_SCREEN.") unless @current_screen_info
@@ -179,7 +189,7 @@ module Cosmos
179
189
  parser.verify_num_parameters(2, 4, 'GROUP_SCREEN <Target Name> <Screen Filename> <X Position (optional)> <Y Position (Optional)>')
180
190
  start_target(parameters[0].upcase, parser, @current_group)
181
191
  screen_filename = File.join(@current_target.dir, 'screens', parameters[1])
182
- start_screen(screen_filename, parameters[2], parameters[3])
192
+ start_screen(screen_filename, parameters[2], parameters[3], skip_read_items)
183
193
 
184
194
  else
185
195
  # blank config.lines will have a nil keyword and should not raise an exception
@@ -233,7 +243,7 @@ module Cosmos
233
243
  end
234
244
  end
235
245
 
236
- def start_screen(screen_filename, x_pos = nil, y_pos = nil)
246
+ def start_screen(screen_filename, x_pos = nil, y_pos = nil, skip_read_items = false)
237
247
  screen_name = File.basename(screen_filename, '.txt').upcase
238
248
  x_pos = x_pos.to_i if x_pos
239
249
  y_pos = y_pos.to_i if y_pos
@@ -244,15 +254,15 @@ module Cosmos
244
254
  @current_screen_info.force_substitute = true if @current_target.auto_screen_substitute
245
255
  @current_screen_info.original_target_name = @current_target.original_name
246
256
  @current_screen_info.substitute = @current_target.name if @current_target.substitute or @current_target.auto_screen_substitute
247
- @current_screen_info.read_items
257
+ @current_screen_info.read_items unless skip_read_items
248
258
  end
249
259
 
250
- def auto_screens
260
+ def auto_screens(skip_read_items = false)
251
261
  @current_group = nil
252
262
  screen_dir = File.join(@current_target.dir, 'screens')
253
263
  if File.exist?(screen_dir)
254
264
  Dir.new(screen_dir).each do |filename|
255
- start_screen(File.join(screen_dir, filename)) if valid_screen_name(filename)
265
+ start_screen(File.join(screen_dir, filename), nil, nil, skip_read_items) if valid_screen_name(filename)
256
266
  end
257
267
  end
258
268
  end