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

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)


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

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
  @obfuscate = false
  @messages_disabled = nil
  @state_colors = nil
  @limits = PacketItemLimits.new
  @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



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

def default
  @default
end

#descriptionString

Returns Description of the item.

Returns:

  • (String)

    Description of the item



47
48
49
# File 'lib/openc3/packets/packet_item.rb', line 47

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



28
29
30
# File 'lib/openc3/packets/packet_item.rb', line 28

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.



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

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



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

def id_value
  @id_value
end

#limitsPacketItemLimits

Returns All information regarding limits for this PacketItem.

Returns:



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

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.



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

def messages_disabled
  @messages_disabled
end

#obfuscateBoolean

Returns Whether the parameter must be obfuscated from logs or not.

Returns:

  • (Boolean)

    Whether the parameter must be obfuscated from logs or not



92
93
94
# File 'lib/openc3/packets/packet_item.rb', line 92

def obfuscate
  @obfuscate
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



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

def range
  @range
end

#read_conversionConversion

Conversion instance used when reading the PacketItem

Returns:



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

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



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

def required
  @required
end

#state_colorsHash

Colors associated with states

Returns:

  • (Hash)

    State colors given as STATE_NAME => COLOR



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

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



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

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



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

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



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

def units_full
  @units_full
end

#write_conversionConversion

Conversion instance used when writing the PacketItem

Returns:



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

def write_conversion
  @write_conversion
end

Instance Method Details

#as_json(*a) ⇒ Object



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
451
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
# File 'lib/openc3/packets/packet_item.rb', line 425

def as_json(*a)
  config = super(*a)
  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['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
  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

  config['limits'] ||= {}
  if self.limits.enabled
    config['limits']['enabled'] = true
  elsif self.limits.values || (self.state_colors && self.state_colors.length > 0)
    # Only set to false if there are limits or state colors
    # to avoid items without limits acting like they can be enabled
    config['limits']['enabled'] = false
  end
  if self.limits.values
    # Only set these if there are limits.values because persistence_setting has a default
    # and we don't want keys on the 'limits' hash if there aren't any limits
    config['limits']['persistence_setting'] = self.limits.persistence_setting if 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['meta'] = @meta if @meta
  config['obfuscate'] = self.obfuscate
  config
end

#calculate_rangeObject



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

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



204
205
206
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
238
239
240
# File 'lib/openc3/packets/packet_item.rb', line 204

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
      when :ARRAY
        raise ArgumentError, "#{@name}: default must be an Array but is a #{@default.class}" unless Array === @default
      when :OBJECT
        raise ArgumentError, "#{@name}: default must be an Hash but is a #{@default.class}" unless Hash === @default
      when :BOOL
        raise ArgumentError, "#{@name}: default must be true/false but is a #{@default.class}" unless TrueClass === @default or FalseClass === @default
      end
    end
  end
end

#cloneObject Also known as: dup

Make a light weight clone of this item



307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/openc3/packets/packet_item.rb', line 307

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.obfuscate = self.obfuscate.clone if @obfuscate
  item
end

#metaObject



292
293
294
# File 'lib/openc3/packets/packet_item.rb', line 292

def meta
  @meta ||= {}
end

#meta=(meta) ⇒ Object



296
297
298
299
300
301
302
303
304
# File 'lib/openc3/packets/packet_item.rb', line 296

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



350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
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
# File 'lib/openc3/packets/packet_item.rb', line 350

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
  config << "    OBFUSCATE\n" if self.obfuscate

  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.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
    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