cosmos 3.8.0 → 3.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/autohotkey/tools/packet_viewer.ahk +4 -0
  3. data/cosmos.gemspec +1 -1
  4. data/data/crc.txt +277 -277
  5. data/demo/Gemfile +2 -2
  6. data/demo/config/data/crc.txt +176 -176
  7. data/demo/config/targets/INST/cmd_tlm/_ccsds_cmd.txt +2 -2
  8. data/demo/config/targets/INST/cmd_tlm/inst_cmds.txt +4 -4
  9. data/demo/procedures/example_test.rb +4 -0
  10. data/install/Gemfile +1 -1
  11. data/install/config/data/crc.txt +112 -112
  12. data/lib/cosmos/config/config_parser.rb +35 -1
  13. data/lib/cosmos/core_ext/string.rb +21 -17
  14. data/lib/cosmos/core_ext/time.rb +6 -2
  15. data/lib/cosmos/gui/opengl/gl_viewer.rb +4 -4
  16. data/lib/cosmos/gui/opengl/stl_shape.rb +5 -1
  17. data/lib/cosmos/gui/qt.rb +0 -26
  18. data/lib/cosmos/io/io_multiplexer.rb +27 -45
  19. data/lib/cosmos/packets/packet.rb +64 -24
  20. data/lib/cosmos/packets/packet_config.rb +254 -54
  21. data/lib/cosmos/packets/packet_item.rb +39 -10
  22. data/lib/cosmos/packets/parsers/packet_item_parser.rb +7 -2
  23. data/lib/cosmos/script/commands.rb +5 -0
  24. data/lib/cosmos/script/scripting.rb +5 -5
  25. data/lib/cosmos/script/telemetry.rb +5 -0
  26. data/lib/cosmos/tools/cmd_tlm_server/api.rb +22 -0
  27. data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +38 -10
  28. data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +48 -9
  29. data/lib/cosmos/tools/test_runner/test_runner.rb +76 -14
  30. data/lib/cosmos/tools/tlm_viewer/widgets/linegraph_widget.rb +11 -2
  31. data/lib/cosmos/tools/tlm_viewer/widgets/timegraph_widget.rb +15 -12
  32. data/lib/cosmos/top_level.rb +29 -32
  33. data/lib/cosmos/version.rb +4 -4
  34. data/spec/config/config_parser_spec.rb +8 -15
  35. data/spec/core_ext/socket_spec.rb +2 -2
  36. data/spec/core_ext/string_spec.rb +10 -0
  37. data/spec/core_ext/time_spec.rb +12 -4
  38. data/spec/io/io_multiplexer_spec.rb +11 -3
  39. data/spec/packets/packet_spec.rb +30 -0
  40. data/spec/script/commands_spec.rb +2 -1
  41. data/spec/script/scripting_spec.rb +22 -0
  42. data/spec/script/telemetry_spec.rb +2 -1
  43. data/spec/spec_helper.rb +2 -2
  44. data/spec/tools/cmd_tlm_server/router_thread_spec.rb +2 -2
  45. data/spec/top_level/top_level_spec.rb +4 -2
  46. metadata +5 -5
@@ -366,7 +366,7 @@ module Cosmos
366
366
  end
367
367
 
368
368
  def to_xtce_type(param_or_arg, xml)
369
- # TODO: Arrays, Spline Conversions
369
+ # TODO: Spline Conversions
370
370
  case self.data_type
371
371
  when :INT, :UINT
372
372
  attrs = { :name => (self.name + '_Type') }
@@ -383,12 +383,13 @@ module Cosmos
383
383
  encoding = 'unsigned'
384
384
  end
385
385
  if @states
386
- xml['xtce'].send('Enumerated' + param_or_arg + 'Type', attrs) do
386
+ xml['xtce'].send('Enumerated' + param_or_arg + 'Type', attrs) do
387
+ to_xtce_endianness(xml)
387
388
  to_xtce_units(xml)
388
389
  xml['xtce'].IntegerDataEncoding(:sizeInBits => self.bit_size, :encoding => encoding)
