cosmos 3.8.3 → 3.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/Manifest.txt +14 -0
- data/Rakefile +35 -2
- data/autohotkey/config/targets/INST/screens/_footer.txt +4 -0
- data/autohotkey/config/targets/INST/screens/hs.txt +1 -4
- data/autohotkey/config/tools/table_manager/OldOneDimensionalTable_def.txt +19 -0
- data/autohotkey/config/tools/table_manager/OldTwoDimensionalTable_def.txt +248 -0
- data/autohotkey/config/tools/table_manager/OneDimensionalTable_def.txt +27 -15
- data/autohotkey/config/tools/table_manager/TwoDimensionalTable_def.txt +12 -232
- data/autohotkey/procedures/example_test.rb +4 -0
- data/autohotkey/tools/TableManagerAHK +4 -9
- data/autohotkey/tools/TableManagerAHK2 +18 -0
- data/autohotkey/tools/TableManagerAHK3 +18 -0
- data/autohotkey/tools/TableManagerAHK4 +24 -0
- data/autohotkey/tools/TlmViewerAHK +1 -1
- data/autohotkey/tools/autohotkey.rb +2 -1
- data/autohotkey/tools/open_gl_builder.ahk +1 -1
- data/autohotkey/tools/table_manager.ahk +141 -70
- data/cosmos.gemspec +3 -3
- data/data/crc.txt +70 -68
- data/data/legal.txt +4 -5
- data/demo/config/data/crc.txt +10 -9
- data/demo/config/targets/INST/screens/_footer.txt +4 -0
- data/demo/config/targets/INST/screens/hs.txt +1 -6
- data/demo/config/targets/INST/screens/limits.txt +3 -11
- data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +1 -0
- data/demo/config/tools/table_manager/MCConfigurationTable_fsw1_def.txt +33 -22
- data/demo/config/tools/table_manager/MCConfigurationTable_fsw2_def.txt +30 -22
- data/demo/config/tools/table_manager/PPSSelectionTable_def.txt +8 -7
- data/demo/config/tools/table_manager/TLMMonitoringTable_def.txt +13 -13
- data/demo/lib/example_background_task.rb +6 -12
- data/demo/procedures/example_test.rb +5 -0
- data/lib/cosmos/conversions/conversion.rb +3 -7
- data/lib/cosmos/core_ext/class.rb +3 -1
- data/lib/cosmos/core_ext/file.rb +1 -0
- data/lib/cosmos/core_ext/io.rb +18 -0
- data/lib/cosmos/core_ext/range.rb +1 -5
- data/lib/cosmos/core_ext/time.rb +3 -3
- data/lib/cosmos/gui/dialogs/about_dialog.rb +60 -36
- data/lib/cosmos/gui/dialogs/calendar_dialog.rb +10 -14
- data/lib/cosmos/gui/dialogs/cmd_details_dialog.rb +4 -5
- data/lib/cosmos/gui/dialogs/cmd_tlm_raw_dialog.rb +31 -17
- data/lib/cosmos/gui/dialogs/details_dialog.rb +63 -47
- data/lib/cosmos/gui/dialogs/exception_dialog.rb +77 -68
- data/lib/cosmos/gui/dialogs/exception_list_dialog.rb +6 -5
- data/lib/cosmos/gui/dialogs/legal_dialog.rb +34 -21
- data/lib/cosmos/gui/dialogs/packet_log_dialog.rb +19 -43
- data/lib/cosmos/gui/dialogs/progress_dialog.rb +79 -42
- data/lib/cosmos/gui/dialogs/pry_dialog.rb +9 -5
- data/lib/cosmos/gui/dialogs/scroll_text_dialog.rb +6 -4
- data/lib/cosmos/gui/dialogs/select_dialog.rb +23 -18
- data/lib/cosmos/gui/dialogs/set_tlm_dialog.rb +34 -10
- data/lib/cosmos/gui/dialogs/splash.rb +18 -8
- data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +38 -43
- data/lib/cosmos/gui/dialogs/tlm_edit_dialog.rb +51 -53
- data/lib/cosmos/gui/line_graph/line_graph_scaling.rb +1 -1
- data/lib/cosmos/gui/line_graph/lines.rb +1 -1
- data/lib/cosmos/gui/qt.rb +9 -2
- data/lib/cosmos/gui/qt_tool.rb +50 -8
- data/lib/cosmos/gui/widgets/packet_log_frame.rb +53 -27
- data/lib/cosmos/interfaces/linc_interface.rb +103 -62
- data/lib/cosmos/io/json_drb_object.rb +3 -3
- data/lib/cosmos/io/raw_logger.rb +4 -8
- data/lib/cosmos/io/tcpip_server.rb +2 -2
- data/lib/cosmos/packets/binary_accessor.rb +1 -1
- data/lib/cosmos/packets/limits.rb +2 -5
- data/lib/cosmos/packets/packet.rb +1 -1
- data/lib/cosmos/packets/packet_config.rb +54 -19
- data/lib/cosmos/packets/parsers/packet_item_parser.rb +7 -1
- data/lib/cosmos/script/scripting.rb +4 -5
- data/lib/cosmos/system/system.rb +2 -1
- data/lib/cosmos/system/target.rb +4 -0
- data/lib/cosmos/tools/cmd_tlm_server/background_task.rb +13 -5
- data/lib/cosmos/tools/cmd_tlm_server/background_tasks.rb +37 -27
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +6 -2
- data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +7 -5
- data/lib/cosmos/tools/cmd_tlm_server/gui/status_tab.rb +21 -10
- data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +11 -11
- data/lib/cosmos/tools/script_runner/script_runner.rb +2 -18
- data/lib/cosmos/tools/script_runner/script_runner_frame.rb +6 -6
- data/lib/cosmos/tools/table_manager/table.rb +32 -41
- data/lib/cosmos/tools/table_manager/table_config.rb +140 -729
- data/lib/cosmos/tools/table_manager/table_item.rb +20 -36
- data/lib/cosmos/tools/table_manager/table_item_parser.rb +46 -0
- data/lib/cosmos/tools/table_manager/table_manager.rb +754 -691
- data/lib/cosmos/tools/table_manager/table_manager_core.rb +172 -358
- data/lib/cosmos/tools/table_manager/table_parser.rb +75 -0
- data/lib/cosmos/tools/test_runner/results_writer.rb +1 -1
- data/lib/cosmos/tools/test_runner/test_runner.rb +11 -0
- data/lib/cosmos/tools/tlm_grapher/data_object_adders/housekeeping_data_object_adder.rb +2 -2
- data/lib/cosmos/tools/tlm_grapher/data_object_adders/singlexy_data_object_adder.rb +2 -2
- data/lib/cosmos/tools/tlm_grapher/data_object_adders/xy_data_object_adder.rb +2 -2
- data/lib/cosmos/tools/tlm_grapher/data_objects/data_object.rb +4 -4
- data/lib/cosmos/tools/tlm_grapher/data_objects/housekeeping_data_object.rb +13 -13
- data/lib/cosmos/tools/tlm_grapher/data_objects/linegraph_data_object.rb +9 -9
- data/lib/cosmos/tools/tlm_grapher/data_objects/xy_data_object.rb +9 -9
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_config.rb +4 -4
- data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tool.rb +1 -1
- data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +8 -18
- data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +7 -4
- data/lib/cosmos/top_level.rb +12 -0
- data/lib/cosmos/version.rb +5 -5
- data/run_gui_tests.bat +6 -0
- data/spec/core_ext/array_spec.rb +1 -1
- data/spec/interfaces/linc_interface_spec.rb +4 -4
- data/spec/io/json_drb_spec.rb +2 -2
- data/spec/io/json_rpc_spec.rb +1 -1
- data/spec/io/raw_logger_spec.rb +5 -1
- data/spec/packet_logs/packet_log_writer_spec.rb +1 -1
- data/spec/packets/packet_config_spec.rb +144 -0
- data/spec/packets/parsers/packet_item_parser_spec.rb +60 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/system/target_spec.rb +5 -1
- data/spec/tools/cmd_tlm_server/background_task_spec.rb +15 -3
- data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +117 -31
- data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +4 -0
- data/spec/tools/launcher/launcher_config_spec.rb +1 -1
- data/spec/tools/table_manager/table_config_spec.rb +226 -0
- data/spec/tools/table_manager/table_item_spec.rb +57 -0
- data/spec/tools/table_manager/table_parser_spec.rb +96 -0
- data/spec/tools/table_manager/table_spec.rb +90 -0
- data/spec/tools/table_manager/tablemanager_core_spec.rb +557 -0
- data/spec/top_level/top_level_spec.rb +9 -0
- data/spec/utilities/csv_spec.rb +3 -3
- metadata +30 -11
@@ -12,12 +12,9 @@ require 'cosmos'
|
|
12
12
|
require 'cosmos/gui/qt'
|
13
13
|
|
14
14
|
module Cosmos
|
15
|
-
|
16
15
|
# Implements the status tab in the Command and Telemetry Server GUI
|
17
16
|
class StatusTab
|
18
|
-
|
19
17
|
# Create the status tab and add it to the tab_widget
|
20
|
-
#
|
21
18
|
# @param tab_widget [Qt::TabWidget] The tab widget to add the tab to
|
22
19
|
def populate(tab_widget)
|
23
20
|
scroll = Qt::ScrollArea.new
|
@@ -141,22 +138,22 @@ module Cosmos
|
|
141
138
|
@background_tasks_table = Qt::TableWidget.new()
|
142
139
|
@background_tasks_table.verticalHeader.hide()
|
143
140
|
@background_tasks_table.setRowCount(CmdTlmServer.background_tasks.all.length)
|
144
|
-
@background_tasks_table.setColumnCount(
|
145
|
-
@background_tasks_table.setHorizontalHeaderLabels(["Name", "State", "Status"])
|
141
|
+
@background_tasks_table.setColumnCount(4)
|
142
|
+
@background_tasks_table.setHorizontalHeaderLabels(["Name", "State", "Status", "Control"])
|
146
143
|
|
147
144
|
background_tasks = CmdTlmServer.background_tasks.all
|
148
145
|
if background_tasks.length > 0
|
149
146
|
row = 0
|
150
147
|
background_tasks.each_with_index do |background_task, index|
|
151
|
-
|
152
|
-
background_task_name = "Background Task ##{index + 1}" unless background_task_name
|
153
|
-
background_task_name_widget = Qt::TableWidgetItem.new(background_task_name)
|
148
|
+
background_task_name_widget = Qt::TableWidgetItem.new(background_task.name)
|
154
149
|
background_task_name_widget.setTextAlignment(Qt::AlignCenter)
|
155
150
|
@background_tasks_table.setItem(row, 0, background_task_name_widget)
|
151
|
+
button_text = 'START'
|
156
152
|
if background_task.thread
|
157
153
|
status = background_task.thread.status
|
158
154
|
status = 'complete' if status == false
|
159
155
|
background_task_state_widget = Qt::TableWidgetItem.new(status.to_s)
|
156
|
+
button_text = background_task.thread.alive? ? 'STOP' : 'START'
|
160
157
|
else
|
161
158
|
background_task_state_widget = Qt::TableWidgetItem.new('no thread')
|
162
159
|
end
|
@@ -165,9 +162,12 @@ module Cosmos
|
|
165
162
|
@background_tasks_table.setItem(row, 1, background_task_state_widget)
|
166
163
|
background_task_status_widget = Qt::TableWidgetItem.new(background_task.status.to_s)
|
167
164
|
background_task_status_widget.setTextAlignment(Qt::AlignCenter)
|
168
|
-
background_task_status_widget.setSizeHint(Qt::Size.new(
|
165
|
+
background_task_status_widget.setSizeHint(Qt::Size.new(400, 30))
|
169
166
|
@background_tasks_table.setItem(row, 2, background_task_status_widget)
|
170
167
|
|
168
|
+
background_task_button = Qt::PushButton.new(button_text)
|
169
|
+
background_task_button.connect(SIGNAL('clicked()')) { start_stop_task(background_task_button) }
|
170
|
+
@background_tasks_table.setCellWidget(row, 3, background_task_button)
|
171
171
|
row += 1
|
172
172
|
end
|
173
173
|
end
|
@@ -231,6 +231,8 @@ module Cosmos
|
|
231
231
|
status = background_task.thread.status
|
232
232
|
status = 'complete' if status == false
|
233
233
|
@background_tasks_table.item(row, 1).setText(status.to_s)
|
234
|
+
text = background_task.thread.alive? ? 'STOP' : 'START'
|
235
|
+
@background_tasks_table.cellWidget(row, 3).setText(text)
|
234
236
|
else
|
235
237
|
@background_tasks_table.item(row, 1).setText('no thread')
|
236
238
|
end
|
@@ -240,5 +242,14 @@ module Cosmos
|
|
240
242
|
end
|
241
243
|
end
|
242
244
|
|
245
|
+
# Start or stop the background task
|
246
|
+
def start_stop_task(button)
|
247
|
+
row = @background_tasks_table.indexAt(button.pos()).row
|
248
|
+
if button.text == 'STOP'
|
249
|
+
CmdTlmServer.background_tasks.stop(row)
|
250
|
+
else
|
251
|
+
CmdTlmServer.background_tasks.start(row)
|
252
|
+
end
|
253
|
+
end
|
243
254
|
end
|
244
|
-
end
|
255
|
+
end
|
@@ -223,7 +223,7 @@ module Cosmos
|
|
223
223
|
|
224
224
|
# Load a new configuration of ignored items and packets and reset
|
225
225
|
#
|
226
|
-
# @param
|
226
|
+
# @param filename [String] Configuration file base name which will be
|
227
227
|
# expanded to find a file in the config/tools/limits_monitor dir.
|
228
228
|
# @return [String] Message indicating success or fail
|
229
229
|
def open_config(filename)
|
@@ -263,7 +263,7 @@ module Cosmos
|
|
263
263
|
|
264
264
|
# Save the current configuration of ignored items and packets.
|
265
265
|
#
|
266
|
-
# @param
|
266
|
+
# @param filename [String] Configuration file to save.
|
267
267
|
# @return [String] Message indicating success or fail
|
268
268
|
def save_config(filename)
|
269
269
|
begin
|
@@ -374,10 +374,10 @@ module Cosmos
|
|
374
374
|
# @return [Widget] The widget which displays the value
|
375
375
|
attr_accessor :value
|
376
376
|
|
377
|
-
# @parent [Qt::Widget] Parent widget (the LimitsMonitor tool)
|
378
|
-
# @target_name [String] Target name
|
379
|
-
# @packet_name [String] Packet name
|
380
|
-
# @item_name [String] Telemetry item name (nil for stale packets)
|
377
|
+
# @param parent [Qt::Widget] Parent widget (the LimitsMonitor tool)
|
378
|
+
# @param target_name [String] Target name
|
379
|
+
# @param packet_name [String] Packet name
|
380
|
+
# @param item_name [String] Telemetry item name (nil for stale packets)
|
381
381
|
def initialize(parent, target_name, packet_name, item_name)
|
382
382
|
super(parent)
|
383
383
|
@layout = Qt::HBoxLayout.new
|
@@ -714,12 +714,12 @@ module Cosmos
|
|
714
714
|
widget
|
715
715
|
end
|
716
716
|
|
717
|
-
# Update
|
717
|
+
# Update a widget with new values
|
718
718
|
#
|
719
|
-
# @param
|
720
|
-
# @param
|
721
|
-
# @param
|
722
|
-
#
|
719
|
+
# @param widget [Qt::Widget] The widget to update
|
720
|
+
# @param value [Object] Value to update
|
721
|
+
# @param limits_state [Symbol] The items limits state, e.g. :GREEN, :RED, etc
|
722
|
+
# @param limits_set [Symbol] The current limits set, e.g. :DEFAULT
|
723
723
|
def update_gui_item(widget, value, limits_state, limits_set)
|
724
724
|
Qt.execute_in_main_thread(true) do
|
725
725
|
widget.set_values(value, limits_state, limits_set) if widget
|
@@ -253,23 +253,7 @@ module Cosmos
|
|
253
253
|
|
254
254
|
@file_open = @file_menu.addMenu(tr('&Open'))
|
255
255
|
@file_open.setIcon(Cosmos.get_icon('open.png'))
|
256
|
-
System.paths['PROCEDURES']
|
257
|
-
next unless File.exist? path
|
258
|
-
path_context = path.split('/')[-2..-1].join('/')
|
259
|
-
action = Qt::Action.new(tr(path_context), self)
|
260
|
-
action.statusTip = "Open #{path}"
|
261
|
-
action.connect(SIGNAL('triggered()')) { file_open(path) }
|
262
|
-
@file_open.addAction(action)
|
263
|
-
end
|
264
|
-
@file_open.addSeparator()
|
265
|
-
System.targets.each do |target_name, target|
|
266
|
-
proc_dir = File.join(target.dir, 'procedures')
|
267
|
-
next unless File.exist? proc_dir
|
268
|
-
action = Qt::Action.new(tr("#{target_name}/procedures"), self)
|
269
|
-
action.statusTip = "Open #{proc_dir}"
|
270
|
-
action.connect(SIGNAL('triggered()')) { file_open(File.join(target.dir, 'procedures')) }
|
271
|
-
@file_open.addAction(action)
|
272
|
-
end
|
256
|
+
target_dirs_action(@file_open, System.paths['PROCEDURES'], 'procedures', method(:file_open))
|
273
257
|
|
274
258
|
@file_menu.addAction(@file_close)
|
275
259
|
@file_menu.addAction(@file_reload)
|
@@ -619,7 +603,7 @@ module Cosmos
|
|
619
603
|
@debug = !@debug
|
620
604
|
if @tab_book.count > 0
|
621
605
|
(0..(@tab_book.count - 1)).each do |index|
|
622
|
-
@tab_book.
|
606
|
+
@tab_book.widget(index).toggle_debug(@debug)
|
623
607
|
end
|
624
608
|
end
|
625
609
|
end
|
@@ -708,7 +708,7 @@ module Cosmos
|
|
708
708
|
end
|
709
709
|
|
710
710
|
def run_selection_while_paused
|
711
|
-
current_script = @tab_book.
|
711
|
+
current_script = @tab_book.widget(@tab_book.currentIndex)
|
712
712
|
selection = current_script.selected_lines
|
713
713
|
if selection
|
714
714
|
start_line_number = current_script.selection_start_line
|
@@ -845,7 +845,7 @@ module Cosmos
|
|
845
845
|
if @tab_book_shown
|
846
846
|
if @tab_book.count > 0
|
847
847
|
(0..(@tab_book.count - 1)).each do |index|
|
848
|
-
@tab_book.
|
848
|
+
@tab_book.widget(index).enable_breakpoints = true
|
849
849
|
end
|
850
850
|
end
|
851
851
|
end
|
@@ -948,7 +948,7 @@ module Cosmos
|
|
948
948
|
if @tab_book_shown
|
949
949
|
if @tab_book.count > 0
|
950
950
|
(0..(@tab_book.count - 1)).each do |index|
|
951
|
-
@tab_book.
|
951
|
+
@tab_book.widget(index).enable_breakpoints = false
|
952
952
|
end
|
953
953
|
end
|
954
954
|
end
|
@@ -984,13 +984,13 @@ module Cosmos
|
|
984
984
|
Qt.execute_in_main_thread(true) do
|
985
985
|
if @tab_book_shown
|
986
986
|
@tab_book.setCurrentIndex(index)
|
987
|
-
@active_script = @tab_book.
|
987
|
+
@active_script = @tab_book.widget(@tab_book.currentIndex)
|
988
988
|
|
989
989
|
first_to_remove = index + 1
|
990
990
|
last_to_remove = @call_stack.length - 1
|
991
991
|
|
992
992
|
last_to_remove.downto(first_to_remove) do |tab_index|
|
993
|
-
tab = @tab_book.
|
993
|
+
tab = @tab_book.widget(tab_index)
|
994
994
|
@tab_book.removeTab(tab_index)
|
995
995
|
tab.dispose
|
996
996
|
end
|
@@ -1489,7 +1489,7 @@ module Cosmos
|
|
1489
1489
|
# is shown
|
1490
1490
|
if not self.class.running? or (running?() and @realtime_button_bar.state != 'Running')
|
1491
1491
|
if @tab_book_shown
|
1492
|
-
current_script = @tab_book.
|
1492
|
+
current_script = @tab_book.widget(@tab_book.currentIndex)
|
1493
1493
|
else
|
1494
1494
|
current_script = @script
|
1495
1495
|
end
|
@@ -12,59 +12,50 @@ require 'cosmos'
|
|
12
12
|
require 'cosmos/tools/table_manager/table_item'
|
13
13
|
|
14
14
|
module Cosmos
|
15
|
-
|
16
15
|
# Table extends Packet by adding more attributes relative to
|
17
16
|
# displaying binary data in a gui.
|
18
17
|
class Table < Packet
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
# Define the target for tables as 'TABLE' since there is no target
|
19
|
+
TARGET = 'TABLE'
|
20
|
+
# @return [Symbol] Either :ONE_DIMENSIONAL or :TWO_DIMENSIONAL
|
22
21
|
attr_reader :type
|
23
|
-
|
22
|
+
# @return [String] File which contains the table definition
|
24
23
|
attr_reader :filename
|
24
|
+
# @return [Integer] Number of columns in the table
|
25
|
+
attr_accessor :num_columns
|
26
|
+
|
27
|
+
alias table_name packet_name
|
25
28
|
|
26
29
|
# Constructor for a TableDefinition
|
27
|
-
def initialize(name,
|
28
|
-
super(
|
29
|
-
|
30
|
+
def initialize(name, endianness, type, description, filename)
|
31
|
+
super(TARGET, name, endianness, description, '', TableItem)
|
32
|
+
if type != :ONE_DIMENSIONAL && type != :TWO_DIMENSIONAL
|
33
|
+
raise ArgumentError, "Invalid type '#{type}' for table '#{name}'. Must be ONE_DIMENSIONAL or TWO_DIMENSIONAL"
|
34
|
+
end
|
30
35
|
@type = type
|
31
|
-
@table_id = table_id
|
32
36
|
@filename = filename
|
33
|
-
@num_columns = 0
|
34
37
|
@num_rows = 0
|
35
|
-
@num_columns =
|
38
|
+
@num_columns = (@type == :ONE_DIMENSIONAL) ? 1 : 0
|
36
39
|
end
|
37
40
|
|
38
|
-
#
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
item.display_type = display_type
|
47
|
-
item.editable = editable
|
48
|
-
item
|
41
|
+
# @param num_rows [Integer] Set the number of rows in a TWO_DIMENSIONAL table
|
42
|
+
def num_rows=(num_rows)
|
43
|
+
case @type
|
44
|
+
when :ONE_DIMENSIONAL
|
45
|
+
raise "Rows are fixed in a ONE_DIMENSIONAL table"
|
46
|
+
when :TWO_DIMENSIONAL
|
47
|
+
@num_rows = num_rows
|
48
|
+
end
|
49
49
|
end
|
50
50
|
|
51
|
-
#
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
item.write_conversion, item.id_value)
|
60
|
-
new_item.description = item.description
|
61
|
-
new_item.range = item.range
|
62
|
-
new_item.display_type = item.display_type
|
63
|
-
new_item.editable = item.editable
|
64
|
-
new_item.states = item.states
|
65
|
-
new_item.constraint = item.constraint
|
66
|
-
new_item
|
51
|
+
# @return [Integer] Number of rows in the table
|
52
|
+
def num_rows
|
53
|
+
case @type
|
54
|
+
when :ONE_DIMENSIONAL
|
55
|
+
@sorted_items.count {|item| !item.hidden }
|
56
|
+
when :TWO_DIMENSIONAL
|
57
|
+
@num_rows
|
58
|
+
end
|
67
59
|
end
|
68
|
-
end
|
69
|
-
|
70
|
-
end # module Cosmos
|
60
|
+
end
|
61
|
+
end
|
@@ -8,765 +8,176 @@
|
|
8
8
|
# as published by the Free Software Foundation; version 3 with
|
9
9
|
# attribution addendums as found in the LICENSE.txt
|
10
10
|
|
11
|
-
require 'cosmos'
|
11
|
+
require 'cosmos/config/config_parser'
|
12
|
+
require 'cosmos/packets/packet_config'
|
12
13
|
require 'cosmos/tools/table_manager/table'
|
14
|
+
require 'cosmos/tools/table_manager/table_parser'
|
15
|
+
require 'cosmos/tools/table_manager/table_item_parser'
|
13
16
|
|
14
17
|
module Cosmos
|
15
|
-
|
16
|
-
#
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
#
|
18
|
+
# Processes the Table Manager configuration files which define tables. Since
|
19
|
+
# this class inherits from {PacketConfig} it only needs to implement Table
|
20
|
+
# Manager specific keywords. All tables are accessed through the table
|
21
|
+
# and tables methods.
|
22
|
+
class TableConfig < PacketConfig
|
23
|
+
# @return [String] Table configuration filename
|
24
|
+
attr_reader :filename
|
25
|
+
|
26
|
+
# Create the table configuration
|
21
27
|
def initialize
|
22
|
-
|
23
|
-
|
24
|
-
@
|
25
|
-
@current_table = nil
|
26
|
-
@current_parameter = nil
|
27
|
-
@cur_bit_offset = 0
|
28
|
-
@default_count = 0
|
29
|
-
@item_definitions = nil
|
30
|
-
@table_names = nil
|
28
|
+
super
|
29
|
+
# Override commands with the Table::TARGET name to store tables
|
30
|
+
@commands[Table::TARGET] = {}
|
31
31
|
end
|
32
32
|
|
33
|
-
#
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
converted_bit_size = nil
|
38
|
-
proc_text = ''
|
33
|
+
# @return [Array<Table>] All tables defined in the configuration file
|
34
|
+
def tables
|
35
|
+
@commands[Table::TARGET]
|
36
|
+
end
|
39
37
|
|
40
|
-
|
38
|
+
# @return [Array<String>] All the table names
|
39
|
+
def table_names
|
40
|
+
tables.keys
|
41
|
+
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
# @param table_name [String] Table name to return
|
44
|
+
# @return [Table]
|
45
|
+
def table(table_name)
|
46
|
+
tables[table_name.upcase]
|
47
|
+
end
|
48
|
+
|
49
|
+
# Processes a COSMOS table configuration file and uses the keywords to build up
|
50
|
+
# knowledge of the tables.
|
51
|
+
#
|
52
|
+
# @param filename [String] The name of the configuration file
|
53
|
+
def process_file(filename)
|
54
|
+
# Partial files are included into another file and thus aren't directly processed
|
55
|
+
return if File.basename(filename)[0] == '_' # Partials start with underscore
|
56
|
+
@filename = filename
|
57
|
+
@converted_type = nil
|
58
|
+
@converted_bit_size = nil
|
59
|
+
@proc_text = ''
|
60
|
+
@building_generic_conversion = false
|
46
61
|
|
47
|
-
parser = ConfigParser.new
|
48
|
-
parser.parse_file(filename) do |keyword,
|
49
|
-
|
50
|
-
if building_generic_conversion
|
62
|
+
parser = ConfigParser.new("http://cosmosrb.com/docs/tools/#table-manager-configuration")
|
63
|
+
parser.parse_file(filename) do |keyword, params|
|
64
|
+
if @building_generic_conversion
|
51
65
|
case keyword
|
52
66
|
# Complete a generic conversion
|
53
|
-
when 'GENERIC_READ_CONVERSION_END', 'GENERIC_WRITE_CONVERSION_END'
|
67
|
+
when 'GENERIC_READ_CONVERSION_END', 'GENERIC_WRITE_CONVERSION_END'
|
54
68
|
parser.verify_num_parameters(0, 0, keyword)
|
55
|
-
@
|
56
|
-
GenericConversion.new(proc_text,
|
57
|
-
converted_type,
|
58
|
-
converted_bit_size) if keyword.include? "READ"
|
59
|
-
@
|
60
|
-
GenericConversion.new(proc_text,
|
61
|
-
converted_type,
|
62
|
-
converted_bit_size) if keyword.include? "WRITE"
|
63
|
-
@
|
64
|
-
GenericConversion.new(proc_text,
|
65
|
-
converted_type,
|
66
|
-
converted_bit_size) if keyword.include? "CONSTRAINT"
|
67
|
-
building_generic_conversion = false
|
69
|
+
@current_item.read_conversion =
|
70
|
+
GenericConversion.new(@proc_text,
|
71
|
+
@converted_type,
|
72
|
+
@converted_bit_size) if keyword.include? "READ"
|
73
|
+
@current_item.write_conversion =
|
74
|
+
GenericConversion.new(@proc_text,
|
75
|
+
@converted_type,
|
76
|
+
@converted_bit_size) if keyword.include? "WRITE"
|
77
|
+
@building_generic_conversion = false
|
68
78
|
# Add the current config.line to the conversion being built
|
69
79
|
else
|
70
|
-
proc_text << parser.line << "\n"
|
80
|
+
@proc_text << parser.line << "\n"
|
71
81
|
end # case keyword
|
72
82
|
|
73
83
|
else # not building generic conversion
|
74
|
-
|
75
84
|
case keyword
|
76
|
-
# Start the definition of a generic conversion.
|
77
|
-
# All config.lines following this config.line are considered part
|
78
|
-
# of the conversion until an end of conversion marker is found
|
79
|
-
when 'GENERIC_READ_CONVERSION_START', 'GENERIC_WRITE_CONVERSION_START', 'CONSTRAINT_START'
|
80
|
-
usage = "#{keyword} <Converted Type (optional)> <Converted Bit Size (optional)>"
|
81
|
-
parser.verify_num_parameters(0, 2, usage)
|
82
|
-
proc_text = ''
|
83
|
-
building_generic_conversion = true
|
84
|
-
converted_type = nil
|
85
|
-
converted_bit_size = nil
|
86
|
-
if parameters[0]
|
87
|
-
converted_type = parameters[0].upcase.intern
|
88
|
-
raise parser.error("Invalid converted_type: #{converted_type}.") unless [:INT, :UINT, :FLOAT, :STRING, :BLOCK].include? converted_type
|
89
|
-
end
|
90
|
-
converted_bit_size = Integer(parameters[1]) if parameters[1]
|
91
|
-
|
92
85
|
when 'TABLEFILE'
|
93
|
-
|
94
|
-
|
86
|
+
usage = "#{keyword} <File name>"
|
87
|
+
parser.verify_num_parameters(1, 1, usage)
|
88
|
+
filename = File.join(File.dirname(filename), params[0])
|
89
|
+
raise parser.error("Table file #{filename} not found", usage) unless File.exist?(filename)
|
90
|
+
process_file(filename)
|
95
91
|
|
96
92
|
when 'TABLE'
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
begin
|
125
|
-
if @current_table.type == :TWO_DIMENSIONAL
|
126
|
-
parameters[0] = "#{parameters[0]}0"
|
127
|
-
end
|
128
|
-
# locals declared for readability
|
129
|
-
name = parameters[0]
|
130
|
-
if @current_table.items[name.upcase]
|
131
|
-
raise ArgumentError, "The name \"#{name}\" was already defined"
|
132
|
-
end
|
133
|
-
description = parameters[1]
|
134
|
-
type = read_item_type(parameters[2])
|
135
|
-
bit_size = parameters[3].to_i
|
136
|
-
display_type, editable = read_display_type(parameters[4], type)
|
137
|
-
if type == :STRING || type == :BLOCK
|
138
|
-
range = nil
|
139
|
-
else
|
140
|
-
range = convert_to_range(parameters[5], parameters[6], type, bit_size)
|
141
|
-
end
|
142
|
-
if @current_table.type == :ONE_DIMENSIONAL
|
143
|
-
if type == :STRING || type == :BLOCK
|
144
|
-
default = convert_to_type(parameters[5], type)
|
145
|
-
else
|
146
|
-
default = convert_to_type(parameters[7], type)
|
147
|
-
end
|
148
|
-
else # TWO_DIMENSIONAL defaults are set by the DEFAULT keyword
|
149
|
-
default = 0
|
150
|
-
end
|
151
|
-
|
152
|
-
endianness = parameters[-1].to_s.upcase.intern
|
153
|
-
if endianness != :BIG_ENDIAN && endianness != :LITTLE_ENDIAN
|
154
|
-
endianness = @current_table.default_endianness
|
155
|
-
end
|
156
|
-
|
157
|
-
@current_parameter = @current_table.create_param(
|
158
|
-
name, @cur_bit_offset, bit_size, type, description,
|
159
|
-
range, default, display_type, editable, endianness)
|
160
|
-
@cur_bit_offset += parameters[3].to_i
|
161
|
-
rescue ArgumentError => err
|
162
|
-
raise parser.error("#{err.message} with #{keyword}.\nUSAGE: #{usage}")
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
when 'STATE'
|
167
|
-
usage = "STATE <Key> <Value>"
|
168
|
-
parser.verify_num_parameters(2, 2, usage)
|
169
|
-
begin
|
170
|
-
# locals declared for readability
|
171
|
-
state_name = parameters[0]
|
172
|
-
state_value = convert_to_type(parameters[1], @current_parameter.data_type)
|
173
|
-
|
174
|
-
@current_parameter.states ||= {}
|
175
|
-
@current_parameter.states[state_name.upcase] = state_value
|
176
|
-
rescue ArgumentError => err
|
177
|
-
raise parser.error("#{err.message} with #{keyword}.\nUSAGE: #{usage}")
|
178
|
-
end
|
179
|
-
|
180
|
-
when 'DEFAULT'
|
181
|
-
usage = "DEFAULT <Value1> <Value2> ... <ValueN>"
|
182
|
-
# if this is our first default value for a TWO_DIMENSIONAL table
|
183
|
-
# then we redefine the default values
|
184
|
-
if @default_count == 0
|
185
|
-
@item_definitions = Array.new(@current_table.sorted_items)
|
186
|
-
index = 0
|
187
|
-
@item_definitions.each do |item_def|
|
188
|
-
set_item_default_value(item_def, parameters[index])
|
189
|
-
index += 1
|
190
|
-
end
|
191
|
-
|
192
|
-
@current_table.num_rows = 1
|
193
|
-
|
194
|
-
# more default values have been given so copy all the parameters from
|
195
|
-
# the first row and reset the defaults
|
196
|
-
else
|
197
|
-
index = 0
|
198
|
-
|
199
|
-
@item_definitions.each do |item_def|
|
200
|
-
new_item = @current_table.duplicate_item(item_def,
|
201
|
-
@default_count,
|
202
|
-
@cur_bit_offset)
|
203
|
-
@cur_bit_offset += item_def.bit_size
|
204
|
-
set_item_default_value(new_item, parameters[index])
|
205
|
-
index += 1
|
206
|
-
end
|
207
|
-
@current_table.num_rows += 1
|
208
|
-
end # end else for if @default_count == 1
|
209
|
-
|
210
|
-
@default_count += 1
|
211
|
-
|
212
|
-
when 'POLY_READ_CONVERSION'
|
213
|
-
parser.verify_num_parameters(2, nil, "#{keyword} <C0> ... <CX>")
|
214
|
-
@current_parameter.read_conversion = PolynomialConversion.new(parameters[0..-1])
|
215
|
-
|
216
|
-
when 'POLY_WRITE_CONVERSION'
|
217
|
-
parser.verify_num_parameters(2, nil, "#{keyword} <C0> ... <CX>")
|
218
|
-
@current_parameter.write_conversion = PolynomialConversion.new(parameters[0..-1])
|
219
|
-
|
220
|
-
else
|
221
|
-
unknown_keyword(parser, keyword, parameters)
|
222
|
-
end # end case parameters[0]
|
223
|
-
end # end else for generic conversion
|
224
|
-
end # end loop
|
225
|
-
|
226
|
-
# Handle last packet
|
227
|
-
finish_table()
|
228
|
-
|
229
|
-
ensure
|
230
|
-
file.close if defined? file and file
|
231
|
-
end
|
232
|
-
|
233
|
-
# Sets the given item definition's default parameter to the default value
|
234
|
-
# given. This function does conversions based on the display_type of the item.
|
235
|
-
def set_item_default_value(item_def, default = nil)
|
236
|
-
begin
|
237
|
-
# If no default was passed use the definition default
|
238
|
-
if default == nil
|
239
|
-
default = item_def.default
|
240
|
-
end
|
241
|
-
if item_def.display_type == :STATE
|
242
|
-
begin
|
243
|
-
val = item_def.states.key(Integer(default))
|
244
|
-
rescue
|
245
|
-
val = default
|
246
|
-
end
|
247
|
-
@current_table.write(item_def.name, val)
|
248
|
-
item_def.default = @current_table.read(item_def.name, :RAW)
|
249
|
-
else
|
250
|
-
item_def.default = convert_to_type(default, item_def.data_type)
|
251
|
-
end
|
252
|
-
rescue
|
253
|
-
Logger.error "Setting #{item_def.name} to #{default} failed! Using #{item_def.range.first} for the default value."
|
254
|
-
item_def.default = item_def.range.first
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
# Classes extending table_definition should override this function to add
|
259
|
-
# new keyword processing. Ensure super() is called after processing new
|
260
|
-
# keywords so the default behavior of raising an ArgumentError is maintained.
|
261
|
-
def unknown_keyword(parser, keyword, parameters)
|
262
|
-
raise parser.error("Unknown keyword '#{keyword}'.", nil) if keyword
|
263
|
-
end
|
264
|
-
|
265
|
-
# Returns a specific Table
|
266
|
-
def get_table(name)
|
267
|
-
@tables[name]
|
268
|
-
end
|
269
|
-
|
270
|
-
# Returns an array of all the Tables in the definition file
|
271
|
-
def get_all_tables
|
272
|
-
@ordered_tables
|
273
|
-
end
|
274
|
-
|
275
|
-
# Returns an array of all the table names in the definition file
|
276
|
-
def get_table_names
|
277
|
-
@table_names
|
278
|
-
end
|
93
|
+
finish_packet()
|
94
|
+
@current_packet = TableParser.parse_table(parser, @commands, @warnings)
|
95
|
+
@current_cmd_or_tlm = COMMAND
|
96
|
+
|
97
|
+
# Select an existing table for editing
|
98
|
+
when 'SELECT_TABLE'
|
99
|
+
usage = "#{keyword} <TABLE NAME>"
|
100
|
+
finish_packet()
|
101
|
+
parser.verify_num_parameters(1, 1, usage)
|
102
|
+
table_name = params[0].upcase
|
103
|
+
@current_packet = table(table_name)
|
104
|
+
raise parser.error("Table #{table_name} not found", usage) unless @current_packet
|
105
|
+
|
106
|
+
#######################################################################
|
107
|
+
# All the following keywords must have a current packet defined
|
108
|
+
#######################################################################
|
109
|
+
when 'SELECT_PARAMETER', 'PARAMETER', 'ID_PARAMETER', 'ARRAY_PARAMETER', 'APPEND_PARAMETER', 'APPEND_ID_PARAMETER', 'APPEND_ARRAY_PARAMETER', 'ALLOW_SHORT', 'HAZARDOUS', 'PROCESSOR', 'META', 'DISABLE_MESSAGES', 'DISABLED'
|
110
|
+
raise parser.error("No current packet for #{keyword}") unless @current_packet
|
111
|
+
process_current_packet(parser, keyword, params)
|
112
|
+
|
113
|
+
#######################################################################
|
114
|
+
# All the following keywords must have a current item defined
|
115
|
+
#######################################################################
|
116
|
+
when 'STATE', 'READ_CONVERSION', 'WRITE_CONVERSION', 'POLY_READ_CONVERSION', 'POLY_WRITE_CONVERSION', 'SEG_POLY_READ_CONVERSION', 'SEG_POLY_WRITE_CONVERSION', 'GENERIC_READ_CONVERSION_START', 'GENERIC_WRITE_CONVERSION_START', 'REQUIRED', 'LIMITS', 'LIMITS_RESPONSE', 'UNITS', 'FORMAT_STRING', 'DESCRIPTION', 'MINIMUM_VALUE', 'MAXIMUM_VALUE', 'DEFAULT_VALUE', 'OVERFLOW', 'UNEDITABLE', 'HIDDEN'
|
117
|
+
raise parser.error("No current item for #{keyword}") unless @current_item
|
118
|
+
process_current_item(parser, keyword, params)
|
279
119
|
|
280
|
-
# Returns a default-value representation of an item to be printed in a DEF file
|
281
|
-
def item_to_def_string(table, item_def)
|
282
|
-
result = ""
|
283
|
-
case item_def.display_type
|
284
|
-
when :STATE
|
285
|
-
if table.type == :ONE_DIMENSIONAL
|
286
|
-
result = table.read(item_def.name, :RAW).to_s
|
287
|
-
else
|
288
|
-
result = table.read(item_def.name).to_s
|
289
|
-
end
|
290
|
-
when :DEC, :STRING, :NONE
|
291
|
-
result = table.read(item_def.name).to_s
|
292
|
-
when :CHECK
|
293
|
-
result = table.read(item_def.name, :RAW).to_s
|
294
|
-
when :HEX
|
295
|
-
result = format_hex(table, item_def)
|
296
|
-
end
|
297
|
-
|
298
|
-
return result
|
299
|
-
end
|
300
|
-
|
301
|
-
# Update all default values in the definition file on disk with current values
|
302
|
-
def commit_default_values(table)
|
303
|
-
new_file_data = ""
|
304
|
-
table_found = false
|
305
|
-
default_count = 0
|
306
|
-
table_parameters = []
|
307
|
-
parser = ConfigParser.new
|
308
|
-
parser.parse_file(table.filename) do |keyword, parameters|
|
309
|
-
line = parser.line
|
310
|
-
|
311
|
-
case keyword
|
312
|
-
when 'TABLE'
|
313
|
-
name = parameters[0].remove_quotes
|
314
|
-
if name == table.name
|
315
|
-
table_found = true
|
316
120
|
else
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
when 'PARAMETER'
|
321
|
-
if table_found
|
322
|
-
name = parameters[0].remove_quotes
|
323
|
-
if table.type == :ONE_DIMENSIONAL
|
324
|
-
item = table.get_item(name)
|
325
|
-
|
326
|
-
# update the default value (in case the user tries to reset default values)
|
327
|
-
item.default = table.read(name, :RAW)
|
328
|
-
|
329
|
-
# determine what the new default value will look like as printed in the DEF file
|
330
|
-
new_default = item_to_def_string(table, item)
|
331
|
-
|
332
|
-
# scan to the beginning of the default value
|
333
|
-
line_index = line.index(keyword) # skip to start of keyword
|
334
|
-
line_index = line.index(parameters[0], line_index+keyword.length) # skip to start of first param
|
335
|
-
(1..7).each do |index|
|
336
|
-
line_index = line.index(parameters[index], line_index+parameters[index-1].length) # skip to start of next param
|
337
|
-
end
|
338
|
-
|
339
|
-
# rebuild the line in 3 parts:
|
340
|
-
# everything up to the old default value
|
341
|
-
# the new default value
|
342
|
-
# everything after the old default value
|
343
|
-
line = line[0...line_index] + new_default + line[(line_index+parameters[7].length)..-1]
|
344
|
-
else
|
345
|
-
table_parameters << name
|
346
|
-
end
|
347
|
-
end
|
348
|
-
|
349
|
-
when 'DEFAULT'
|
350
|
-
if table_found
|
351
|
-
line_index = line.index(keyword)
|
352
|
-
previous_word = keyword
|
353
|
-
table_parameters.each_with_index do |param_name, index|
|
354
|
-
item_name = "#{param_name}#{default_count}"
|
355
|
-
item = table.get_item(item_name)
|
356
|
-
|
357
|
-
# update the default value (in case the user tries to reset default values)
|
358
|
-
item.default = table.read(item_name, :RAW)
|
359
|
-
|
360
|
-
# determine what the new default value will look like as printed in the DEF file
|
361
|
-
new_default = item_to_def_string(table, item)
|
362
|
-
if new_default.index(" ")
|
363
|
-
new_default = '"' + new_default + '"'
|
364
|
-
end
|
365
|
-
|
366
|
-
# scan to the beginning of the default value
|
367
|
-
line_index = line.index(parameters[index], line_index+previous_word.length)
|
368
|
-
|
369
|
-
# rebuild the line in 3 parts:
|
370
|
-
# everything up to the old default value
|
371
|
-
# the new default value
|
372
|
-
# everything after the old default value
|
373
|
-
line = line[0...line_index] + new_default + line[(line_index+parameters[index].length)..-1]
|
374
|
-
|
375
|
-
# update previous_word so that we can find the next value
|
376
|
-
previous_word = new_default
|
377
|
-
end
|
378
|
-
|
379
|
-
# count the row so that we know what the item_name is next time we see DEFAULT
|
380
|
-
default_count += 1
|
381
|
-
end
|
382
|
-
end
|
383
|
-
|
384
|
-
new_file_data << (line + "\n")
|
385
|
-
|
386
|
-
end # end loop
|
387
|
-
|
388
|
-
# ok, now replace the old def file with the new one
|
389
|
-
File.open(table.filename, "w") do |file|
|
390
|
-
file.puts new_file_data
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
|
-
# # Return the entire table_definition file for the given table name as a string
|
395
|
-
# def print_table(name)
|
396
|
-
# tdef = @tables[name]
|
397
|
-
# tstr = ""
|
398
|
-
# if tdef.table_id.class != Array
|
399
|
-
# tstr << "TABLE \"#{tdef.name}\" \"#{tdef.description}\" #{convert_table_type(tdef.type)} #{convert_endianness(tdef.get_endianness)} #{tdef.table_id}\n"
|
400
|
-
# else
|
401
|
-
# tstr << "TABLE \"#{tdef.name}\" \"#{tdef.description}\" #{convert_table_type(tdef.type)} #{convert_endianness(tdef.get_endianness)} #{tdef.table_id.join(' ')}\n"
|
402
|
-
# end
|
403
|
-
# if tdef.type == :ONE_DIMENSIONAL
|
404
|
-
# tdef.sorted_items.each do |item|
|
405
|
-
# tstr << create_item_string(item, tdef.type)
|
406
|
-
# end
|
407
|
-
# else # TWO_DIMENSIONAL
|
408
|
-
# tdef.num_columns.times do |column|
|
409
|
-
# item_def = tdef.sorted_items[column]
|
410
|
-
# tstr << create_item_string(item_def, tdef.type)
|
411
|
-
# end
|
412
|
-
#
|
413
|
-
# index = 0
|
414
|
-
# tdef.sorted_items.each do |item|
|
415
|
-
# if index % tdef.num_columns == 0
|
416
|
-
# tstr << "\n DEFAULT "
|
417
|
-
# end
|
418
|
-
# case item.display_type
|
419
|
-
# when :DEC
|
420
|
-
# default = item.default
|
421
|
-
# when :STATE
|
422
|
-
# default = "\"#{item.default}\""
|
423
|
-
# when :HEX
|
424
|
-
# default = "0x#{item.default.to_s(16)}"
|
425
|
-
# end
|
426
|
-
# tstr << "#{default} "
|
427
|
-
# index += 1
|
428
|
-
# end
|
429
|
-
# end # end else # TWO_DIMENSIONAL
|
430
|
-
# tstr
|
431
|
-
# end # end print_table(name)
|
432
|
-
|
433
|
-
def format_hex(table, item_def)
|
434
|
-
case item_def.bit_size
|
435
|
-
when 8
|
436
|
-
x = sprintf("%02X", table.read(item_def.name).to_s)
|
437
|
-
# if the number was negative x will have .. and possibly another
|
438
|
-
# F in the string which we remove by taking the last 4 digits
|
439
|
-
x = /\w{2}$/.match(x)[0]
|
440
|
-
when 16
|
441
|
-
x = sprintf("%04X", table.read(item_def.name).to_s)
|
442
|
-
# if the number was negative x will have .. and possibly another
|
443
|
-
# F in the string which we remove by taking the last 4 digits
|
444
|
-
x = /\w{4}$/.match(x)[0]
|
445
|
-
else
|
446
|
-
x = sprintf("%08X", table.read(item_def.name).to_s)
|
447
|
-
# if the number was negative x will have .. and possibly another
|
448
|
-
# F in the string which we remove by taking the last 8 digits
|
449
|
-
x = /\w{8}$/.match(x)[0]
|
450
|
-
end
|
451
|
-
return "0x%X" % Integer("0x#{x}") # convert to Integer
|
452
|
-
end
|
453
|
-
|
454
|
-
#############################################################################
|
455
|
-
protected
|
456
|
-
#############################################################################
|
457
|
-
|
458
|
-
# # helper function to print_table to get states, constraint, read_conversion,
|
459
|
-
# # and write_conversion that may be associated with an item in the table
|
460
|
-
# def create_item_string(item, type)
|
461
|
-
# tstr = ""
|
462
|
-
# case item.display_type
|
463
|
-
# when :DEC
|
464
|
-
# min = item.range.first
|
465
|
-
# max = item.range.last
|
466
|
-
# default = item.default
|
467
|
-
# when :STATE
|
468
|
-
# min = item.range.first
|
469
|
-
# max = item.range.last
|
470
|
-
# default = item.states[item.default]
|
471
|
-
# when :HEX
|
472
|
-
# min = "0x#{item.range.first.to_s(16)}"
|
473
|
-
# max = "0x#{item.range.last.to_s(16)}"
|
474
|
-
# default = "0x#{item.default.to_s(16)}"
|
475
|
-
# end
|
476
|
-
#
|
477
|
-
# name = item.name
|
478
|
-
# display = convert_display_type(item.display_type, item.editable)
|
479
|
-
# tstr << " PARAMETER \"#{name}\" \"#{item.description}\" #{convert_item_type(item.data_type)} #{item.bit_size} #{display} #{min} #{max}"
|
480
|
-
# if type == :ONE_DIMENSIONAL
|
481
|
-
# tstr << " #{default}\n"
|
482
|
-
# else # TWO_DIMENSIONAL
|
483
|
-
# tstr << "\n"
|
484
|
-
# end
|
485
|
-
#
|
486
|
-
# if item.states
|
487
|
-
# item.states.each do |key, value|
|
488
|
-
# tstr << " STATE \"#{key}\" #{value}\n"
|
489
|
-
# end
|
490
|
-
# end
|
491
|
-
# if item.constraint
|
492
|
-
# tstr << " CONSTRAINT_START\n"
|
493
|
-
# tstr << item.constraint.code
|
494
|
-
# tstr << " CONSTRAINT_END\n"
|
495
|
-
# end
|
496
|
-
# if item.read_conversion
|
497
|
-
# if item.read_conversion.class == PolynomialConversion
|
498
|
-
# tstr << " POLY_READ_CONVERSION #{item.read_conversion.code}\n"
|
499
|
-
# else
|
500
|
-
# tstr << " GENERIC_READ_CONVERSION_START\n"
|
501
|
-
# tstr << item.read_conversion.code
|
502
|
-
# tstr << " GENERIC_READ_CONVERSION_END\n"
|
503
|
-
# end
|
504
|
-
# end
|
505
|
-
# if not item.write_conversion.nil?
|
506
|
-
# if item.write_conversion.class == PolynomialConversion
|
507
|
-
# tstr << " POLY_WRITE_CONVERSION #{item.write_conversion.code}\n"
|
508
|
-
# else
|
509
|
-
# tstr << " GENERIC_WRITE_CONVERSION_START\n"
|
510
|
-
# tstr << item.write_conversion.code
|
511
|
-
# tstr << " GENERIC_WRITE_CONVERSION_END\n"
|
512
|
-
# end
|
513
|
-
# end
|
514
|
-
# tstr
|
515
|
-
# end
|
516
|
-
|
517
|
-
# Finish Updating parameter in packet
|
518
|
-
def finish_parameter
|
519
|
-
unless @current_parameter.nil?
|
520
|
-
@current_table.set_item(@current_parameter)
|
521
|
-
end
|
522
|
-
end
|
523
|
-
|
524
|
-
# Start processing a new packet
|
525
|
-
def start_new_table(name, description, type, endianness, table_id, filename)
|
526
|
-
finish_table
|
527
|
-
@current_table = Table.new(name, description, type, endianness, table_id, filename)
|
528
|
-
@current_name = name
|
529
|
-
@default_count = 0
|
530
|
-
end
|
531
|
-
|
532
|
-
# Add current packet into hash if it exists
|
533
|
-
def finish_table
|
534
|
-
finish_parameter
|
535
|
-
if @current_table
|
536
|
-
Logger.info "finish_table #{@current_name}"
|
537
|
-
if @current_table.num_rows
|
538
|
-
if @tables.nil? or @table_names.nil? or @ordered_tables.nil?
|
539
|
-
@tables = {}
|
540
|
-
@table_names = []
|
541
|
-
@ordered_tables = []
|
542
|
-
end
|
543
|
-
@tables[@current_name] = @current_table
|
544
|
-
@table_names << @current_name
|
545
|
-
@ordered_tables << @current_table
|
121
|
+
# blank config.lines will have a nil keyword and should not raise an exception
|
122
|
+
raise parser.error("Unknown keyword '#{keyword}'") if keyword
|
123
|
+
end # case keyword
|
546
124
|
end
|
547
|
-
@current_table = nil
|
548
|
-
@current_parameter = nil
|
549
|
-
@cur_bit_offset = 0
|
550
|
-
end
|
551
|
-
end
|
552
|
-
|
553
|
-
# Convert the table type string to a value
|
554
|
-
def read_table_type(str)
|
555
|
-
str.upcase!
|
556
|
-
case str
|
557
|
-
when 'ONE_DIMENSIONAL'
|
558
|
-
:ONE_DIMENSIONAL
|
559
|
-
when 'TWO_DIMENSIONAL'
|
560
|
-
:TWO_DIMENSIONAL
|
561
|
-
else
|
562
|
-
raise ArgumentError, "Unknown table type:#{str}! Must be ONE_DIMENSIONAL or TWO_DIMENSIONAL"
|
563
|
-
end
|
564
|
-
end
|
565
|
-
|
566
|
-
# Convert the table type value to a string
|
567
|
-
def convert_table_type(type)
|
568
|
-
case type
|
569
|
-
when :ONE_DIMENSIONAL
|
570
|
-
'ONE_DIMENSIONAL'
|
571
|
-
when :TWO_DIMENSIONAL
|
572
|
-
'TWO_DIMENSIONAL'
|
573
|
-
else
|
574
|
-
raise ArgumentError, "Unknown table type:#{type}!"
|
575
125
|
end
|
576
|
-
end
|
577
126
|
|
578
|
-
|
579
|
-
|
580
|
-
str.upcase!
|
581
|
-
case str
|
582
|
-
when 'BIG_ENDIAN'
|
583
|
-
:BIG_ENDIAN
|
584
|
-
when 'LITTLE_ENDIAN'
|
585
|
-
:LITTLE_ENDIAN
|
586
|
-
else
|
587
|
-
raise ArgumentError, "Unknown endianness:#{str}! Must be BIG_ENDIAN or LITTLE_ENDIAN"
|
588
|
-
end
|
127
|
+
# Complete the last defined packet
|
128
|
+
finish_packet()
|
589
129
|
end
|
590
130
|
|
591
|
-
#
|
592
|
-
def
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
'LITTLE_ENDIAN'
|
131
|
+
# (see PacketConfig#process_current_packet)
|
132
|
+
def process_current_packet(parser, keyword, params)
|
133
|
+
super(parser, keyword, params)
|
134
|
+
rescue => err
|
135
|
+
if err.message.include?("not found")
|
136
|
+
raise parser.error("#{params[0]} not found in table #{@current_packet.table_name}", "SELECT_PARAMETER <PARAMETER NAME>")
|
598
137
|
else
|
599
|
-
raise
|
600
|
-
end
|
601
|
-
end
|
602
|
-
|
603
|
-
#
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
when '
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
when '
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
end
|
639
|
-
|
640
|
-
# Convert a string to the correct item type
|
641
|
-
def convert_to_type(val, type)
|
642
|
-
raise ArgumentError, "Value is not defined" if val.nil?
|
643
|
-
begin
|
644
|
-
case type
|
645
|
-
when :INT, :UINT
|
646
|
-
val = Integer(val)
|
647
|
-
when :FLOAT
|
648
|
-
val = Float(val)
|
649
|
-
when :STRING, :BLOCK
|
650
|
-
val = val.to_s
|
651
|
-
end
|
652
|
-
rescue
|
653
|
-
begin
|
654
|
-
val = eval(val)
|
655
|
-
rescue
|
656
|
-
case type
|
657
|
-
when :INT
|
658
|
-
type_name = 'INT'
|
659
|
-
when :UINT
|
660
|
-
type_name = 'UINT'
|
661
|
-
when :FLOAT
|
662
|
-
type_name = 'FLOAT'
|
138
|
+
raise err
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Overridden method to handle the unique table item parameters: UNEDITABLE
|
143
|
+
# and HIDDEN.
|
144
|
+
# (see PacketConfig#process_current_item)
|
145
|
+
def process_current_item(parser, keyword, params)
|
146
|
+
super(parser, keyword, params)
|
147
|
+
case keyword
|
148
|
+
when 'UNEDITABLE'
|
149
|
+
usage = "#{keyword}"
|
150
|
+
parser.verify_num_parameters(0, 0, usage)
|
151
|
+
@current_item.editable = false
|
152
|
+
when 'HIDDEN'
|
153
|
+
usage = "#{keyword}"
|
154
|
+
parser.verify_num_parameters(0, 0, usage)
|
155
|
+
@current_item.hidden = true
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# (see PacketConfig#start_item)
|
160
|
+
def start_item(parser)
|
161
|
+
finish_item()
|
162
|
+
@current_item = TableItemParser.parse(parser, @current_packet)
|
163
|
+
end
|
164
|
+
|
165
|
+
# If the table is TWO_DIMENSIONAL all currently defined items are
|
166
|
+
# duplicated until the specified number of rows are created.
|
167
|
+
def finish_packet
|
168
|
+
if @current_packet
|
169
|
+
if @current_packet.type == :TWO_DIMENSIONAL
|
170
|
+
items = @current_packet.sorted_items.clone
|
171
|
+
(@current_packet.num_rows - 1).times do |row|
|
172
|
+
items.each do |item|
|
173
|
+
new_item = item.clone
|
174
|
+
new_item.name = "#{new_item.name[0...-1]}#{row + 1}"
|
175
|
+
@current_packet.append(new_item)
|
176
|
+
end
|
663
177
|
end
|
664
|
-
raise ArgumentError, "Error evaluating value:#{val} of type:#{type_name}"
|
665
178
|
end
|
666
179
|
end
|
667
|
-
|
668
|
-
end
|
669
|
-
|
670
|
-
# Convert the given minimum and maximum values of the given type and bit_size
|
671
|
-
# into a valid Ruby range: min..max. The function verifies the range is not
|
672
|
-
# backwards and that the minimum and maximum values make sense for the given
|
673
|
-
# type and bit_size. For example, a maximum of 256 doesn't make sense for a UINT8.
|
674
|
-
def convert_to_range(min, max, type, bit_size)
|
675
|
-
min = ConfigParser.handle_defined_constants(min.convert_to_value, type, bit_size)
|
676
|
-
max = ConfigParser.handle_defined_constants(max.convert_to_value, type, bit_size)
|
677
|
-
range = min..max
|
678
|
-
|
679
|
-
# First check for backwards ranges
|
680
|
-
if min > max
|
681
|
-
raise ArgumentError, "Min:#{min} can't be larger than max:#{max} in range"
|
682
|
-
end
|
683
|
-
|
684
|
-
case type
|
685
|
-
# No case for FLOAT because if the type is a float the range
|
686
|
-
# can be anything since you can't set a range wider than that allowed by a float
|
687
|
-
when :UINT
|
688
|
-
# First check for a negative range which doesn't make sense for UINT
|
689
|
-
if min < 0 or max < 0
|
690
|
-
raise ArgumentError, "Negative value in UINT range doesn't make sense"
|
691
|
-
end
|
692
|
-
if (bit_size == 8 and max > 255) or
|
693
|
-
(bit_size == 16 and max > 65535) or
|
694
|
-
(bit_size == 32 and max > 4294967295)
|
695
|
-
raise ArgumentError, "Max value of #{max} in UINT range doesn't make sense"
|
696
|
-
end
|
697
|
-
when :INT
|
698
|
-
if (bit_size == 8 and (min < -128 or max > 127)) or
|
699
|
-
(bit_size == 16 and (min < -32768 or max > 32767)) or
|
700
|
-
(bit_size == 32 and (min < -2147483648 or max > 2147483647))
|
701
|
-
raise ArgumentError, "Max value of #{max} in INT range doesn't make sense"
|
702
|
-
end
|
703
|
-
end
|
704
|
-
range
|
180
|
+
super()
|
705
181
|
end
|
706
|
-
|
707
|
-
|
708
|
-
def read_display_type(display_type, value_type)
|
709
|
-
editable = true
|
710
|
-
display_type.upcase!
|
711
|
-
|
712
|
-
if /-U/ =~ display_type
|
713
|
-
editable = false
|
714
|
-
display_type.sub!(/-U/,"")
|
715
|
-
end
|
716
|
-
|
717
|
-
case display_type
|
718
|
-
when 'DEC'
|
719
|
-
display_type = :DEC
|
720
|
-
when 'HEX'
|
721
|
-
display_type = :HEX
|
722
|
-
when 'STATE'
|
723
|
-
display_type = :STATE
|
724
|
-
when 'CHECK'
|
725
|
-
display_type = :CHECK
|
726
|
-
when 'STRING'
|
727
|
-
display_type = :STRING
|
728
|
-
when 'NONE'
|
729
|
-
display_type = :NONE
|
730
|
-
editable = false
|
731
|
-
else
|
732
|
-
raise ArgumentError, "Unknown display type:#{display_type}! Must be DEC, DEC-U, HEX, HEX-U, STATE, STATE-U, CHECK, CHECK-U, STRING or NONE"
|
733
|
-
end
|
734
|
-
|
735
|
-
if value_type ==:STRING && display_type != :STRING
|
736
|
-
raise ArgumentError, "STRING items must have a display type of STRING"
|
737
|
-
end
|
738
|
-
if value_type == :BLOCK && display_type != :NONE
|
739
|
-
raise ArgumentError, "BLOCK items must have a display type of NONE"
|
740
|
-
end
|
741
|
-
|
742
|
-
return display_type, editable
|
743
|
-
end
|
744
|
-
|
745
|
-
# Convert display type value to a display type string
|
746
|
-
def convert_display_type(type, editable)
|
747
|
-
display =
|
748
|
-
case type
|
749
|
-
when :DEC
|
750
|
-
'DEC'
|
751
|
-
when :HEX
|
752
|
-
'HEX'
|
753
|
-
when :STATE
|
754
|
-
'STATE'
|
755
|
-
when :CHECK
|
756
|
-
'CHECK'
|
757
|
-
when :STRING
|
758
|
-
'STRING'
|
759
|
-
when :NONE
|
760
|
-
'NONE'
|
761
|
-
else
|
762
|
-
raise ArgumentError, "Unkown display type:#{type}!"
|
763
|
-
end
|
764
|
-
if not editable
|
765
|
-
display << "-U"
|
766
|
-
end
|
767
|
-
display
|
768
|
-
end
|
769
|
-
|
770
|
-
end # class TableConfig
|
771
|
-
|
772
|
-
end # module Cosmos
|
182
|
+
end
|
183
|
+
end
|