Class: OpenC3::PacketItem

Inherits:
StructureItem
  • Object
show all
Defined in:
lib/openc3/packets/packet_item.rb,
ext/openc3/ext/packet/packet.c

Overview

Maintains knowledge of an item in a Packet

Direct Known Subclasses

TableItem

Constant Summary collapse

STATE_COLORS =

The allowable state colors

[:GREEN, :YELLOW, :RED]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, bit_offset, bit_size, data_type, endianness, array_size = nil, overflow = :ERROR) ⇒ Object

Create a StructureItem by setting all the attributes. It calls all the setter routines to do the attribute verification and then verifies the overall integrity.

It also initializes the attributes of the PacketItem.

Parameters:

  • name (String)

    The item name

  • bit_offset (Integer)

    Offset to the item starting at 0

  • bit_size (Integer)

    Size of the items in bits

  • data_type (Symbol)

    DATA_TYPES

  • endianness (Symbol)
  • array_size (Integer, nil) (defaults to: nil)

    Size of the array item in bits. For example, if the bit_size is 8, an array_size of 16 holds two values.

  • overflow (Symbol) (defaults to: :ERROR)


98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/openc3/packets/packet_item.rb', line 98

def initialize(name, bit_offset, bit_size, data_type, endianness, array_size = nil, overflow = :ERROR)
  super(name, bit_offset, bit_size, data_type, endianness, array_size, overflow)
  @format_string = nil
  @read_conversion = nil
  @write_conversion = nil
  @id_value = nil
  @states = nil
  @description = nil
  @units_full = nil
  @units = nil
  @default = nil
  @range = nil
  @required = false
  @hazardous = nil
  @messages_disabled = nil
  @state_colors = nil
  @limits = PacketItemLimits.new
  @persistence_setting = 1
  @persistence_count = 0
  @meta = nil
end

Instance Attribute Details

#defaultObject

The default value type depends on the data_type of the PacketItem

Returns:

  • Default value for this item



66
67
68
# File 'lib/openc3/packets/packet_item.rb', line 66

def default
  @default
end

#descriptionString

Returns Description of the item.

Returns:

  • (String)

    Description of the item



52
53
54
# File 'lib/openc3/packets/packet_item.rb', line 52

def description
  @description
end

#format_stringString

Returns Printf-style string used to format the item.

Returns:

  • (String)

    Printf-style string used to format the item



33
34
35
# File 'lib/openc3/packets/packet_item.rb', line 33

def format_string
  @format_string
end

#hazardousHash

States that are hazardous for this item as well as their descriptions

Returns:

  • (Hash)

    Hazardous states given as STATE_NAME => DESCRIPTION. If no description was given the value will be nil.



80
81
82
# File 'lib/openc3/packets/packet_item.rb', line 80

def hazardous
  @hazardous
end

#id_valueObject

The id_value type depends on the data_type of the PacketItem

Returns:

  • Value used to identify a packet



45
46
47
# File 'lib/openc3/packets/packet_item.rb', line 45

def id_value
  @id_value
end

#limitsPacketItemLimits

Returns All information regarding limits for this PacketItem.

Returns:



94
95
96
# File 'lib/openc3/packets/packet_item.rb', line 94

def limits
  @limits
end

#messages_disabledHash

Returns Whether or not messages should be printed for this state. Given as STATE_NAME => true / false.

Returns:

  • (Hash)

    Whether or not messages should be printed for this state. Given as STATE_NAME => true / false.



84
85
86
# File 'lib/openc3/packets/packet_item.rb', line 84

def messages_disabled
  @messages_disabled
end

#rangeRange

The valid range of values for this item. Returns nil for items with data_type of :STRING or :BLOCK items.

Returns:

  • (Range)

    Valid range of values or nil



71
72
73
# File 'lib/openc3/packets/packet_item.rb', line 71

def range
  @range
end

#read_conversionConversion

Conversion instance used when reading the PacketItem

Returns:



37
38
39
# File 'lib/openc3/packets/packet_item.rb', line 37

def read_conversion
  @read_conversion
end

#requiredBoolean

default value. true if it must be specified.

Returns:

  • (Boolean)

    Whether this item must be specified or can use its



75
76
77
# File 'lib/openc3/packets/packet_item.rb', line 75

def required
  @required
end

#state_colorsHash

Colors associated with states

Returns:

  • (Hash)

    State colors given as STATE_NAME => COLOR



88
89
90
# File 'lib/openc3/packets/packet_item.rb', line 88

def state_colors
  @state_colors
end

#statesHash

States are used to convert from a numeric value to a String.

Returns:

  • (Hash)

    Item states given as STATE_NAME => VALUE



49
50
51
# File 'lib/openc3/packets/packet_item.rb', line 49

def states
  @states
end

#unitsString

