cosmos 3.8.3 → 3.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -3
  3. data/Manifest.txt +14 -0
  4. data/Rakefile +35 -2
  5. data/autohotkey/config/targets/INST/screens/_footer.txt +4 -0
  6. data/autohotkey/config/targets/INST/screens/hs.txt +1 -4
  7. data/autohotkey/config/tools/table_manager/OldOneDimensionalTable_def.txt +19 -0
  8. data/autohotkey/config/tools/table_manager/OldTwoDimensionalTable_def.txt +248 -0
  9. data/autohotkey/config/tools/table_manager/OneDimensionalTable_def.txt +27 -15
  10. data/autohotkey/config/tools/table_manager/TwoDimensionalTable_def.txt +12 -232
  11. data/autohotkey/procedures/example_test.rb +4 -0
  12. data/autohotkey/tools/TableManagerAHK +4 -9
  13. data/autohotkey/tools/TableManagerAHK2 +18 -0
  14. data/autohotkey/tools/TableManagerAHK3 +18 -0
  15. data/autohotkey/tools/TableManagerAHK4 +24 -0
  16. data/autohotkey/tools/TlmViewerAHK +1 -1
  17. data/autohotkey/tools/autohotkey.rb +2 -1
  18. data/autohotkey/tools/open_gl_builder.ahk +1 -1
  19. data/autohotkey/tools/table_manager.ahk +141 -70
  20. data/cosmos.gemspec +3 -3
  21. data/data/crc.txt +70 -68
  22. data/data/legal.txt +4 -5
  23. data/demo/config/data/crc.txt +10 -9
  24. data/demo/config/targets/INST/screens/_footer.txt +4 -0
  25. data/demo/config/targets/INST/screens/hs.txt +1 -6
  26. data/demo/config/targets/INST/screens/limits.txt +3 -11
  27. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +1 -0
  28. data/demo/config/tools/table_manager/MCConfigurationTable_fsw1_def.txt +33 -22
  29. data/demo/config/tools/table_manager/MCConfigurationTable_fsw2_def.txt +30 -22
  30. data/demo/config/tools/table_manager/PPSSelectionTable_def.txt +8 -7
  31. data/demo/config/tools/table_manager/TLMMonitoringTable_def.txt +13 -13
  32. data/demo/lib/example_background_task.rb +6 -12
  33. data/demo/procedures/example_test.rb +5 -0
  34. data/lib/cosmos/conversions/conversion.rb +3 -7
  35. data/lib/cosmos/core_ext/class.rb +3 -1
  36. data/lib/cosmos/core_ext/file.rb +1 -0
  37. data/lib/cosmos/core_ext/io.rb +18 -0
  38. data/lib/cosmos/core_ext/range.rb +1 -5
  39. data/lib/cosmos/core_ext/time.rb +3 -3
  40. data/lib/cosmos/gui/dialogs/about_dialog.rb +60 -36
  41. data/lib/cosmos/gui/dialogs/calendar_dialog.rb +10 -14
  42. data/lib/cosmos/gui/dialogs/cmd_details_dialog.rb +4 -5
  43. data/lib/cosmos/gui/dialogs/cmd_tlm_raw_dialog.rb +31 -17
  44. data/lib/cosmos/gui/dialogs/details_dialog.rb +63 -47
  45. data/lib/cosmos/gui/dialogs/exception_dialog.rb +77 -68
  46. data/lib/cosmos/gui/dialogs/exception_list_dialog.rb +6 -5
  47. data/lib/cosmos/gui/dialogs/legal_dialog.rb +34 -21
  48. data/lib/cosmos/gui/dialogs/packet_log_dialog.rb +19 -43
  49. data/lib/cosmos/gui/dialogs/progress_dialog.rb +79 -42
  50. data/lib/cosmos/gui/dialogs/pry_dialog.rb +9 -5
  51. data/lib/cosmos/gui/dialogs/scroll_text_dialog.rb +6 -4
  52. data/lib/cosmos/gui/dialogs/select_dialog.rb +23 -18
  53. data/lib/cosmos/gui/dialogs/set_tlm_dialog.rb +34 -10
  54. data/lib/cosmos/gui/dialogs/splash.rb +18 -8
  55. data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +38 -43
  56. data/lib/cosmos/gui/dialogs/tlm_edit_dialog.rb +51 -53
  57. data/lib/cosmos/gui/line_graph/line_graph_scaling.rb +1 -1
  58. data/lib/cosmos/gui/line_graph/lines.rb +1 -1
  59. data/lib/cosmos/gui/qt.rb +9 -2
  60. data/lib/cosmos/gui/qt_tool.rb +50 -8
  61. data/lib/cosmos/gui/widgets/packet_log_frame.rb +53 -27
  62. data/lib/cosmos/interfaces/linc_interface.rb +103 -62
  63. data/lib/cosmos/io/json_drb_object.rb +3 -3
  64. data/lib/cosmos/io/raw_logger.rb +4 -8
  65. data/lib/cosmos/io/tcpip_server.rb +2 -2
  66. data/lib/cosmos/packets/binary_accessor.rb +1 -1
  67. data/lib/cosmos/packets/limits.rb +2 -5
  68. data/lib/cosmos/packets/packet.rb +1 -1
  69. data/lib/cosmos/packets/packet_config.rb +54 -19
  70. data/lib/cosmos/packets/parsers/packet_item_parser.rb +7 -1
  71. data/lib/cosmos/script/scripting.rb +4 -5
  72. data/lib/cosmos/system/system.rb +2 -1
  73. data/lib/cosmos/system/target.rb +4 -0
  74. data/lib/cosmos/tools/cmd_tlm_server/background_task.rb +13 -5
  75. data/lib/cosmos/tools/cmd_tlm_server/background_tasks.rb +37 -27
  76. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +6 -2
  77. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +7 -5
  78. data/lib/cosmos/tools/cmd_tlm_server/gui/status_tab.rb +21 -10
  79. data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +11 -11
  80. data/lib/cosmos/tools/script_runner/script_runner.rb +2 -18
  81. data/lib/cosmos/tools/script_runner/script_runner_frame.rb +6 -6
  82. data/lib/cosmos/tools/table_manager/table.rb +32 -41
  83. data/lib/cosmos/tools/table_manager/table_config.rb +140 -729
  84. data/lib/cosmos/tools/table_manager/table_item.rb +20 -36
  85. data/lib/cosmos/tools/table_manager/table_item_parser.rb +46 -0
  86. data/lib/cosmos/tools/table_manager/table_manager.rb +754 -691
  87. data/lib/cosmos/tools/table_manager/table_manager_core.rb +172 -358
  88. data/lib/cosmos/tools/table_manager/table_parser.rb +75 -0
  89. data/lib/cosmos/tools/test_runner/results_writer.rb +1 -1
  90. data/lib/cosmos/tools/test_runner/test_runner.rb +11 -0
  91. data/lib/cosmos/tools/tlm_grapher/data_object_adders/housekeeping_data_object_adder.rb +2 -2
  92. data/lib/cosmos/tools/tlm_grapher/data_object_adders/singlexy_data_object_adder.rb +2 -2
  93. data/lib/cosmos/tools/tlm_grapher/data_object_adders/xy_data_object_adder.rb +2 -2
  94. data/lib/cosmos/tools/tlm_grapher/data_objects/data_object.rb +4 -4
  95. data/lib/cosmos/tools/tlm_grapher/data_objects/housekeeping_data_object.rb +13 -13
  96. data/lib/cosmos/tools/tlm_grapher/data_objects/linegraph_data_object.rb +9 -9
  97. data/lib/cosmos/tools/tlm_grapher/data_objects/xy_data_object.rb +9 -9
  98. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_config.rb +4 -4
  99. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tool.rb +1 -1
  100. data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +8 -18
  101. data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +7 -4
  102. data/lib/cosmos/top_level.rb +12 -0
  103. data/lib/cosmos/version.rb +5 -5
  104. data/run_gui_tests.bat +6 -0
  105. data/spec/core_ext/array_spec.rb +1 -1
  106. data/spec/interfaces/linc_interface_spec.rb +4 -4
  107. data/spec/io/json_drb_spec.rb +2 -2
  108. data/spec/io/json_rpc_spec.rb +1 -1
  109. data/spec/io/raw_logger_spec.rb +5 -1
  110. data/spec/packet_logs/packet_log_writer_spec.rb +1 -1
  111. data/spec/packets/packet_config_spec.rb +144 -0
  112. data/spec/packets/parsers/packet_item_parser_spec.rb +60 -0
  113. data/spec/spec_helper.rb +11 -0
  114. data/spec/system/target_spec.rb +5 -1
  115. data/spec/tools/cmd_tlm_server/background_task_spec.rb +15 -3
  116. data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +117 -31
  117. data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +4 -0
  118. data/spec/tools/launcher/launcher_config_spec.rb +1 -1
  119. data/spec/tools/table_manager/table_config_spec.rb +226 -0
  120. data/spec/tools/table_manager/table_item_spec.rb +57 -0
  121. data/spec/tools/table_manager/table_parser_spec.rb +96 -0
  122. data/spec/tools/table_manager/table_spec.rb +90 -0
  123. data/spec/tools/table_manager/tablemanager_core_spec.rb +557 -0
  124. data/spec/top_level/top_level_spec.rb +9 -0
  125. data/spec/utilities/csv_spec.rb +3 -3
  126. 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(3)
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
- background_task_name = background_task.name
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(500, 30))
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 # module Cosmos
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 config_file [String] Configuration file base name which will be
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 config_file [String] Configuration file to save.
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 out of limit item with a values
717
+ # Update a widget with new values
718
718
  #