389
- xml['xtce'].EnumerationList do
390
+ xml['xtce'].EnumerationList do
390
391
  @states.each do |state_name, state_value|
391
- xml['xtce'].Enumeration(:value => state_value, :label => state_name)
392
+ xml['xtce'].Enumeration(:value => state_value, :label => state_name)
392
393
  end
393
394
  end
394
395
  end
@@ -400,6 +401,7 @@ module Cosmos
400
401
  attrs[:signed] = signed
401
402
  end
402
403
  xml['xtce'].send(type_string, attrs) do
404
+ to_xtce_endianness(xml)
403
405
  to_xtce_units(xml)
404
406
  if (self.read_conversion and self.read_conversion.class == PolynomialConversion) or (self.write_conversion and self.write_conversion.class == PolynomialConversion)
405
407
  xml['xtce'].IntegerDataEncoding(:sizeInBits => self.bit_size, :encoding => encoding) do
@@ -432,6 +434,7 @@ module Cosmos
432
434
  attrs[:initialValue] = self.default if self.default and !self.array_size
433
435
  attrs[:shortDescription] = self.description if self.description
434
436
  xml['xtce'].send('Float' + param_or_arg + 'Type', attrs) do
437
+ to_xtce_endianness(xml)
435
438
  to_xtce_units(xml)
436
439
  if (self.read_conversion and self.read_conversion.class == PolynomialConversion) or (self.write_conversion and self.write_conversion.class == PolynomialConversion)
437
440
  xml['xtce'].FloatDataEncoding(:sizeInBits => self.bit_size, :encoding => 'IEEE754_1985') do
@@ -467,9 +470,10 @@ module Cosmos
467
470
  attrs[:initialValue] = self.default if self.default and !self.array_size
468
471
  attrs[:shortDescription] = self.description if self.description
469
472
  xml['xtce'].send('String' + param_or_arg + 'Type', attrs) do
473
+ to_xtce_endianness(xml)
470
474
  to_xtce_units(xml)
471
475
  xml['xtce'].StringDataEncoding(:encoding => 'UTF-8') do
472
- xml['xtce'].SizeInBits do
476
+ xml['xtce'].SizeInBits do
473
477
  xml['xtce'].Fixed do
474
478
  xml['xtce'].FixedValue(self.bit_size.to_s)
475
479
  end
@@ -483,9 +487,10 @@ module Cosmos
483
487
  attrs[:shortDescription] = self.description if self.description
484
488
  #attrs[:initialValue] = self.default if self.default and !self.array_size
485
489
  xml['xtce'].send('Binary' + param_or_arg + 'Type', attrs) do
490
+ to_xtce_endianness(xml)
486
491
  to_xtce_units(xml)
487
492
  xml['xtce'].BinaryDataEncoding do
488
- xml['xtce'].SizeInBits do
493
+ xml['xtce'].SizeInBits do
489
494
  xml['xtce'].FixedValue(self.bit_size.to_s)
490
495
  end
491
496
  end
@@ -493,10 +498,24 @@ module Cosmos
493
498
  when :DERIVED
494
499
  raise "DERIVED data type not supported in XTCE"
495
500
  end
501
+
502
+ # Handle arrays
503
+ if self.array_size
504
+ # The above will have created the type for the array entries. Now we create the type for the actual array.
505
+ attrs = { :name => (self.name + '_ArrayType') }
506
+ attrs[:shortDescription] = self.description if self.description
507
+ attrs[:arrayTypeRef] = (self.name + '_Type')
508
+ attrs[:numberOfDimensions] = '1' # COSMOS Only supports one-dimensional arrays
509
+ xml['xtce'].send('Array' + param_or_arg + 'Type', attrs)
510
+ end
496
511
  end
497
512
 
498
513
  def to_xtce_item(param_or_arg, xml)
499
- xml['xtce'].send(param_or_arg, :name => self.name, "#{param_or_arg.downcase}TypeRef" => self.name + '_Type')
514
+ if self.array_size
515
+ xml['xtce'].send(param_or_arg, :name => self.name, "#{param_or_arg.downcase}TypeRef" => self.name + '_ArrayType')
516
+ else
517
+ xml['xtce'].send(param_or_arg, :name => self.name, "#{param_or_arg.downcase}TypeRef" => self.name + '_Type')
518
+ end
500
519
  end
