Class: SDN::Client
- Inherits:
-
Object
- Object
- SDN::Client
- Defined in:
- lib/sdn/client.rb
Overview
Transport client for sending and receiving SDN frames over serial, TCP, RFC2217, or PTY.
Constant Summary collapse
- WAIT_TIME =
Default inter-read wait time, in seconds, while assembling a partial frame.
0.25
Instance Attribute Summary collapse
-
#trace ⇒ true, false
writeonly
Enables or disables raw byte tracing in the client logs.
Instance Method Summary collapse
-
#ensure(message) ⇒ SDN::Message
Re-sends a request until an expected response is received.
-
#initialize(port) ⇒ Client
constructor
Opens a connection to an SDN bus over serial, TCP, RFC2217, or PTY.
-
#receive(timeout = nil) {|message| ... } ⇒ <SDN::Message>
Reads and parses messages from the transport until parsing is exhausted or a timeout occurs.
-
#send(message) ⇒ void
Serializes and writes a message to the underlying transport.
-
#trace? ⇒ true, false
Indicates whether raw byte tracing is enabled.
-
#transact(message) ⇒ <SDN::Message>
Sends a message with acknowledgement requested and waits for an initial response batch.
Constructor Details
#initialize(port) ⇒ Client
Opens a connection to an SDN bus over serial, TCP, RFC2217, or PTY.
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 |
# File 'lib/sdn/client.rb', line 16 def initialize(port) uri = URI.parse(port) @io = if uri.scheme == "tcp" require "socket" TCPSocket.new(uri.host, uri.port) elsif %w[telnet rfc2217].include?(uri.scheme) require "net/telnet/rfc2217" Net::Telnet::RFC2217.new(host: uri.host, port: uri.port || 23, baud: 4800, data_bits: 8, parity: :odd, stop_bits: 1) elsif port == "/dev/ptmx" require "pty" io, slave = PTY.open puts "Slave PTY available at #{slave.path}" io elsif uri.scheme == "esphome" gem "esphome", "~> 1.1" require "esphome/serial_proxy" ESPHome::SerialProxy.open(uri, baud: 4800, data_bits: 8, parity: :odd, stop_bits: 1) else require "ccutrer-serialport" CCutrer::SerialPort.new(port, baud: 4800, data_bits: 8, parity: :odd, stop_bits: 1) end @buffer = +"" end |
Instance Attribute Details
#trace=(value) ⇒ true, false (writeonly)
Enables or disables raw byte tracing in the client logs.
11 12 13 |
# File 'lib/sdn/client.rb', line 11 def trace=(value) @trace = value end |
Instance Method Details
#ensure(message) ⇒ SDN::Message
Re-sends a request until an expected response is received.
The expected response message is dependent on the message sent.
80 81 82 83 84 85 86 87 88 |
# File 'lib/sdn/client.rb', line 80 def ensure() loop do = transact() next if .empty? next unless .class.expected_response?(.first) return .first end end |
#receive(timeout = nil) {|message| ... } ⇒ <SDN::Message>
Reads and parses messages from the transport until parsing is exhausted or a timeout occurs.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/sdn/client.rb', line 101 def receive(timeout = nil) = [] loop do , bytes_read = Message.parse(@buffer.bytes) # discard how much we read @buffer = @buffer[bytes_read..] if bytes_read unless break unless .empty? # one EOF is just serial ports saying they have no data; # several EOFs in a row is the file is dead and gone eofs = 0 begin block = @io.read_nonblock(64 * 1024) SDN.logger.debug("Read #{block.unpack1("H*").gsub(/\h{2}/, "\\0 ")}") if trace? @buffer.concat(block) next rescue IO::WaitReadable, EOFError => e if e.is_a?(EOFError) eofs += 1 else eofs = 0 end raise if eofs == 5 wait = @buffer.empty? ? timeout : WAIT_TIME if @io.wait_readable(wait).nil? # timed out; just discard everything unless @buffer.empty? SDN.logger.debug "Discarding #{@buffer.unpack1("H*").gsub(/\h{2}/, "\\0 ")} due to timeout" end @buffer = +"" return if timeout end retry end next end SDN.logger.debug("Received message #{.inspect}") if block_given? yield else << end end end |
#send(message) ⇒ void
This method returns an undefined value.
Serializes and writes a message to the underlying transport.
57 58 59 60 |
# File 'lib/sdn/client.rb', line 57 def send() SDN.logger.debug("Sending #{.inspect}") @io.write(.serialize) end |
#trace? ⇒ true, false
Indicates whether raw byte tracing is enabled.
48 49 50 |
# File 'lib/sdn/client.rb', line 48 def trace? @trace end |
#transact(message) ⇒ <SDN::Message>
Sends a message with acknowledgement requested and waits for an initial response batch.
67 68 69 70 71 |
# File 'lib/sdn/client.rb', line 67 def transact() .ack_requested = true send() receive(1) end |