Returns the abbreviated units of the item. For example, if the item represents a voltage, this would return “V”.

Returns:

  • (String)

    Abbreviated units of the item



62
63
64
# File 'lib/openc3/packets/packet_item.rb', line 62

def units
  @units
end

#units_fullString

Returns the fully spelled out units of the item. For example, if the item represents a voltage, this would return “Voltage”.

Returns:

  • (String)

    Units of the item



57
58
59
# File 'lib/openc3/packets/packet_item.rb', line 57

def units_full
  @units_full
end

#write_conversionConversion

Conversion instance used when writing the PacketItem

Returns:



41
42
43
# File 'lib/openc3/packets/packet_item.rb', line 41

def write_conversion
  @write_conversion
end

Class Method Details

.from_json(hash) ⇒ Object



520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
# File 'lib/openc3/packets/packet_item.rb', line 520

def self.from_json(hash)
  # Convert strings to symbols
  endianness = hash['endianness'] ? hash['endianness'].intern : nil
  data_type = hash['data_type'] ? hash['data_type'].intern : nil
  overflow = hash['overflow'] ? hash['overflow'].intern : nil
  item = PacketItem.new(hash['name'], hash['bit_offset'], hash['bit_size'],
    data_type, endianness, hash['array_size'], overflow)
  item.description = hash['description']
  item.id_value = hash['id_value']
  item.default = hash['default']
  item.range = (hash['minimum']..hash['maximum']) if hash['minimum'] && hash['maximum']
  item.required = hash['required']
  item.format_string = hash['format_string']
  item.units = hash['units']
  item.units_full = hash['units_full']
  if hash['states']
    item.states = {}
    item.hazardous = {}
    item.messages_disabled = {}
    item.state_colors = {}
    hash['states'].each do |state_name, state|
      item.states[state_name] = state['value']
      item.hazardous[state_name] = state['hazardous']
      item.messages_disabled[state_name] = state['messages_disabled']
      item.state_colors[state_name] = state['color'].to_sym if state['color']
    end
  end
  # Recreate OpenC3 built-in conversions
  if hash['read_conversion']
    begin
      item.read_conversion = OpenC3::const_get(hash['read_conversion']['class']).new(*hash['read_conversion']['params'])
    rescue => error
      Logger.instance.error "#{item.name} read_conversion of #{hash['read_conversion']} could not be instantiated due to #{error}"
    end
  end
  if hash['write_conversion']
    begin
      item.write_conversion = OpenC3::const_get(hash['write_conversion']['class']).new(*hash['write_conversion']['params'])
    rescue => error
      Logger.instance.error "#{item.name} write_conversion of #{hash['write_conversion']} could not be instantiated due to #{error}"
    end
  end

  item.limits = PacketItemLimits.new
  if hash['limits']
    # Delete the keys so the only ones left are limits sets
    persistence_setting = hash['limits'].delete('persistence_setting')
    item.limits.persistence_setting = persistence_setting if persistence_setting
    hash['limits'].delete('response') # Can't round trip response
    item.limits.enabled = true if hash['limits'].delete('enabled')
    values = {}
    hash['limits'].each do |set, items|
      values[set.to_sym] = [items['red_low'], items['yellow_low'], items['yellow_high'], items['red_high']]
      values[set.to_sym].concat([items['green_low'], items['green_high']]) if items['green_low'] && items['green_high']
    end
    item.limits.values = values if values.length > 0
  end
  item.meta = hash['meta']
  item.variable_bit_size = hash['variable_bit_size']
  item
end

Instance Method Details

#as_json(*a) ⇒ Object



452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
# File 'lib/openc3/packets/packet_item.rb', line 452