501
520
 
502
521
  protected
@@ -511,6 +530,16 @@ module Cosmos
511
530
  end
512
531
  end
513
532
 
533
+ def to_xtce_endianness(xml)
534
+ if self.endianness == :LITTLE_ENDIAN and self.bit_size > 8
535
+ xml['xtce'].ByteOrderList do
536
+ (((self.bit_size - 1)/ 8) + 1).times do |byte_significance|
537
+ xml['xtce'].Byte(:byteSignificance => byte_significance)
538
+ end
539
+ end
540
+ end
541
+ end
542
+
514
543
  def to_xtce_conversion(xml)
515
544
  if self.read_conversion
516
545
  conversion = self.read_conversion
@@ -519,11 +548,11 @@ module Cosmos
519
548
  end
520
549
  if conversion and conversion.class == PolynomialConversion
521
550
  xml['xtce'].DefaultCalibrator do
522
- xml['xtce'].PolynomialCalibrator do
551
+ xml['xtce'].PolynomialCalibrator do
523
552
  conversion.coeffs.each_with_index do |coeff, index|
524
- xml['xtce'].Term(:coefficient => coeff, :exponent => index)
553
+ xml['xtce'].Term(:coefficient => coeff, :exponent => index)
525
554
  end
526
- end
555
+ end
527
556
  end
528
557
  end
529
558
  end
@@ -119,7 +119,11 @@ module Cosmos
119
119
  return nil if data_type == :STRING or data_type == :BLOCK
120
120
 
121
121
  index = append? ? 3 : 4
122
- (ConfigParser.handle_defined_constants(@parser.parameters[index].convert_to_value))..(ConfigParser.handle_defined_constants(@parser.parameters[index+1].convert_to_value))
122
+ min = ConfigParser.handle_defined_constants(
123
+ @parser.parameters[index].convert_to_value, get_data_type(), get_bit_size())
124
+ max = ConfigParser.handle_defined_constants(
125
+ @parser.parameters[index+1].convert_to_value, get_data_type(), get_bit_size())
126
+ min..max
123
127
  end
124
128
 
125
129
  def get_default
@@ -130,7 +134,8 @@ module Cosmos
130
134
  if data_type == :STRING or data_type == :BLOCK
131
135
  return @parser.parameters[index]
132
136
  else
133
- return ConfigParser.handle_defined_constants(@parser.parameters[index+2].convert_to_value)
137
+ return ConfigParser.handle_defined_constants(
138
+ @parser.parameters[index+2].convert_to_value, get_data_type(), get_bit_size())
134
139
  end
135
140
  end
136
141
 
@@ -178,6 +178,11 @@ module Cosmos
178
178
  results
179
179
  end
180
180
 
181
+ # Returns the buffer from the most recent specified command
182
+ def get_cmd_buffer(target_name, command_name)
183
+ return $cmd_tlm_server.get_cmd_buffer(target_name, command_name)
184
+ end
185
+
181
186
  end # module Script
182
187
 
183
188
  end # module Cosmos
@@ -596,13 +596,13 @@ module Cosmos
596
596
  when 3
597
597
  target_name, packet_name, item_name = extract_fields_from_tlm_text(args[0])
598
598
  expected_value = args[1]
599
- tolerance = args[2]
599
+ tolerance = args[2].abs
600
600
  when 5
601
601
  target_name = args[0]
602
602
  packet_name = args[1]
603
603
  item_name = args[2]
604
604
  expected_value = args[3]
605
- tolerance = args[4]
605
+ tolerance = args[4].abs
606
606
  else
607
607
  # Invalid number of arguments
608
608
  raise "ERROR: Invalid number of arguments (#{args.length}) passed to #{function_name}()"
@@ -676,7 +676,7 @@ module Cosmos
676
676
  when 4, 5
677
677
  target_name, packet_name, item_name = extract_fields_from_tlm_text(args[0])
