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.
- checksums.yaml +4 -4
- data/.travis.yml +5 -5
- data/Manifest.txt +11 -1
- data/README.md +3 -2
- data/Rakefile +18 -4
- data/appveyor.yml +19 -0
- data/cosmos.gemspec +12 -3
- data/data/config/cmd_tlm_server.yaml +3 -0
- data/data/crc.txt +63 -60
- data/demo/config/targets/INST/cmd_tlm_server.txt +1 -0
- data/demo/config/targets/INST/cmd_tlm_server2.txt +7 -0
- data/demo/config/tools/cmd_sequence/cmd_sequence.txt +2 -0
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +8 -12
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +7 -9
- data/demo/lib/cmd_sequence_exporter.rb +52 -0
- data/demo/lib/example_background_task.rb +1 -0
- data/demo/procedures/replay_test.rb +32 -0
- data/ext/cosmos/ext/structure/structure.c +39 -3
- data/install/config/tools/cmd_tlm_server/cmd_tlm_server.txt +1 -0
- data/install/config/tools/launcher/launcher.txt +2 -0
- data/lib/cosmos/config/config_parser.rb +2 -0
- data/lib/cosmos/core_ext/io.rb +89 -60
- data/lib/cosmos/gui/qt.rb +5 -8
- data/lib/cosmos/gui/qt_tool.rb +8 -8
- data/lib/cosmos/gui/text/ruby_editor.rb +12 -12
- data/lib/cosmos/gui/utilities/script_module_gui.rb +9 -9
- data/lib/cosmos/gui/widgets/realtime_button_bar.rb +18 -17
- data/lib/cosmos/interfaces/protocols/fixed_protocol.rb +2 -2
- data/lib/cosmos/interfaces/protocols/template_protocol.rb +3 -0
- data/lib/cosmos/interfaces/udp_interface.rb +27 -14
- data/lib/cosmos/io/buffered_file.rb +0 -1
- data/lib/cosmos/io/json_drb.rb +134 -214
- data/lib/cosmos/io/json_drb_object.rb +22 -61
- data/lib/cosmos/io/json_drb_rack.rb +79 -0
- data/lib/cosmos/io/json_rpc.rb +27 -0
- data/lib/cosmos/io/udp_sockets.rb +102 -58
- data/lib/cosmos/packets/commands.rb +1 -1
- data/lib/cosmos/packets/structure.rb +1 -1
- data/lib/cosmos/packets/structure_item.rb +37 -5
- data/lib/cosmos/script/cmd_tlm_server.rb +76 -2
- data/lib/cosmos/script/replay.rb +60 -0
- data/lib/cosmos/script/script.rb +20 -2
- data/lib/cosmos/script/scripting.rb +9 -9
- data/lib/cosmos/script/tools.rb +14 -0
- data/lib/cosmos/system/system.rb +185 -92
- data/lib/cosmos/system/target.rb +1 -1
- data/lib/cosmos/tools/cmd_sequence/cmd_sequence.rb +44 -4
- data/lib/cosmos/tools/cmd_sequence/sequence_item.rb +4 -0
- data/lib/cosmos/tools/cmd_sequence/sequence_list.rb +7 -0
- data/lib/cosmos/tools/cmd_tlm_server/api.rb +347 -20
- data/lib/cosmos/tools/cmd_tlm_server/background_tasks.rb +3 -0
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +329 -111
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +13 -0
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +261 -95
- data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +46 -35
- data/lib/cosmos/tools/cmd_tlm_server/gui/logging_tab.rb +18 -8
- data/lib/cosmos/tools/cmd_tlm_server/gui/packets_tab.rb +39 -28
- data/lib/cosmos/tools/cmd_tlm_server/gui/replay_tab.rb +242 -0
- data/lib/cosmos/tools/cmd_tlm_server/gui/status_tab.rb +24 -8
- data/lib/cosmos/tools/cmd_tlm_server/gui/targets_tab.rb +18 -6
- data/lib/cosmos/tools/cmd_tlm_server/limits_groups_background_task.rb +5 -4
- data/lib/cosmos/tools/cmd_tlm_server/replay_backend.rb +375 -0
- data/lib/cosmos/tools/cmd_tlm_server/routers.rb +10 -2
- data/lib/cosmos/tools/data_viewer/data_viewer.rb +40 -5
- data/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb +18 -20
- data/lib/cosmos/tools/launcher/launcher_config.rb +5 -16
- data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +65 -39
- data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +19 -0
- data/lib/cosmos/tools/replay/replay.rb +5 -505
- data/lib/cosmos/tools/script_runner/script_audit.rb +1 -0
- data/lib/cosmos/tools/script_runner/script_runner.rb +3 -4
- data/lib/cosmos/tools/script_runner/script_runner_config.rb +3 -4
- data/lib/cosmos/tools/script_runner/script_runner_frame.rb +44 -23
- data/lib/cosmos/tools/test_runner/results_writer.rb +4 -0
- data/lib/cosmos/tools/test_runner/test_runner.rb +0 -3
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +6 -2
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tool.rb +26 -1
- data/lib/cosmos/tools/tlm_viewer/screen.rb +24 -1
- data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +25 -0
- data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +24 -14
- data/lib/cosmos/top_level.rb +34 -24
- data/lib/cosmos/utilities/csv.rb +60 -8
- data/lib/cosmos/version.rb +5 -5
- data/spec/config/config_parser_spec.rb +10 -1
- data/spec/core_ext/socket_spec.rb +4 -2
- data/spec/gui/utilities/script_module_gui_spec.rb +102 -0
- data/spec/install/config/data/data.txt +1 -0
- data/spec/install/config/targets/INST/cmd_tlm/inst_cmds.txt +2 -0
- data/spec/interfaces/cmd_tlm_server_interface_spec.rb +1 -2
- data/spec/interfaces/protocols/template_protocol_spec.rb +72 -2
- data/spec/interfaces/serial_interface_spec.rb +1 -1
- data/spec/interfaces/udp_interface_spec.rb +14 -0
- data/spec/io/buffered_file_spec.rb +37 -0
- data/spec/io/json_drb_object_spec.rb +2 -15
- data/spec/io/json_drb_spec.rb +61 -121
- data/spec/io/udp_sockets_spec.rb +42 -2
- data/spec/packet_logs/packet_log_reader_spec.rb +5 -2
- data/spec/packets/binary_accessor_spec.rb +1 -1
- data/spec/packets/packet_item_spec.rb +1 -1
- data/spec/packets/structure_item_spec.rb +5 -6
- data/spec/script/cmd_tlm_server_spec.rb +39 -4
- data/spec/script/commands_disconnect_spec.rb +1 -1
- data/spec/script/commands_spec.rb +2 -1
- data/spec/script/scripting_spec.rb +18 -3
- data/spec/script/telemetry_spec.rb +5 -0
- data/spec/spec_helper.rb +43 -26
- data/spec/streams/tcpip_socket_stream_spec.rb +2 -2
- data/spec/system/system_spec.rb +11 -9
- data/spec/system/target_spec.rb +3 -0
- data/spec/tools/cmd_tlm_server/api_spec.rb +543 -29
- data/spec/tools/cmd_tlm_server/background_task_spec.rb +2 -2
- data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +31 -75
- data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +199 -66
- data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +85 -9
- data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +29 -127
- data/spec/tools/cmd_tlm_server/router_thread_spec.rb +10 -50
- data/spec/tools/launcher/launcher_config_spec.rb +1 -1
- data/spec/tools/table_manager/table_item_spec.rb +1 -1
- data/spec/tools/table_manager/tablemanager_core_spec.rb +4 -4
- data/spec/top_level/top_level_spec.rb +151 -3
- data/spec/utilities/csv_spec.rb +24 -5
- metadata +61 -9
- data/lib/cosmos/tools/replay/replay_server.rb +0 -91
|
@@ -102,6 +102,10 @@ module Cosmos
|
|
|
102
102
|
@option_action.statusTip = tr('Application Options')
|
|
103
103
|
connect(@option_action, SIGNAL('triggered()'), self, SLOT('file_options()'))
|
|
104
104
|
|
|
105
|
+
@replay_action = Qt::Action.new(tr('Toggle Replay Mode'), self)
|
|
106
|
+
@replay_action.statusTip = tr('Toggle Replay Mode')
|
|
107
|
+
@replay_action.connect(SIGNAL('triggered()')) { toggle_replay_mode() }
|
|
108
|
+
|
|
105
109
|
@color_blind_action = Qt::Action.new(tr('Color&blind Mode'), self)
|
|
106
110
|
@color_blind_keyseq = Qt::KeySequence.new(tr('Ctrl+B'))
|
|
107
111
|
@color_blind_action.shortcut = @color_blind_keyseq
|
|
@@ -180,6 +184,7 @@ module Cosmos
|
|
|
180
184
|
file_menu.addAction(@edit_action)
|
|
181
185
|
file_menu.addAction(@reset_action)
|
|
182
186
|
file_menu.addAction(@option_action)
|
|
187
|
+
file_menu.addAction(@replay_action)
|
|
183
188
|
file_menu.addSeparator()
|
|
184
189
|
file_menu.addAction(@exit_action)
|
|
185
190
|
|
|
@@ -207,6 +212,11 @@ module Cosmos
|
|
|
207
212
|
# Create the top level vertical layout
|
|
208
213
|
top_layout = Qt::VBoxLayout.new(central_widget)
|
|
209
214
|
|
|
215
|
+
@replay_flag = Qt::Label.new("Replay Mode")
|
|
216
|
+
@replay_flag.setStyleSheet("background:green;color:white;padding:5px;font-weight:bold;")
|
|
217
|
+
top_layout.addWidget(@replay_flag)
|
|
218
|
+
@replay_flag.hide
|
|
219
|
+
|
|
210
220
|
# Set the target combobox selection
|
|
211
221
|
@target_select = Qt::ComboBox.new
|
|
212
222
|
@target_select.setMaxVisibleItems(6)
|
|
@@ -265,6 +275,15 @@ module Cosmos
|
|
|
265
275
|
@polling_rate, 0, 1000, 1, nil)
|
|
266
276
|
end
|
|
267
277
|
|
|
278
|
+
def toggle_replay_mode
|
|
279
|
+
set_replay_mode(!get_replay_mode())
|
|
280
|
+
if get_replay_mode()
|
|
281
|
+
@replay_flag.show
|
|
282
|
+
else
|
|
283
|
+
@replay_flag.hide
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
268
287
|
def edit_definition
|
|
269
288
|
# Grab all the cmd_tlm_files and processes them in reverse sort order
|
|
270
289
|
# because typically we'll have cmd.txt and tlm.txt and we want to process
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# encoding: ascii-8bit
|
|
2
2
|
|
|
3
|
-
# Copyright
|
|
3
|
+
# Copyright 2017 Ball Aerospace & Technologies Corp.
|
|
4
4
|
# All Rights Reserved.
|
|
5
5
|
#
|
|
6
6
|
# This program is free software; you can modify and/or redistribute it
|
|
@@ -9,509 +9,9 @@
|
|
|
9
9
|
# attribution addendums as found in the LICENSE.txt
|
|
10
10
|
|
|
11
11
|
require 'cosmos'
|
|
12
|
-
|
|
13
|
-
require 'cosmos/gui/qt_tool'
|
|
14
|
-
require 'cosmos/gui/dialogs/splash'
|
|
15
|
-
require 'cosmos/gui/dialogs/progress_dialog'
|
|
16
|
-
require 'cosmos/gui/dialogs/packet_log_dialog'
|
|
17
|
-
require 'cosmos/tools/replay/replay_server'
|
|
18
|
-
require 'cosmos/gui/choosers/string_chooser'
|
|
19
|
-
end
|
|
12
|
+
require 'cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui'
|
|
20
13
|
|
|
21
14
|
module Cosmos
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
UNKNOWN_BYTES_TO_PRINT = 36
|
|
26
|
-
|
|
27
|
-
def initialize(options)
|
|
28
|
-
# MUST BE FIRST - All code before super is executed twice in RubyQt Based classes
|
|
29
|
-
super(options)
|
|
30
|
-
Cosmos.load_cosmos_icon("replay.png")
|
|
31
|
-
|
|
32
|
-
initialize_actions()
|
|
33
|
-
initialize_menus()
|
|
34
|
-
initialize_central_widget()
|
|
35
|
-
complete_initialize()
|
|
36
|
-
|
|
37
|
-
@ready = false
|
|
38
|
-
Splash.execute(self) do |splash|
|
|
39
|
-
ConfigParser.splash = splash
|
|
40
|
-
splash.message = "Initializing Replay Server"
|
|
41
|
-
|
|
42
|
-
# Start the thread that will process server messages and add them to the output text
|
|
43
|
-
process_server_messages(options)
|
|
44
|
-
|
|
45
|
-
ReplayServer.new(options.config_file, false, false, false)
|
|
46
|
-
@ready = true
|
|
47
|
-
|
|
48
|
-
ConfigParser.splash = nil
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Initialize variables
|
|
52
|
-
@packet_log_reader = System.default_packet_log_reader.new(*System.default_packet_log_reader_params)
|
|
53
|
-
@log_directory = System.paths['LOGS']
|
|
54
|
-
@log_directory << '/' unless @log_directory[-1..-1] == '\\' or @log_directory[-1..-1] == '/'
|
|
55
|
-
@log_filename = nil
|
|
56
|
-
@playing = false
|
|
57
|
-
@playback_thread = nil
|
|
58
|
-
@playback_index = 0
|
|
59
|
-
@packet_offsets = []
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def initialize_menus
|
|
63
|
-
# File Menu
|
|
64
|
-
@file_menu = menuBar.addMenu(tr('&File'))
|
|
65
|
-
@file_menu.addAction(@exit_action)
|
|
66
|
-
|
|
67
|
-
# Help Menu
|
|
68
|
-
@about_string = "Telemetry Viewer provides a view of every telemetry packet in the system."
|
|
69
|
-
@about_string << " Packets can be viewed in numerous represenations ranging from the raw data to formatted with units."
|
|
70
|
-
|
|
71
|
-
initialize_help_menu()
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def initialize_central_widget
|
|
75
|
-
# Create the central widget
|
|
76
|
-
@central_widget = Qt::Widget.new
|
|
77
|
-
setCentralWidget(@central_widget)
|
|
78
|
-
|
|
79
|
-
@top_layout = Qt::VBoxLayout.new
|
|
80
|
-
|
|
81
|
-
@log_widget = Qt::Widget.new
|
|
82
|
-
@log_widget.setSizePolicy(Qt::SizePolicy::MinimumExpanding, Qt::SizePolicy::MinimumExpanding)
|
|
83
|
-
@log_layout = Qt::VBoxLayout.new()
|
|
84
|
-
|
|
85
|
-
# This widget goes inside the top layout so we want 0 contents margins
|
|
86
|
-
@log_layout.setContentsMargins(0,0,0,0)
|
|
87
|
-
@log_widget.setLayout(@log_layout)
|
|
88
|
-
|
|
89
|
-
# Create the log file GUI
|
|
90
|
-
@log_file_selection = Qt::GroupBox.new("Log File Selection")
|
|
91
|
-
@log_select = Qt::HBoxLayout.new(@log_file_selection)
|
|
92
|
-
@log_name = Qt::LineEdit.new
|
|
93
|
-
@log_name.setReadOnly(true)
|
|
94
|
-
@log_select.addWidget(@log_name)
|
|
95
|
-
@log_open = Qt::PushButton.new("Browse...")
|
|
96
|
-
@log_select.addWidget(@log_open)
|
|
97
|
-
@log_layout.addWidget(@log_file_selection)
|
|
98
|
-
|
|
99
|
-
@log_open.connect(SIGNAL('clicked()')) { select_log_file() }
|
|
100
|
-
|
|
101
|
-
# Create the operation buttons GUI
|
|
102
|
-
@op = Qt::GroupBox.new(tr("Playback Control"))
|
|
103
|
-
@op_layout = Qt::VBoxLayout.new(@op)
|
|
104
|
-
@op_button_layout = Qt::HBoxLayout.new
|
|
105
|
-
@move_start = Qt::PushButton.new(Cosmos.get_icon('skip_to_start-26.png'), '')
|
|
106
|
-
@move_start.connect(SIGNAL('clicked()')) { move_start() }
|
|
107
|
-
@op_button_layout.addWidget(@move_start)
|
|
108
|
-
@step_back = Qt::PushButton.new(Cosmos.get_icon('rewind-26.png'), '')
|
|
109
|
-
@step_back_timer = Qt::Timer.new
|
|
110
|
-
@step_back_timeout = 100
|
|
111
|
-
@step_back_timer.connect(SIGNAL('timeout()')) { step_back(); @step_back_timeout = (@step_back_timeout / 2).to_i; @step_back_timer.start(@step_back_timeout) }
|
|
112
|
-
@step_back.connect(SIGNAL('pressed()')) { step_back(); @step_back_timeout = 300; @step_back_timer.start(@step_back_timeout) }
|
|
113
|
-
@step_back.connect(SIGNAL('released()')) { @step_back_timer.stop }
|
|
114
|
-
@op_button_layout.addWidget(@step_back)
|
|
115
|
-
@reverse_play = Qt::PushButton.new(Cosmos.get_icon('reverse-play-26.png'), '')
|
|
116
|
-
@reverse_play.connect(SIGNAL('clicked()')) { reverse_play() }
|
|
117
|
-
@op_button_layout.addWidget(@reverse_play)
|
|
118
|
-
@stop = Qt::PushButton.new(Cosmos.get_icon('stop-26.png'), '')
|
|
119
|
-
@stop.connect(SIGNAL('clicked()')) { stop() }
|
|
120
|
-
@op_button_layout.addWidget(@stop)
|
|
121
|
-
@play = Qt::PushButton.new(Cosmos.get_icon('play-26.png'), '')
|
|
122
|
-
@play.connect(SIGNAL('clicked()')) { play() }
|
|
123
|
-
@op_button_layout.addWidget(@play)
|
|
124
|
-
@step_forward = Qt::PushButton.new(Cosmos.get_icon('fast_forward-26.png'), '')
|
|
125
|
-
@step_forward_timer = Qt::Timer.new
|
|
126
|
-
@step_forward_timeout = 100
|
|
127
|
-
@step_forward_timer.connect(SIGNAL('timeout()')) { step_forward(); @step_forward_timeout = (@step_forward_timeout / 2).to_i; @step_forward_timer.start(@step_forward_timeout) }
|
|
128
|
-
@step_forward.connect(SIGNAL('pressed()')) { step_forward(); @step_forward_timeout = 300; @step_forward_timer.start(@step_forward_timeout) }
|
|
129
|
-
@step_forward.connect(SIGNAL('released()')) { @step_forward_timer.stop }
|
|
130
|
-
@op_button_layout.addWidget(@step_forward)
|
|
131
|
-
@move_end = Qt::PushButton.new(Cosmos.get_icon('end-26.png'), '')
|
|
132
|
-
@move_end.connect(SIGNAL('clicked()')) { move_end() }
|
|
133
|
-
@op_button_layout.addWidget(@move_end)
|
|
134
|
-
@op_layout.addLayout(@op_button_layout)
|
|
135
|
-
|
|
136
|
-
# Speed Selection
|
|
137
|
-
@playback_delay = nil
|
|
138
|
-
@speed_select = Qt::ComboBox.new
|
|
139
|
-
@variants = []
|
|
140
|
-
@variants << Qt::Variant.new(nil)
|
|
141
|
-
@speed_select.addItem("No Delay", @variants[-1])
|
|
142
|
-
@variants << Qt::Variant.new(0.001)
|
|
143
|
-
@speed_select.addItem("1ms Delay", @variants[-1])
|
|
144
|
-
@variants << Qt::Variant.new(0.002)
|
|
145
|
-
@speed_select.addItem("2ms Delay", @variants[-1])
|
|
146
|
-
@variants << Qt::Variant.new(0.005)
|
|
147
|
-
@speed_select.addItem("5ms Delay", @variants[-1])
|
|
148
|
-
@variants << Qt::Variant.new(0.01)
|
|
149
|
-
@speed_select.addItem("10ms Delay", @variants[-1])
|
|
150
|
-
@variants << Qt::Variant.new(0.05)
|
|
151
|
-
@speed_select.addItem("50ms Delay", @variants[-1])
|
|
152
|
-
@variants << Qt::Variant.new(0.125)
|
|
153
|
-
@speed_select.addItem("125ms Delay", @variants[-1])
|
|
154
|
-
@variants << Qt::Variant.new(0.25)
|
|
155
|
-
@speed_select.addItem("250ms Delay", @variants[-1])
|
|
156
|
-
@variants << Qt::Variant.new(0.5)
|
|
157
|
-
@speed_select.addItem("500ms Delay", @variants[-1])
|
|
158
|
-
@variants << Qt::Variant.new(1.0)
|
|
159
|
-
@speed_select.addItem("1s Delay", @variants[-1])
|
|
160
|
-
@variants << Qt::Variant.new(-1.0)
|
|
161
|
-
@speed_select.addItem("Realtime", @variants[-1])
|
|
162
|
-
@speed_select.setMaxVisibleItems(11)
|
|
163
|
-
@speed_select.connect(SIGNAL('currentIndexChanged(int)')) do
|
|
164
|
-
@playback_delay = @speed_select.itemData(@speed_select.currentIndex).value
|
|
165
|
-
end
|
|
166
|
-
@speed_layout = Qt::FormLayout.new()
|
|
167
|
-
@speed_layout.addRow("&Delay:", @speed_select)
|
|
168
|
-
@status = Qt::LineEdit.new
|
|
169
|
-
@status.setReadOnly(true)
|
|
170
|
-
@status.setText('Stopped')
|
|
171
|
-
@speed_layout.addRow("&Status:", @status)
|
|
172
|
-
@op_layout.addLayout(@speed_layout)
|
|
173
|
-
@log_layout.addWidget(@op)
|
|
174
|
-
|
|
175
|
-
@file_pos = Qt::GroupBox.new(tr("File Position"))
|
|
176
|
-
@file_pos_layout = Qt::VBoxLayout.new(@file_pos)
|
|
177
|
-
@slider = Qt::Slider.new(Qt::Horizontal)
|
|
178
|
-
@slider.setRange(0, 10000)
|
|
179
|
-
@slider.setTickInterval(1000)
|
|
180
|
-
@slider.setTickPosition(Qt::Slider::TicksBothSides)
|
|
181
|
-
@slider.setTracking(false)
|
|
182
|
-
@slider.connect(SIGNAL('sliderReleased()')) { slider_released() }
|
|
183
|
-
@time_layout = Qt::HBoxLayout.new()
|
|
184
|
-
@start_time = StringChooser.new(self, 'Start:', '', 200, true, true, Qt::AlignCenter | Qt::AlignVCenter)
|
|
185
|
-
@end_time = StringChooser.new(self, 'End:', '', 200, true, true, Qt::AlignCenter | Qt::AlignVCenter)
|
|
186
|
-
@current_time = StringChooser.new(self, 'Current:', '', 200, true, true, Qt::AlignCenter | Qt::AlignVCenter)
|
|
187
|
-
@time_layout.addWidget(@start_time)
|
|
188
|
-
@time_layout.addWidget(@current_time)
|
|
189
|
-
@time_layout.addWidget(@end_time)
|
|
190
|
-
@file_pos_layout.addLayout(@time_layout)
|
|
191
|
-
@file_pos_layout.addWidget(@slider)
|
|
192
|
-
@log_layout.addWidget(@file_pos)
|
|
193
|
-
@top_layout.addWidget(@log_widget)
|
|
194
|
-
|
|
195
|
-
# Add the message output
|
|
196
|
-
@output = Qt::PlainTextEdit.new
|
|
197
|
-
@output.setReadOnly(true)
|
|
198
|
-
@output.setMaximumBlockCount(100)
|
|
199
|
-
|
|
200
|
-
@top_layout.addWidget(@output, 500)
|
|
201
|
-
|
|
202
|
-
# Override stdout to the message window
|
|
203
|
-
# All code attempting to print into the GUI must use $stdout rather than STDOUT
|
|
204
|
-
@string_output = StringIO.new("", "r+")
|
|
205
|
-
$stdout = @string_output
|
|
206
|
-
Logger.level = Logger::INFO
|
|
207
|
-
|
|
208
|
-
@central_widget.setLayout(@top_layout)
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
def select_log_file
|
|
212
|
-
unless @playback_thread
|
|
213
|
-
packet_log_dialog = PacketLogDialog.new(
|
|
214
|
-
self, 'Select Log File', @log_directory, @packet_log_reader,
|
|
215
|
-
[], nil, false, false, true, Cosmos::TLM_FILE_PATTERN,
|
|
216
|
-
Cosmos::BIN_FILE_PATTERN, false
|
|
217
|
-
)
|
|
218
|
-
case packet_log_dialog.exec
|
|
219
|
-
when Qt::Dialog::Accepted
|
|
220
|
-
stop()
|
|
221
|
-
@packet_log_reader = packet_log_dialog.packet_log_reader
|
|
222
|
-
@log_filename = packet_log_dialog.filenames[0]
|
|
223
|
-
@log_directory = File.dirname(@log_filename)
|
|
224
|
-
@log_directory << '/' unless @log_directory[-1..-1] == '\\'
|
|
225
|
-
@log_name.text = @log_filename
|
|
226
|
-
|
|
227
|
-
System.telemetry.reset
|
|
228
|
-
@cancel = false
|
|
229
|
-
ProgressDialog.execute(self, 'Analyzing Log File', 500, 10, true, false, true, false, true) do |progress_dialog|
|
|
230
|
-
progress_dialog.append_text("Processing File: #{@log_filename}\n")
|
|
231
|
-
progress_dialog.set_overall_progress(0.0)
|
|
232
|
-
progress_dialog.cancel_callback = method(:cancel_callback)
|
|
233
|
-
progress_dialog.enable_cancel_button
|
|
234
|
-
Cosmos.check_log_configuration(@packet_log_reader, @log_filename)
|
|
235
|
-
@packet_offsets = @packet_log_reader.packet_offsets(@log_filename, lambda {|percentage| progress_dialog.set_overall_progress(percentage); @cancel})
|
|
236
|
-
@playback_index = 0
|
|
237
|
-
update_slider_and_current_time(nil)
|
|
238
|
-
@packet_log_reader.open(@log_filename)
|
|
239
|
-
progress_dialog.close_done
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
if ProgressDialog.canceled?
|
|
243
|
-
@packet_log_reader.close
|
|
244
|
-
@log_name.text = ''
|
|
245
|
-
@log_filename = nil
|
|
246
|
-
@packet_offsets = []
|
|
247
|
-
@playback_index = 0
|
|
248
|
-
@start_time.value = ''
|
|
249
|
-
@current_time.value = ''
|
|
250
|
-
@end_time.value = ''
|
|
251
|
-
else
|
|
252
|
-
move_end()
|
|
253
|
-
move_start()
|
|
254
|
-
end
|
|
255
|
-
end
|
|
256
|
-
end
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
def cancel_callback(progress_dialog = nil)
|
|
260
|
-
@cancel = true
|
|
261
|
-
return true, false
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
def move_start
|
|
265
|
-
if @log_filename and !@playback_thread
|
|
266
|
-
packet = read_at_index(0, :FORWARD)
|
|
267
|
-
@start_time.value = packet.received_time.formatted(true, 3, true) if packet and packet.received_time
|
|
268
|
-
else
|
|
269
|
-
stop()
|
|
270
|
-
end
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
def step_back
|
|
274
|
-
if @log_filename and !@playback_thread
|
|
275
|
-
@playback_index = @packet_offsets.length - 2 if @playback_index >= @packet_offsets.length
|
|
276
|
-
read_at_index(@playback_index, :BACKWARD)
|
|
277
|
-
else
|
|
278
|
-
stop()
|
|
279
|
-
end
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
def reverse_play
|
|
283
|
-
if @log_filename and !@playback_thread
|
|
284
|
-
@playback_index = @packet_offsets.length - 2 if @playback_index >= @packet_offsets.length
|
|
285
|
-
start_playback(:BACKWARD)
|
|
286
|
-
else
|
|
287
|
-
stop()
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
def stop
|
|
292
|
-
@playing = false
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
def play
|
|
296
|
-
if @log_filename and !@playback_thread
|
|
297
|
-
@playback_index = 1 if @playback_index < 0
|
|
298
|
-
start_playback(:FORWARD)
|
|
299
|
-
else
|
|
300
|
-
stop()
|
|
301
|
-
end
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
def step_forward
|
|
305
|
-
if @log_filename and !@playback_thread
|
|
306
|
-
@playback_index = 1 if @playback_index < 0
|
|
307
|
-
read_at_index(@playback_index, :FORWARD)
|
|
308
|
-
else
|
|
309
|
-
stop()
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
def move_end
|
|
314
|
-
if @log_filename and !@playback_thread
|
|
315
|
-
packet = read_at_index(@packet_offsets.length - 1, :FORWARD)
|
|
316
|
-
@end_time.value = packet.received_time.formatted(true, 3, true) if packet and packet.received_time
|
|
317
|
-
else
|
|
318
|
-
stop()
|
|
319
|
-
end
|
|
320
|
-
end
|
|
321
|
-
|
|
322
|
-
def slider_released
|
|
323
|
-
if @log_filename and !@playback_thread
|
|
324
|
-
read_at_index(((@slider.sliderPosition / 10000.0) * (@packet_offsets.length - 1)).to_i, :FORWARD)
|
|
325
|
-
end
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
def start_playback(direction)
|
|
329
|
-
@playback_thread = Thread.new do
|
|
330
|
-
error = nil
|
|
331
|
-
begin
|
|
332
|
-
@playing = true
|
|
333
|
-
Qt.execute_in_main_thread(true) do
|
|
334
|
-
@status.setText('Playing')
|
|
335
|
-
end
|
|
336
|
-
previous_packet = nil
|
|
337
|
-
while (@playing)
|
|
338
|
-
if @playback_delay
|
|
339
|
-
packet_start = Time.now.sys
|
|
340
|
-
packet = read_at_index(@playback_index, direction)
|
|
341
|
-
break unless packet
|
|
342
|
-
delay_time = 0.0
|
|
343
|
-
if @playback_delay > 0.0
|
|
344
|
-
delay_time = @playback_delay - (Time.now.sys - packet_start)
|
|
345
|
-
elsif previous_packet and packet.received_time and previous_packet.received_time
|
|
346
|
-
if direction == :FORWARD
|
|
347
|
-
delay_time = packet.received_time - previous_packet.received_time - (Time.now.sys - packet_start)
|
|
348
|
-
else
|
|
349
|
-
delay_time = previous_packet.received_time - packet.received_time - (Time.now.sys - packet_start)
|
|
350
|
-
end
|
|
351
|
-
end
|
|
352
|
-
sleep(delay_time) if delay_time > 0.0
|
|
353
|
-
previous_packet = packet
|
|
354
|
-
else
|
|
355
|
-
packet = read_at_index(@playback_index, direction)
|
|
356
|
-
break unless packet
|
|
357
|
-
end
|
|
358
|
-
end
|
|
359
|
-
rescue Exception => error
|
|
360
|
-
Qt.execute_in_main_thread(true) {|| ExceptionDialog.new(self, error, "Playback Thread")}
|
|
361
|
-
ensure
|
|
362
|
-
Qt.execute_in_main_thread(true) do
|
|
363
|
-
@status.setText('Stopped')
|
|
364
|
-
end
|
|
365
|
-
@playing = false
|
|
366
|
-
@playback_thread = nil
|
|
367
|
-
end
|
|
368
|
-
end
|
|
369
|
-
end
|
|
370
|
-
|
|
371
|
-
def read_at_index(index, direction)
|
|
372
|
-
packet_offset = nil
|
|
373
|
-
packet_offset = @packet_offsets[index] if index >= 0
|
|
374
|
-
if packet_offset
|
|
375
|
-
# Read the packet
|
|
376
|
-
packet = @packet_log_reader.read_at_offset(packet_offset, false)
|
|
377
|
-
handle_packet(packet)
|
|
378
|
-
|
|
379
|
-
# Adjust index for next read
|
|
380
|
-
if direction == :FORWARD
|
|
381
|
-
@playback_index = index + 1
|
|
382
|
-
else
|
|
383
|
-
@playback_index = index - 1
|
|
384
|
-
end
|
|
385
|
-
update_slider_and_current_time(packet)
|
|
386
|
-
|
|
387
|
-
return packet
|
|
388
|
-
else
|
|
389
|
-
return nil
|
|
390
|
-
end
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
def update_slider_and_current_time(packet)
|
|
394
|
-
Qt.execute_in_main_thread(false) do
|
|
395
|
-
value = (((@playback_index - 1) / @packet_offsets.length.to_f) * 10000).to_i
|
|
396
|
-
@slider.setSliderPosition(value)
|
|
397
|
-
@slider.setValue(value)
|
|
398
|
-
@current_time.value = packet.received_time.formatted(true, 3, true) if packet and packet.received_time
|
|
399
|
-
end
|
|
400
|
-
end
|
|
401
|
-
|
|
402
|
-
def handle_packet(packet)
|
|
403
|
-
# For replay we will try our best here but not crash on errors
|
|
404
|
-
begin
|
|
405
|
-
interface = nil
|
|
406
|
-
|
|
407
|
-
# Identify and update packet
|
|
408
|
-
if packet.identified?
|
|
409
|
-
# Preidentifed packet - place it into the current value table
|
|
410
|
-
identified_packet = System.telemetry.update!(packet.target_name,
|
|
411
|
-
packet.packet_name,
|
|
412
|
-
packet.buffer)
|
|
413
|
-
else
|
|
414
|
-
# Packet needs to be identified
|
|
415
|
-
identified_packet = System.telemetry.identify!(packet.buffer)
|
|
416
|
-
end
|
|
417
|
-
|
|
418
|
-
if identified_packet and packet.target_name != 'UNKNOWN'
|
|
419
|
-
identified_packet.received_time = packet.received_time
|
|
420
|
-
packet = identified_packet
|
|
421
|
-
target = System.targets[packet.target_name.upcase]
|
|
422
|
-
interface = target.interface if target
|
|
423
|
-
else
|
|
424
|
-
unknown_packet = System.telemetry.update!('UNKNOWN', 'UNKNOWN', packet.buffer)
|
|
425
|
-
unknown_packet.received_time = packet.received_time
|
|
426
|
-
packet = unknown_packet
|
|
427
|
-
data_length = packet.length
|
|
428
|
-
string = "Unknown #{data_length} byte packet starting: "
|
|
429
|
-
num_bytes_to_print = [UNKNOWN_BYTES_TO_PRINT, data_length].min
|
|
430
|
-
data_to_print = packet.buffer(false)[0..(num_bytes_to_print - 1)]
|
|
431
|
-
data_to_print.each_byte do |byte|
|
|
432
|
-
string << sprintf("%02X", byte)
|
|
433
|
-
end
|
|
434
|
-
time_string = ''
|
|
435
|
-
time_string = packet.received_time.formatted << ' ' if packet.received_time
|
|
436
|
-
puts "#{time_string}ERROR: #{string}"
|
|
437
|
-
end
|
|
438
|
-
|
|
439
|
-
target = System.targets[packet.target_name]
|
|
440
|
-
target.tlm_cnt += 1 if target
|
|
441
|
-
packet.received_count += 1
|
|
442
|
-
packet.check_limits(System.limits_set)
|
|
443
|
-
ReplayServer.instance.post_packet(packet)
|
|
444
|
-
|
|
445
|
-
# Write to routers
|
|
446
|
-
if interface
|
|
447
|
-
interface.routers.each do |router|
|
|
448
|
-
begin
|
|
449
|
-
router.write(packet) if router.write_allowed? and router.connected?
|
|
450
|
-
rescue => err
|
|
451
|
-
Logger.error "Problem writing to router #{router.name} - #{err.class}:#{err.message}"
|
|
452
|
-
end
|
|
453
|
-
end
|
|
454
|
-
end
|
|
455
|
-
rescue Exception => err
|
|
456
|
-
Logger.error "Problem handling packet #{packet.target_name} #{packet.packet_name} - #{err.class}:#{err.message}"
|
|
457
|
-
end
|
|
458
|
-
end
|
|
459
|
-
|
|
460
|
-
def process_server_messages(options)
|
|
461
|
-
# Start thread to read server messages
|
|
462
|
-
@output_thread = Thread.new do
|
|
463
|
-
begin
|
|
464
|
-
while !@ready
|
|
465
|
-
sleep(1)
|
|
466
|
-
end
|
|
467
|
-
while true
|
|
468
|
-
if @string_output.string[-1..-1] == "\n"
|
|
469
|
-
Qt.execute_in_main_thread(true) do
|
|
470
|
-
string = @string_output.string.clone
|
|
471
|
-
@string_output.string = @string_output.string[string.length..-1]
|
|
472
|
-
string.each_line {|out_line| @output.add_formatted_text(out_line) }
|
|
473
|
-
@output.flush
|
|
474
|
-
end
|
|
475
|
-
end
|
|
476
|
-
sleep(1)
|
|
477
|
-
end
|
|
478
|
-
rescue Exception => error
|
|
479
|
-
Qt.execute_in_main_thread(true) do
|
|
480
|
-
ExceptionDialog.new(self, error, "#{options.title}: Messages Thread")
|
|
481
|
-
end
|
|
482
|
-
end
|
|
483
|
-
end
|
|
484
|
-
end
|
|
485
|
-
|
|
486
|
-
def closeEvent(event)
|
|
487
|
-
Cosmos.kill_thread(self, @playback_thread)
|
|
488
|
-
super(event)
|
|
489
|
-
end
|
|
490
|
-
|
|
491
|
-
# Gracefully kill threads
|
|
492
|
-
def graceful_kill
|
|
493
|
-
stop()
|
|
494
|
-
end
|
|
495
|
-
|
|
496
|
-
def self.run(option_parser = nil, options = nil)
|
|
497
|
-
Cosmos.catch_fatal_exception do
|
|
498
|
-
unless option_parser and options
|
|
499
|
-
option_parser, options = create_default_options()
|
|
500
|
-
options.title = 'Replay'
|
|
501
|
-
options.width = 800
|
|
502
|
-
options.height = 500
|
|
503
|
-
options.auto_size = false
|
|
504
|
-
options.config_file = CmdTlmServer::DEFAULT_CONFIG_FILE
|
|
505
|
-
option_parser.separator "Replay Specific Options:"
|
|
506
|
-
option_parser.on("-c", "--config FILE", "Use the specified configuration file") do |arg|
|
|
507
|
-
options.config_file = arg
|
|
508
|
-
end
|
|
509
|
-
end
|
|
510
|
-
|
|
511
|
-
super(option_parser, options)
|
|
512
|
-
end
|
|
513
|
-
end
|
|
514
|
-
|
|
515
|
-
end # class Replay
|
|
516
|
-
|
|
517
|
-
end # module Cosmos
|
|
15
|
+
class Replay < CmdTlmServerGui
|
|
16
|
+
end
|
|
17
|
+
end
|