Class: SDN::Message

Inherits:
Object
  • Object
show all
Includes:
Helpers
Defined in:
lib/sdn/message.rb,
lib/sdn/messages/get.rb,
lib/sdn/messages/set.rb,
lib/sdn/messages/post.rb,
lib/sdn/messages/control.rb,
lib/sdn/messages/helpers.rb

Defined Under Namespace

Modules: Helpers Classes: Ack, GetGroupAddr, GetMotorDirection, GetMotorIP, GetMotorLimits, GetMotorPosition, GetMotorRollingSpeed, GetMotorStatus, GetNodeAddr, GetNodeLabel, GetNodeSerialNumber, GetNodeStackVersion, Move, MoveOf, MoveTo, Nack, PostGroupAddr, PostMotorDirection, PostMotorIP, PostMotorLimits, PostMotorPosition, PostMotorRollingSpeed, PostMotorStatus, PostNodeAddr, PostNodeLabel, PostNodeSerialNumber, PostNodeStackVersion, SetFactoryDefault, SetGroupAddr, SetMotorDirection, SetMotorIP, SetMotorLimits, SetMotorRollingSpeed, SetNodeLabel, SimpleRequest, Stop, UnknownMessage, Wink

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers

#checksum, #from_number, #from_string, #is_group_address?, #parse_address, #print_address, #to_number, #to_string, #transform_param

Constructor Details

#initialize(reserved: nil, ack_requested: false, src: nil, dest: nil) ⇒ Message

Returns a new instance of Message.



54
55
56
57
58
59
60
61
62
63
# File 'lib/sdn/message.rb', line 54

def initialize(reserved: nil, ack_requested: false, src: nil, dest: nil)
  @reserved = reserved || 0x02 # message sent to Sonesse 30
  @ack_requested = ack_requested
  if src.nil? && is_group_address?(dest)
    src = dest
    dest = nil
  end
  @src = src || [0, 0, 1]
  @dest = dest || [0, 0, 0]
end

Instance Attribute Details

#ack_requestedObject (readonly)

Returns the value of attribute ack_requested.



52
53
54
# File 'lib/sdn/message.rb', line 52

def ack_requested
  @ack_requested
end

#destObject (readonly)

Returns the value of attribute dest.



52
53
54
# File 'lib/sdn/message.rb', line 52

def dest
  @dest
end

#reservedObject (readonly)

Returns the value of attribute reserved.



52
53
54
# File 'lib/sdn/message.rb', line 52

def reserved
  @reserved
end

#srcObject (readonly)

Returns the value of attribute src.



52
53
54
# File 'lib/sdn/message.rb', line 52

def src
  @src
end

Class Method Details

.parse(data) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/sdn/message.rb', line 8

def parse(data)
  offset = -1
  msg = length = ack_requested = message_class = nil
  # we loop here scanning for a valid message
  loop do
    offset += 1
    return nil if data.length - offset < 11
    msg = to_number(data[offset])
    length = to_number(data[offset + 1])
    ack_requested = length & 0x80 == 0x80
    length &= 0x7f
    # impossible message
    next if length < 11 || length > 32
    # don't have enough data for what this message wants;
    # it could be garbage on the line so keep scanning
    next if length > data.length - offset

    message_class = constants.find { |c| (const_get(c, false).const_get(:MSG, false) rescue nil) == msg }
    message_class = const_get(message_class, false) if message_class
    message_class ||= UnknownMessage

    calculated_sum = checksum(data.slice(offset, length - 2))
    read_sum = data.slice(offset + length - 2, 2)
    next unless read_sum == calculated_sum

    break
  end

  puts "discarding invalid data prior to message #{data[0...offset].map { |b| '%02x' % b }.join(' ')}" unless offset == 0
  puts "read #{data.slice(offset, length).map { |b| '%02x' % b }.join(' ')}"

  reserved = to_number(data[offset + 2])
  src = transform_param(data.slice(offset + 3, 3))
  dest = transform_param(data.slice(offset + 6, 3))
  result = message_class.new(reserved: reserved, ack_requested: ack_requested, src: src, dest: dest)
  result.parse(data.slice(offset + 9, length - 11))
  result.msg = msg if message_class == UnknownMessage
  [result, offset + length]
end

Instance Method Details

#class_inspectObject



83
84
85
86
87
# File 'lib/sdn/message.rb', line 83

def class_inspect
  ivars = instance_variables - [:@reserved, :@ack_requested, :@src, :@dest]
  return if ivars.empty?
  ivars.map { |iv| ", #{iv}=#{instance_variable_get(iv).inspect}" }.join
end

#inspectObject



79
80
81
# File 'lib/sdn/message.rb', line 79

def inspect
  "#<%s @reserved=%02xh, @ack_requested=%s, @src=%s, @dest=%s%s>" % [self.class.name, reserved, ack_requested, print_address(src), print_address(dest), class_inspect]
end

#parse(params) ⇒ Object

Raises:



65
66
67
# File 'lib/sdn/message.rb', line 65

def parse(params)
  raise MalformedMessage, "unrecognized params for #{self.class.name}: #{params.map { |b| '%02x' % b }}" if self.class.const_defined?(:PARAMS_LENGTH) && params.length != self.class.const_get(:PARAMS_LENGTH)
end

#serializeObject



69
70
71
72
73
74
75
76
77
# File 'lib/sdn/message.rb', line 69

def serialize
  result = transform_param(reserved) + transform_param(src) + transform_param(dest) + params
  length = result.length + 4
  length |= 0x80 if ack_requested
  result = transform_param(self.class.const_get(:MSG)) + transform_param(length) + result
  result.concat(checksum(result))
  puts "wrote #{result.map { |b| '%02x' % b }.join(' ')}"
  result.pack("C*")
end