Class: SDN::Message
- Inherits:
-
Object
- Object
- SDN::Message
- 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
Direct Known Subclasses
Ack, GetGroupAddr, GetMotorIP, GetNodeAddr, Move, MoveOf, MoveTo, Nack, PostGroupAddr, PostMotorDirection, PostMotorIP, PostMotorLimits, PostMotorPosition, PostMotorRollingSpeed, PostMotorStatus, PostNodeAddr, PostNodeLabel, PostNodeSerialNumber, SetFactoryDefault, SetGroupAddr, SetMotorDirection, SetMotorIP, SetMotorLimits, SetMotorRollingSpeed, SetNodeLabel, SimpleRequest, Stop, UnknownMessage
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
-
#ack_requested ⇒ Object
readonly
Returns the value of attribute ack_requested.
-
#dest ⇒ Object
readonly
Returns the value of attribute dest.
-
#reserved ⇒ Object
readonly
Returns the value of attribute reserved.
-
#src ⇒ Object
readonly
Returns the value of attribute src.
Class Method Summary collapse
Instance Method Summary collapse
- #class_inspect ⇒ Object
-
#initialize(reserved: nil, ack_requested: false, src: nil, dest: nil) ⇒ Message
constructor
A new instance of Message.
- #inspect ⇒ Object
- #parse(params) ⇒ Object
- #serialize ⇒ Object
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.
89 90 91 92 93 94 95 96 97 98 |
# File 'lib/sdn/message.rb', line 89 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_requested ⇒ Object (readonly)
Returns the value of attribute ack_requested.
87 88 89 |
# File 'lib/sdn/message.rb', line 87 def ack_requested @ack_requested end |
#dest ⇒ Object (readonly)
Returns the value of attribute dest.
87 88 89 |
# File 'lib/sdn/message.rb', line 87 def dest @dest end |
#reserved ⇒ Object (readonly)
Returns the value of attribute reserved.
87 88 89 |
# File 'lib/sdn/message.rb', line 87 def reserved @reserved end |
#src ⇒ Object (readonly)
Returns the value of attribute src.
87 88 89 |
# File 'lib/sdn/message.rb', line 87 def src @src end |
Class Method Details
.parse(io) ⇒ Object
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/sdn/message.rb', line 23 def parse(io) io = StringIO.new(io) if io.is_a?(String) data = readpartial(io, 2, allow_empty: false) if data.length != 2 # don't have enough data yet; buffer it io.ungetbyte(data.first) if data.length == 1 raise MalformedMessage, "Could not get message type and length" end msg = to_number(data.first) length = to_number(data.last) ack_requested = length & 0x80 == 0x80 length &= 0x7f if length < 11 || length > 32 # only skip over one byte to try and re-sync io.ungetbyte(data.last) raise MalformedMessage, "Message has bogus length: #{length}" end data.concat(readpartial(io, length - 4)) unless data.length == length - 2 data.reverse.each { |byte| io.ungetbyte(byte) } raise MalformedMessage, "Missing data: got #{data.length} expected #{length}" end = constants.find { |c| (const_get(c, false).const_get(:MSG, false) rescue nil) == msg } = const_get(, false) if ||= UnknownMessage bogus_checksums = [SetNodeLabel::MSG, PostNodeLabel::MSG].include?(msg) calculated_sum = checksum(data) read_sum = readpartial(io, 2) if read_sum.length == 0 || (!bogus_checksums && read_sum.length == 1) read_sum.each { |byte| io.ungetbyte(byte) } data.reverse.each { |byte| io.ungetbyte(byte) } raise MalformedMessage, "Missing data: got #{data.length} expected #{length}" end # check both the proper checksum, and a truncated checksum unless calculated_sum == read_sum || (bogus_checksums && calculated_sum.last == read_sum.first) = (data + read_sum).map { |b| '%02x' % b }.join(' ') # skip over single byte to try and re-sync data.shift read_sum.reverse.each { |byte| io.ungetbyte(byte) } data.reverse.each { |byte| io.ungetbyte(byte) } raise MalformedMessage, "Checksum mismatch for #{.name}: #{}" end # the checksum was truncated; put back the unused byte io.ungetbyte(read_sum.last) if calculated_sum != read_sum && read_sum.length == 2 puts "read #{(data + read_sum).map { |b| '%02x' % b }.join(' ')}" reserved = to_number(data[2]) src = transform_param(data[3..5]) dest = transform_param(data[6..8]) result = .new(reserved: reserved, ack_requested: ack_requested, src: src, dest: dest) result.parse(data[9..-1]) result.msg = msg if == UnknownMessage result end |
.readpartial(io, length, allow_empty: true) ⇒ Object
8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/sdn/message.rb', line 8 def readpartial(io, length, allow_empty: true) data = [] while data.length < length begin data.concat(io.read_nonblock(length - data.length).bytes) rescue EOFError break rescue IO::WaitReadable break if allow_empty IO.select([io]) end end data end |
Instance Method Details
#class_inspect ⇒ Object
118 119 120 121 122 |
# File 'lib/sdn/message.rb', line 118 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 |
#inspect ⇒ Object
114 115 116 |
# File 'lib/sdn/message.rb', line 114 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
100 101 102 |
# File 'lib/sdn/message.rb', line 100 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 |
#serialize ⇒ Object
104 105 106 107 108 109 110 111 112 |
# File 'lib/sdn/message.rb', line 104 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 |