class LXP::Packet::Base

Attributes

chksum[RW]

2 bytes

data[RW]

usually 16 bytes?

header[RW]

20 bytes

Public Class Methods

new() click to toggle source
# File lib/lxp/packet/base.rb, line 18
def initialize
  @header ||= [0] * 20
  @data ||= [0] * 16
  @chksum ||= [0, 0]

  # prefix
  @header[0] = 161
  @header[1] = 26

  self.protocol = 1

  self.packet_length = 32

  @header[6] = 1 # unsure, always seems to be 1
end
parse(ascii) click to toggle source
# File lib/lxp/packet/base.rb, line 43
def self.parse(ascii)
  # array of integers
  bdata = ascii.unpack('C*')

  raise 'invalid packet' if bdata[0] != 161 || bdata[1] != 26

  i = new

  # header is always 20 bytes
  i.header[0, 20] = bdata[0, 20]

  # data can vary from 17 bytes upwards
  i.data = bdata[20, i.data_length - 2] # -2, don't copy checksum
  raise 'bad data length' unless i.data.length != i.data_length

  # calculate checksum and compare to input
  i.update_checksum
  raise 'invalid checksum' if i.chksum != bdata[-2..-1]

  i
end

Public Instance Methods

bytes() click to toggle source
# File lib/lxp/packet/base.rb, line 34
def bytes
  update_checksum
  header + data + chksum
end
data_length() click to toggle source
# File lib/lxp/packet/base.rb, line 100
def data_length
  @header[18] | @header[19] << 8
end
data_length=(data_length) click to toggle source
# File lib/lxp/packet/base.rb, line 104
def data_length=(data_length)
  @header[18] = data_length & 0xff
  @header[19] = (data_length >> 8) & 0xff
end
datalog_serial() click to toggle source
# File lib/lxp/packet/base.rb, line 91
def datalog_serial
  @header[8, 10].pack('C*')
end
datalog_serial=(datalog_serial) click to toggle source

Passed as a string

# File lib/lxp/packet/base.rb, line 96
def datalog_serial=(datalog_serial)
  @header[8, 10] = datalog_serial.bytes
end
device_function() click to toggle source
# File lib/lxp/packet/base.rb, line 109
def device_function
  @data[1]
end
device_function=(device_function) click to toggle source
# File lib/lxp/packet/base.rb, line 113
def device_function=(device_function)
  @data[1] = device_function
end
inverter_serial() click to toggle source
# File lib/lxp/packet/base.rb, line 117
def inverter_serial
  @data[2, 10].pack('C*')
end
inverter_serial=(inverter_serial) click to toggle source

Passed as a string

# File lib/lxp/packet/base.rb, line 122
def inverter_serial=(inverter_serial)
  @data[2, 10] = inverter_serial.bytes
end
packet_length() click to toggle source
# File lib/lxp/packet/base.rb, line 74
def packet_length
  @header[4] | @header[5] << 8
end
packet_length=(packet_length) click to toggle source
# File lib/lxp/packet/base.rb, line 78
def packet_length=(packet_length)
  @header[4] = packet_length & 0xff
  @header[5] = (packet_length >> 8) & 0xff
end
protocol() click to toggle source
# File lib/lxp/packet/base.rb, line 65
def protocol
  @header[2] | @header[3] << 8
end
protocol=(protocol) click to toggle source
# File lib/lxp/packet/base.rb, line 69
def protocol=(protocol)
  @header[2] = protocol & 0xff
  @header[3] = (protocol >> 8) & 0xff
end
register() click to toggle source
# File lib/lxp/packet/base.rb, line 126
def register
  @data[12] | @data[13] << 8
end
register=(register) click to toggle source
# File lib/lxp/packet/base.rb, line 130
def register=(register)
  @data[12] = register & 0xff
  @data[13] = (register >> 8) & 0xff
end
tcp_function() click to toggle source
# File lib/lxp/packet/base.rb, line 83
def tcp_function
  @header[7]
end
tcp_function=(tcp_function) click to toggle source
# File lib/lxp/packet/base.rb, line 87
def tcp_function=(tcp_function)
  @header[7] = tcp_function & 0xff
end
to_bin() click to toggle source
# File lib/lxp/packet/base.rb, line 39
def to_bin
  bytes.pack('C*')
end
update_checksum() click to toggle source
# File lib/lxp/packet/base.rb, line 165
def update_checksum
  chksum = crc16_modbus(data)
  @chksum[0] = chksum & 0xff
  @chksum[1] = (chksum >> 8) & 0xff
end
value=(value) click to toggle source

this only makes sense for protocol 1 at the moment. for 2 we'd need to append to an array, and not sure that is even used (sending an array of values to inverter) (maybe with W_MULTI?)

# File lib/lxp/packet/base.rb, line 158
def value=(value)
  raise 'cannot set value with protocol 2 yet' if protocol == 2

  @data[14] = value & 0xff
  @data[15] = (value >> 8) & 0xff
end
value_length() click to toggle source
# File lib/lxp/packet/base.rb, line 135
def value_length
  if value_length_byte?
    @data[14]
  else
    2
  end
end
values() click to toggle source

protocol 1 has value at 14 and 15 protocol 2 has length at 14, then that many bytes of values

# File lib/lxp/packet/base.rb, line 146
def values
  if value_length_byte?
    @data[15, value_length]
  else
    @data[14, 2] # | @data[15] << 8
  end
end

Private Instance Methods

crc16_modbus(arr) click to toggle source
# File lib/lxp/packet/base.rb, line 179
def crc16_modbus(arr)
  arr.length.times.inject(0xffff) do |r, n|
    r ^= arr[n]
    8.times do
      t = r >> 1
      r = (r & 1).positive? ? 40_961 ^ t : t
    end
    r
  end
end
value_length_byte?() click to toggle source
# File lib/lxp/packet/base.rb, line 173
def value_length_byte?
  @value_length_byte ||=
    protocol == 2 &&
    device_function != DeviceFunctions::WRITE_SINGLE
end