678
678
  expected_value = args[1]
679
- tolerance = args[2]
679
+ tolerance = args[2].abs
680
680
  timeout = args[3]
681
681
  if args.length == 5
682
682
  polling_rate = args[4]
@@ -688,7 +688,7 @@ module Cosmos
688
688
  packet_name = args[1]
689
689
  item_name = args[2]
690
690
  expected_value = args[3]
691
- tolerance = args[4]
691
+ tolerance = args[4].abs
692
692
  timeout = args[5]
693
693
  if args.length == 7
694
694
  polling_rate = args[6]
@@ -799,7 +799,7 @@ module Cosmos
799
799
 
800
800
  def cosmos_script_wait_implementation_tolerance(target_name, packet_name, item_name, value_type, expected_value, tolerance, timeout, polling_rate = DEFAULT_TLM_POLLING_RATE)
801
801
  _cosmos_script_wait_implementation(target_name, packet_name, item_name, value_type, timeout, polling_rate) do
802
- "((#{expected_value} - #{tolerance})..(#{expected_value} + #{tolerance})).include? value"
802
+ "((#{expected_value} - #{tolerance.abs})..(#{expected_value} + #{tolerance.abs})).include? value"
803
803
  end
804
804
  end
805
805
 
@@ -122,6 +122,11 @@ module Cosmos
122
122
  $cmd_tlm_server.get_tlm_details(items)
123
123
  end
124
124
 
125
+ # Returns the buffer from the telemetry packet.
126
+ def get_tlm_buffer(target_name, packet_name)
127
+ return $cmd_tlm_server.get_tlm_buffer(target_name, packet_name)
128
+ end
129
+
125
130
  # Subscribe to one or more telemetry packets. The queue ID is returned for
126
131
  # use in get_packet_data and unsubscribe_packet_data.
127
132
  # Usage:
@@ -28,6 +28,7 @@ module Cosmos
28
28
  'cmd_raw_no_hazardous_check',
29
29
  'cmd_raw_no_checks',
30
30
  'send_raw',
31
+ 'get_cmd_buffer',
31
32
  'get_cmd_list',
32
33
  'get_cmd_param_list',
33
34
  'get_cmd_hazardous',
@@ -40,6 +41,7 @@ module Cosmos
40
41
  'tlm_variable',
41
42
  'set_tlm',
42
43
  'set_tlm_raw',
44
+ 'get_tlm_buffer',
43
45
  'get_tlm_packet',
44
46
  'get_tlm_values',
45
47
  'get_tlm_list',
@@ -226,6 +228,16 @@ module Cosmos
226
228
  nil
227
229
  end
228
230
 
231
+ # Returns the raw buffer from the most recent specified command packet.
232
+ #
233
+ # @param target_name [String] Target name of the command
234
+ # @param command_name [String] Packet name of the command
235
+ # @return [String] last command buffer packet
236
+ def get_cmd_buffer(target_name, command_name)
237
+ packet = System.commands.packet(target_name, command_name)
238
+ return packet.buffer
239
+ end
240
+
229
241
  # Returns the list of all the command names and their descriptions from the
230
242
  # given target.
231
243
  #
@@ -480,6 +492,16 @@ module Cosmos
480
492
  nil
481
493
  end
482
494
 
495
+ # Returns the raw buffer for a telemetry packet.
496
+ #
497
+ # @param target_name [String] Name of the target
498
+ # @param packet_name [String] Name of the packet
499
+ # @return [String] last telemetry packet buffer
500
+ def get_tlm_buffer(target_name, packet_name)
501
+ packet = System.telemetry.packet(target_name, packet_name)
502
+ return packet.buffer
503
+ end
504
+
483
505
  # Returns all the values (along with their limits state) for a packet.
484
506
  #
485
507
  # @param target_name [String] Name of the target
@@ -58,6 +58,12 @@ module Cosmos
58
58
  attr_reader :ignored
59
59
  # @return [Boolean] Whether the limits items have been fetched from the server
60
60
  attr_reader :initialized