def as_json(*a)
  config = {}
  config['name'] = self.name
  config['bit_offset'] = self.bit_offset
  config['bit_size'] = self.bit_size
  config['data_type'] = self.data_type.to_s
  config['array_size'] = self.array_size if self.array_size
  config['description'] = self.description
  config['id_value'] = self.id_value.as_json(*a) if self.id_value
  if @default
    config['default'] = @default.as_json(*a)
  end
  if self.range
    config['minimum'] = self.range.first.as_json(*a)
    config['maximum'] = self.range.last.as_json(*a)
  end
  config['endianness'] = self.endianness.to_s
  config['required'] = self.required
  config['format_string'] = self.format_string if self.format_string
  if self.units
    config['units'] = self.units
    config['units_full'] = self.units_full
  end
  config['overflow'] = self.overflow.to_s
  if @states
    states = {}
    config['states'] = states
    @states.each do |state_name, state_value|
      state = {}
      states[state_name] = state
      state['value'] = state_value.as_json(*a)
      state['hazardous'] = @hazardous[state_name] if @hazardous and @hazardous[state_name]
      state['messages_disabled'] = @messages_disabled[state_name] if @messages_disabled and @messages_disabled[state_name]
      state['color'] = @state_colors[state_name].to_s if @state_colors and @state_colors[state_name]
    end
  end

  config['read_conversion'] = self.read_conversion.as_json(*a) if self.read_conversion
  config['write_conversion'] = self.write_conversion.as_json(*a) if self.write_conversion

  if self.limits
    config['limits'] ||= {}
    config['limits']['enabled'] = true if self.limits.enabled
    if self.limits.values
      config['limits'] ||= {}
      config['limits']['persistence_setting'] = self.limits.persistence_setting
      config['limits']['response'] = self.limits.response.to_s if self.limits.response
      self.limits.values.each do |limits_set, limits_values|
        limits = {}
        limits['red_low'] =  limits_values[0]
        limits['yellow_low'] = limits_values[1]
        limits['yellow_high'] = limits_values[2]
        limits['red_high'] = limits_values[3]
        limits['green_low'] = limits_values[4] if limits_values[4]
        limits['green_high'] = limits_values[5] if limits_values[5]
        config['limits'][limits_set] = limits
      end
    end
    config['limits_response'] = self.limits.response.as_json(*a) if self.limits.response
  end

  config['meta'] = @meta if @meta
  if @variable_bit_size
    config['variable_bit_size'] = @variable_bit_size
  end
  config
end

#calculate_rangeObject



353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# File 'lib/openc3/packets/packet_item.rb', line 353

def calculate_range
  first = range.first
  last = range.last
  if data_type == :FLOAT
    if bit_size == 32
      if range.first == -3.402823e38
        first = 'MIN'
      end
      if range.last == 3.402823e38
        last = 'MAX'
      end
    else
      if range.first == -Float::MAX
        first = 'MIN'
      end
      if range.last == Float::MAX
        last = 'MAX'
      end
    end
  end
  return [first, last]
end

#check_default_and_range_data_typesObject



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/openc3/packets/packet_item.rb', line 207

def check_default_and_range_data_types
  if @default and !@write_conversion
    if @array_size
      raise ArgumentError, "#{@name}: default must be an Array but is a #{default.class}" unless Array === @default
    else
      case data_type
      when :INT, :UINT
        raise ArgumentError, "#{@name}: default must be a Integer but is a #{@default.class}" unless Integer === @default

        if @range
          raise ArgumentError, "#{@name}: minimum must be a Integer but is a #{@range.first.class}" unless Integer === @range.first
          raise ArgumentError, "#{@name}: maximum must be a Integer but is a #{@range.last.class}" unless Integer === @range.last
        end
      when :FLOAT
        raise ArgumentError, "#{@name}: default must be a Float but is a #{@default.class}" unless Float === @default or Integer === @default

        @default = @default.to_f
        if @range
          raise ArgumentError, "#{@name}: minimum must be a Float but is a #{@range.first.class}" unless Float === @range.first or Integer === @range.first
          raise ArgumentError, "#{@name}: maximum must be a Float but is a #{@range.last.class}" unless Float === @range.last or Integer === @range.last

          @range = ((@range.first.to_f)..(@range.last.to_f))
        end
      when :BLOCK, :STRING
        raise ArgumentError, "#{@name}: default must be a String but is a #{@default.class}" unless String === @default

        @default = @default.clone.freeze
      end
    end
  end
end

#cloneObject Also known as: dup

Make a light weight clone of this item



304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/openc3/packets/packet_item.rb', line 304

def clone
  item = super()
  item.format_string = self.format_string.clone if self.format_string
  item.read_conversion = self.read_conversion.clone if self.read_conversion
  item.write_conversion = self.write_conversion.clone if self.write_conversion
  item.states = self.states.clone if self.states
  item.description = self.description.clone if self.description
  item.units_full = self.units_full.clone if self.units_full
  item.units = self.units.clone if self.units
  item.default = self.default.clone if self.default and String === self.default
  item.hazardous = self.hazardous.clone if self.hazardous
  item.messages_disabled = self.messages_disabled.clone if self.messages_disabled
  item.state_colors = self.state_colors.clone if self.state_colors
  item.limits = self.limits.clone if self.limits
  item.meta = self.meta.clone if @meta
  item
end

#metaObject



289
290
291
# File 'lib/openc3/packets/packet_item.rb', line 289

def meta
  @meta ||= {}
end

#meta=(meta) ⇒ Object



293
294
295
296
297
298
299
300
301
# File 'lib/openc3/packets/packet_item.rb', line 293

def meta=(meta)
  if meta
    raise ArgumentError, "#{@name}: meta must be a Hash but is a #{meta.class}" unless Hash === meta

    @meta = meta.clone
  else
    @meta = nil
  end
end

#to_config(cmd_or_tlm, default_endianness) ⇒ Object