719
- # @param target_name [String] Target name of out of limits item.
720
- # @param packet_name [String] Packet name of out of limits item.
721
- # @param item_name [String] Item name of out of limits item or nil
722
- # if its a stale packet
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'].each do |path|
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.tab(index).toggle_debug(@debug)
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.tab(@tab_book.currentIndex)
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.tab(index).enable_breakpoints = true
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.tab(index).enable_breakpoints = false
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.tab(@tab_book.currentIndex)
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.tab(tab_index)
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.tab(@tab_book.currentIndex)
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
- attr_accessor :num_rows
20
- attr_accessor :num_columns
21
- attr_reader :name
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
- attr_reader :table_id
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, description, type, endianness, table_id, filename)
28
- super('TABLE', name, endianness, description, '', TableItem)
29
- @name = name
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 = 1 if @type == :ONE_DIMENSIONAL
38
+ @num_columns = (@type == :ONE_DIMENSIONAL) ? 1 : 0
36
39
  end
37
40
 
38
- # Calls define_item in Packet but also incrememts @num_columns
39
- # if this table is a REPEATING table.
40
- def create_param(name, bit_offset, bit_size, type, description, range, default, display_type, editable, endianness)
41
- @num_columns += 1 if @type == :TWO_DIMENSIONAL
42
- item = define_item(name, bit_offset, bit_size, type, nil, endianness)
43
- item.description = description
44
- item.range = range
45
- item.default = default
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
- # Calls define_packet_item in GenericPacket to duplicate the passed in packet
52
- # item. name_extension is concatenated with the orignal item name to make it
53
- # unique.
54
- def duplicate_item(item, name_extension, bit_offset)
55
- new_item = define_item("#{item.name[0...-1]}#{name_extension}",
56
- bit_offset, item.bit_size, item.data_type, item.array_size,
57
- item.endianness, item.overflow,
58
- item.format_string, item.read_conversion,
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 # class Table
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
- # TableConfig provides capabilities to read an ascii file that defines the
17
- # table parameters in a system and create a set of Tables for each.
18
- class TableConfig
19
-
20
- # Constructor for a TableConfig
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
- @ordered_tables = nil
23
- @tables = nil
24
- @current_name = nil
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
- # Processes a file and adds in the tables defined in the file
34
- def process(filename)
35
- building_generic_conversion = false
36
- converted_type = nil
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
- Logger.info "Processing table config in file '#{filename}'"
38
+ # @return [Array<String>] All the table names
39
+ def table_names
40
+ tables.keys
41
+ end
41
42
 
42
- unless test ?f, filename
43
- Logger.error "File does not exist"
44
- raise "ERROR! Table config file #{filename} does not exist!"
45
- end
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, parameters|
49
- next unless keyword
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', 'CONSTRAINT_END'
67
+ when 'GENERIC_READ_CONVERSION_END', 'GENERIC_WRITE_CONVERSION_END'
54
68
  parser.verify_num_parameters(0, 0, keyword)
55
- @current_parameter.read_conversion =
56
- GenericConversion.new(proc_text,
57
- converted_type,
58
- converted_bit_size) if keyword.include? "READ"
59
- @current_parameter.write_conversion =
60
- GenericConversion.new(proc_text,
61
- converted_type,
62
- converted_bit_size) if keyword.include? "WRITE"
63
- @current_parameter.constraint =
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
- parser.verify_num_parameters(1, 1, "#{keyword} <File name>")
94
- process(File.join(File.dirname(filename), parameters[0]))
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
- usage = "TABLE <Table Name> <Table Description> <ONE_DIMENSIONAL or TWO_DIMENSIONAL> <BIG_ENDIAN or LITTLE_ENDIAN> <Identifier>"
98
- parser.verify_num_parameters(5, nil, usage)
99
- begin
100
- # locals declared for readability
101
- name = parameters[0]
102
- description = parameters[1]
103
- type = read_table_type(parameters[2])
104
- endianness = read_endianness(parameters[3])
105
- if parameters[5].nil?
106
- table_id = Integer(parameters[4])
107
- else
108
- table_id = []
109
- parameters[4..-1].each {|parameter| table_id << Integer(parameter)}
110
- end
111
-
112
- start_new_table(name, description, type, endianness, table_id, filename)
113
- rescue ArgumentError => err
114
- raise parser.error("#{err.message} with #{keyword}.\nUSAGE: #{usage}")
115
- end
116
-
117
- when 'PARAMETER'
118
- usage = "PARAMETER <Parameter Name> <Parameter Description> <Data Type> <Bit Size> <Display Type> <Minimum Value> <Maximum Value> <Default Value (Only in ONE_DIMENTIONAL)> <ENDIANNESS (Optional)>"
119
- parser.verify_num_parameters(6, 9, usage)
120
- finish_parameter()
121
- if @current_table
122
- @current_table.num_rows += 1
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
- table_found = false
318
- end
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
- # Convert the endianness string to a value
579
- def read_endianness(str)
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
- # Convert the endianness value to a string
592
- def convert_endianness(endianness)
593
- case endianness
594
- when :BIG_ENDIAN
595
- 'BIG_ENDIAN'
596
- when :LITTLE_ENDIAN
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 ArgumentError, "Unknown endianness:#{endianness}!"
600
- end
601
- end
602
-
603
- # Process a item type string into a value
604
- def read_item_type(str)
605
- str.upcase!
606
- case str
607
- when 'INT'
608
- :INT
609
- when 'UINT'
610
- :UINT
611
- when 'FLOAT'
612
- :FLOAT
613
- when 'STRING'
614
- :STRING
615
- when 'BLOCK'
616
- :BLOCK
617
- else
618
- raise ArgumentError, "Unknown type:#{str}! Must be INT, UINT, FLOAT, STRING, or BLOCK"
619
- end
620
- end
621
-
622
- # Process a item type value into a string
623
- def convert_item_type(type)
624
- case type
625
- when :INT
626
- 'INT'
627
- when :UINT
628
- 'UINT'
629
- when :FLOAT
630
- 'FLOAT'
631
- when :STRING
632
- 'STRING'
633
- when :BLOCK
634
- 'BLOCK'
635
- else
636
- raise ArgumentError, "Unknown type:#{type}!"
637
- end
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
- val
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
- # Convert a display type string to the type value
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