61
+ # @return [Boolean] Whether to display an item with a colorblind option
62
+ attr_accessor :colorblind
63
+ # @return [Boolean] Whether to display an item with operational limits while it's
64
+ # currently green. If false, items are not displayed until they go yellow
65
+ # or red. If true, items are displayed when transitioning from blue to green.
66
+ attr_accessor :monitor_operational
61
67
 
62
68
  UNKNOWN_ARRAY = ['UNKNOWN', 'UNKNOWN', nil]
63
69
 
@@ -73,6 +79,8 @@ module Cosmos
73
79
  @out_of_limits = []
74
80
  @queue_id = nil
75
81
  @limits_set = :DEFAULT
82
+ @colorblind = false
83
+ @monitor_operational = true
76
84
  request_reset()
77
85
  end
78
86
 
@@ -237,6 +245,10 @@ module Cosmos
237
245
  @ignored << ([params[0], params[1], params[2]])
238
246
  when 'IGNORE_PACKET'
239
247
  @ignored << ([params[0], params[1], nil])
248
+ when 'COLOR_BLIND'
249
+ @colorblind = true
250
+ when 'IGNORE_OPERATIONAL_LIMITS'
251
+ @monitor_operational = false
240
252
  end
241
253
  end
242
254
  result = "#{filename} loaded. "
@@ -256,6 +268,12 @@ module Cosmos
256
268
  def save_config(filename)
257
269
  begin
258
270
  File.open(filename, "w") do |file|
271
+ if @colorblind
272
+ file.puts("COLOR_BLIND")
273
+ end
274
+ unless @monitor_operational
275
+ file.puts("IGNORE_OPERATIONAL_LIMITS")
276
+ end
259
277
  @ignored.each do |target, pkt_name, item_name|
260
278
  if item_name
261
279
  file.puts("IGNORE_ITEM #{target} #{pkt_name} #{item_name}")
@@ -311,7 +329,11 @@ module Cosmos
311
329
  message << "ERROR: "
312
330
  color = :RED
313
331
  out_of_limit(item)
314
- when :GREEN, :GREEN_HIGH, :GREEN_LOW
332
+ when :GREEN_HIGH, :GREEN_LOW
333
+ message << "INFO: "
334
+ color = :GREEN
335
+ out_of_limit(item) if @monitor_operational
336
+ when :GREEN
315
337
  message << "INFO: "
316
338
  color = :GREEN
317
339
  when :BLUE
@@ -343,6 +365,8 @@ module Cosmos
343
365
  # encountered by the COSMOS server. It provides the ability to ignore and
344
366
  # restore limits as well as logs all limits events.
345
367
  class LimitsMonitor < QtTool
368
+ attr_reader :limits_items
369
+
346
370
  # LimitsWidget displays either a stale packet using the Label widget
347
371
  # or more commonly an out of limits item using the Labelvaluelimitsbar
348
372
  # Widget.
@@ -364,7 +388,7 @@ module Cosmos
364
388
  item = [target_name, packet_name, item_name]
365
389
  if item_name
366
390
  @value = LabelvaluelimitsbarWidget.new(@layout, target_name, packet_name, item_name)
367
- @value.set_setting('COLORBLIND', [@colorblind])
391
+ @value.set_setting('COLORBLIND', [parent.limits_items.colorblind])
368
392
  @value.process_settings
369
393
  else
370
394
  @value = LabelWidget.new(layout, "#{target_name} #{packet_name} is STALE")
@@ -530,7 +554,9 @@ module Cosmos
530
554
  dialog.setWindowTitle('Options')
531
555
 
532
556
  colorblind_box = Qt::CheckBox.new('Colorblind Mode Enabled', self)
533
- colorblind_box.setCheckState(Qt::Checked) if @colorblind
557
+ colorblind_box.setCheckState(Qt::Checked) if @limits_items.colorblind
558
+ operational_limit_box = Qt::CheckBox.new('Monitor Operational Limits', self)
559
+ operational_limit_box.setCheckState(Qt::Checked) if @limits_items.monitor_operational
534
560
 
535
561
  ok = Qt::PushButton.new('Ok') do
536
562
  connect(SIGNAL('clicked()')) { dialog.accept }