376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
# File 'lib/openc3/packets/packet_item.rb', line 376

def to_config(cmd_or_tlm, default_endianness)
  config = ''
  if cmd_or_tlm == :TELEMETRY
    if self.array_size
      config << "  ARRAY_ITEM #{self.name.to_s.quote_if_necessary} #{self.bit_offset} #{self.bit_size} #{self.data_type} #{self.array_size} \"#{self.description.to_s.gsub("\"", "'")}\""
    elsif self.id_value
      id_value = self.id_value
      if self.data_type == :BLOCK || self.data_type == :STRING
        unless self.id_value.is_printable?
          id_value = "0x" + self.id_value.simple_formatted
        else
          id_value = "\"#{self.id_value}\""
        end
      end
      config << "  ID_ITEM #{self.name.to_s.quote_if_necessary} #{self.bit_offset} #{self.bit_size} #{self.data_type} #{id_value} \"#{self.description.to_s.gsub("\"", "'")}\""
    else
      config << "  ITEM #{self.name.to_s.quote_if_necessary} #{self.bit_offset} #{self.bit_size} #{self.data_type} \"#{self.description.to_s.gsub("\"", "'")}\""
    end
  else # :COMMAND
    if self.array_size
      config << "  ARRAY_PARAMETER #{self.name.to_s.quote_if_necessary} #{self.bit_offset} #{self.bit_size} #{self.data_type} #{self.array_size} \"#{self.description.to_s.gsub("\"", "'")}\""
    else
      config << parameter_config()
    end
  end
  config << " #{self.endianness}" if self.endianness != default_endianness && self.data_type != :STRING && self.data_type != :BLOCK
  config << "\n"

  config << "    VARIABLE_BIT_SIZE '#{self.variable_bit_size['length_item_name']}' #{self.variable_bit_size['length_bits_per_count']} #{self.variable_bit_size['length_value_bit_offset']}\n" if self.variable_bit_size
  config << "    REQUIRED\n" if self.required
  config << "    FORMAT_STRING #{self.format_string.to_s.quote_if_necessary}\n" if self.format_string
  config << "    UNITS #{self.units_full.to_s.quote_if_necessary} #{self.units.to_s.quote_if_necessary}\n" if self.units
  config << "    OVERFLOW #{self.overflow}\n" if self.overflow != :ERROR

  if @states
    @states.each do |state_name, state_value|
      config << "    STATE #{state_name.to_s.quote_if_necessary} #{state_value.to_s.quote_if_necessary}"
      if @hazardous and @hazardous[state_name]
        config << " HAZARDOUS #{@hazardous[state_name].to_s.quote_if_necessary}"
      end
      if @messages_disabled and @messages_disabled[state_name]
        config << " DISABLE_MESSAGES"
      end
      if @state_colors and @state_colors[state_name]
        config << " #{@state_colors[state_name]}"
      end
      config << "\n"
    end
  end

  config << self.read_conversion.to_config(:READ) if self.read_conversion
  config << self.write_conversion.to_config(:WRITE) if self.write_conversion

  if self.limits
    if self.limits.values
      self.limits.values.each do |limits_set, limits_values|
        config << "    LIMITS #{limits_set} #{self.limits.persistence_setting} #{self.limits.enabled ? 'ENABLED' : 'DISABLED'} #{limits_values[0]} #{limits_values[1]} #{limits_values[2]} #{limits_values[3]}"
        if limits_values[4] && limits_values[5]
          config << " #{limits_values[4]} #{limits_values[5]}\n"
        else
          config << "\n"
        end
      end
    end
    config << self.limits.response.to_config if self.limits.response
  end

  if @meta
    @meta.each do |key, values|
      config << "    META #{key.to_s.quote_if_necessary} #{values.map { |a| a.to_s.quote_if_necessary }.join(" ")}\n"
    end
  end

  config
end

#to_hashObject



323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# File 'lib/openc3/packets/packet_item.rb', line 323

def to_hash
  hash = super()
  hash['format_string'] = self.format_string
  if self.read_conversion
    hash['read_conversion'] = self.read_conversion.to_s
  else
    hash['read_conversion'] = nil
  end
  if self.write_conversion
    hash['write_conversion'] = self.write_conversion.to_s
  else
    hash['write_conversion'] = nil
  end
  hash['id_value'] = self.id_value
  hash['states'] = self.states
  hash['description'] = self.description
  hash['units_full'] = self.units_full
  hash['units'] = self.units
  hash['default'] = self.default
  hash['range'] = self.range
  hash['required'] = self.required
  hash['hazardous'] = self.hazardous
  hash['messages_disabled'] = self.messages_disabled
  hash['state_colors'] = self.state_colors
  hash['limits'] = self.limits.to_hash
  hash['meta'] = nil
  hash['meta'] = @meta if @meta
  hash
end