@@ -544,18 +570,24 @@ module Cosmos
544
570
  end
545
571
  dialog.layout = Qt::VBoxLayout.new do
546
572
  addWidget(colorblind_box)
573
+ addWidget(operational_limit_box)
547
574
  addLayout(buttons)
548
575
  end
549
576
 
550
577
  case dialog.exec
551
578
  when Qt::Dialog::Accepted
579
+ if (operational_limit_box.checkState() == Qt::Checked)
580
+ @limits_items.monitor_operational = true
581
+ else
582
+ @limits_items.monitor_operational = false
583
+ end
552
584
  if (colorblind_box.checkState() == Qt::Checked)
553
- @colorblind = true
585
+ @limits_items.colorblind = true
554
586
  else
555
- @colorblind = false
587
+ @limits_items.colorblind = false
556
588
  end
557
589
  (0...@scroll_layout.count).each do |index|
558
- @scroll_layout.itemAt(index).widget.set_colorblind(@colorblind)
590
+ @scroll_layout.itemAt(index).widget.set_colorblind(@limits_items.colorblind)
559
591
  end
560
592
  end
561
593
  dialog.dispose
@@ -784,10 +816,6 @@ module Cosmos
784
816
  palette = Cosmos.getPalette(Cosmos.getColor(0, 0, 0), Cosmos.getColor(255,0,0))
785
817
  @monitored_state_text_field.setPalette(palette)
786
818
  text = 'Red'
787
- when :BLUE
788
- palette = Cosmos.getPalette(Cosmos.getColor(0, 0, 0), Cosmos.getColor(0,0,255))
789
- @monitored_state_text_field.setPalette(palette)
790
- text = 'Blue'
791
819
  end
792
820
  text << ' - Some Items Ignored' if @limits_items.ignored_items?
793
821
  @monitored_state_text_field.text = text
@@ -116,6 +116,14 @@ module Cosmos
116
116
  end
117
117
  end
118
118
 
119
+ @derived_last_action = Qt::Action.new(tr('&Display Derived Last'), self)
120
+ @derived_last_keyseq = Qt::KeySequence.new(tr('Ctrl+D'))
121
+ @derived_last_action.shortcut = @derived_last_keyseq
122
+ @derived_last_action.statusTip = tr('Display derived telemetry items last')
123
+ @derived_last_action.setCheckable(true)
124
+ @derived_last_action.setChecked(false)
125
+ @derived_last_action.connect(SIGNAL('triggered()')) { update_tlm_items() }
126
+
119
127
  @formatted_tlm_units_action = Qt::Action.new(tr('Formatted Telemetry With &Units'), self)
120
128
  @formatted_tlm_units_keyseq = Qt::KeySequence.new(tr('Ctrl+U'))
121
129
  @formatted_tlm_units_action.shortcut = @formatted_tlm_units_keyseq
@@ -177,6 +185,7 @@ module Cosmos
177
185
  view_menu = menuBar.addMenu(tr('&View'))
178
186
  view_menu.addAction(@color_blind_action)
179
187
  view_menu.addAction(@hide_ignored_action)
188
+ view_menu.addAction(@derived_last_action)
180
189
  view_menu.addSeparator.setText(tr('Formatting'));
181
190
  view_menu.addAction(@formatted_tlm_units_action)
182
191
  view_menu.addAction(@formatted_tlm_action)
@@ -253,7 +262,8 @@ module Cosmos
253
262
  end
254
263
 
255
264
  def file_options
256
- @polling_rate = Qt::InputDialog.getDouble(self, tr("Options"), tr("Polling Rate (sec):"), @polling_rate, 0, 1000, 1, nil)
265
+ @polling_rate = Qt::InputDialog.getDouble(self, tr("Options"), tr("Polling Rate (sec):"),
266
+ @polling_rate, 0, 1000, 1, nil)
257
267
  end
258
268
 
259
269
  def update_all
@@ -330,8 +340,22 @@ module Cosmos
330
340
  # Update Telemetry Items
331
341
  tlm_items = []
332
342
  begin
333
- System.telemetry.items(target_name, packet_name).each do |item|
334
- tlm_items << [item.name, item.states, item.description]
343
+ @derived_row = 0
344
+ if @derived_last_action.isChecked
345
+ derived = []
346
+ System.telemetry.items(target_name, packet_name).each do |item|
347
+ if item.data_type == :DERIVED
348
+ derived << [item.name, item.states, item.description]
349
+ else
350
+ tlm_items << [item.name, item.states, item.description]
351
+ @derived_row += 1
352
+ end
353
+ end
354
+ tlm_items.concat(derived) # Tack the derived onto the end
355
+ else
356
+ System.telemetry.items(target_name, packet_name).each do |item|
357
+ tlm_items << [item.name, item.states, item.description]
358
+ end
335
359
  end
336
360
  rescue
337
361
  # Unknown packet
@@ -371,9 +395,11 @@ module Cosmos
371
395
 
372
396
  # Handle Table Clicks
373
397
  @table.setMouseTracking(true)
374
- connect(@table, SIGNAL('cellEntered(int, int)'), self, SLOT('mouse_over(int, int)'))
398
+ connect(@table, SIGNAL('cellEntered(int, int)'),
399
+ self, SLOT('mouse_over(int, int)'))
375
400
  @table.setContextMenuPolicy(Qt::CustomContextMenu)
376
- connect(@table, SIGNAL('customContextMenuRequested(const QPoint&)'), self, SLOT('context_menu(const QPoint&)'))
401
+ connect(@table, SIGNAL('customContextMenuRequested(const QPoint&)'),
402
+ self, SLOT('context_menu(const QPoint&)'))
377
403
 
378
404
  # Start Update Thread
379
405
  update_needed = false
@@ -403,15 +429,23 @@ module Cosmos
403
429
 
404
430
  Qt.execute_in_main_thread(true) do
405
431
  # If we need an update (which indicates we've reconnected to the server)
406
- # Then we call update_all which will update all the telemetry items and kill and respawn this thread
432
+ # Then we call update_all which will update all the telemetry items
433
+ # and kill and respawn this thread
407
434
  if update_needed
408
435
  update_all()
409
436
  end
410
437
 
411
438
  if tlm_items
412
- row = 0
439
+ # Start with wherever the first derived item is
440
+ # See above where we populate tlm_items
441
+ row = @derived_row
413
442
  tlm_items.each do |name, value, limits_state|
414
443
  text = value.to_s
444
+ # If derived is last we need to reset the row to 0
445
+ # to start populating the real items at the top
446
+ if row == (tlm_items.length)
447
+ row = 0
448
+ end
415
449
 
416
450
  case limits_state
417
451
  when :GREEN, :GREEN_HIGH
@@ -527,7 +561,8 @@ module Cosmos
527
561
  options.height = 200
528
562
  options.title = 'Packet Viewer : Formatted Telemetry with Units'
529
563
  option_parser.separator "Packet Viewer Specific Options:"
530
- option_parser.on("-p", "--packet 'TARGET_NAME PACKET_NAME'", "Start viewing the specified packet") do |arg|
564
+ option_parser.on("-p", "--packet 'TARGET_NAME PACKET_NAME'",
565
+ "Start viewing the specified packet") do |arg|
531
566
  split = arg.split
532
567
  if split.length != 2
533
568
  puts "Packet must be specified as 'TARGET_NAME PACKET_NAME' in quotes"
@@ -535,7 +570,10 @@ module Cosmos
535
570
  end
536
571
  options.packet = split
537
572
  end
538
- option_parser.on("-r", "--rate PERIOD", "Set the polling rate to PERIOD (unit seconds)") { |arg| options.rate = Float(arg) }
573
+ option_parser.on("-r", "--rate PERIOD",
574
+ "Set the polling rate to PERIOD (unit seconds)") do |arg|
575
+ options.rate = Float(arg)
576
+ end
539
577
  end
540
578
 
541
579
  super(option_parser, options)
@@ -545,3 +583,4 @@ module Cosmos
545
583
  end # class PacketViewer
546
584
 
547
585
  end # module Cosmos
586
+