socket_switcher 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.utilsrc +26 -0
- data/Gemfile +8 -0
- data/README.md +0 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/arduino-receiver/receiver/receiver.ino +36 -0
- data/arduino/lib/.holder +0 -0
- data/arduino/lib/RCSwitch/RCSwitch.cpp +823 -0
- data/arduino/lib/RCSwitch/RCSwitch.h +144 -0
- data/arduino/lib/RCSwitch/examples/ReceiveDemo_Advanced/ReceiveDemo_Advanced.pde +24 -0
- data/arduino/lib/RCSwitch/examples/ReceiveDemo_Advanced/helperfunctions.ino +20 -0
- data/arduino/lib/RCSwitch/examples/ReceiveDemo_Advanced/output.ino +52 -0
- data/arduino/lib/RCSwitch/examples/ReceiveDemo_Simple/ReceiveDemo_Simple.pde +35 -0
- data/arduino/lib/RCSwitch/examples/SendDemo/SendDemo.pde +57 -0
- data/arduino/lib/RCSwitch/examples/TypeA_WithDIPSwitches/TypeA_WithDIPSwitches.pde +40 -0
- data/arduino/lib/RCSwitch/examples/TypeA_WithDIPSwitches_Lightweight/TypeA_WithDIPSwitches_Lightweight.ino +43 -0
- data/arduino/lib/RCSwitch/examples/TypeB_WithRotaryOrSlidingSwitches/TypeB_WithRotaryOrSlidingSwitches.pde +40 -0
- data/arduino/lib/RCSwitch/examples/TypeC_Intertechno/TypeC_Intertechno.pde +40 -0
- data/arduino/lib/RCSwitch/examples/TypeD_REV/TypeD_REV.ino +41 -0
- data/arduino/lib/RCSwitch/examples/Webserver/Webserver.pde +154 -0
- data/arduino/lib/RCSwitch/keywords.txt +57 -0
- data/arduino/src/switcher/switcher.ino.erb +79 -0
- data/config/default.yml +11 -0
- data/config/traffic_lights.yml +8 -0
- data/examples/blinkenlights.rb +25 -0
- data/lib/socket_switcher.rb +7 -0
- data/lib/socket_switcher/device.rb +24 -0
- data/lib/socket_switcher/errors.rb +26 -0
- data/lib/socket_switcher/port.rb +134 -0
- data/lib/socket_switcher/version.rb +8 -0
- data/socket_switcher.gemspec +49 -0
- data/spec/socket_switcher/device_spec.rb +37 -0
- data/spec/socket_switcher/port_spec.rb +216 -0
- data/spec/spec_helper.rb +9 -0
- metadata +176 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
module SocketSwitcher
|
2
|
+
class SocketSwitcherError < StandardError
|
3
|
+
def self.for_device(device, message)
|
4
|
+
new(message).tap do |error|
|
5
|
+
error.device = device
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.wrap(device, exception)
|
10
|
+
for_device(device, "wrapped #{exception.class}: #{exception}").tap do |e|
|
11
|
+
e.set_backtrace exception.backtrace
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_accessor :device
|
16
|
+
end
|
17
|
+
|
18
|
+
class CommunicationError < SocketSwitcherError
|
19
|
+
end
|
20
|
+
|
21
|
+
class InvalidResponse < SocketSwitcherError
|
22
|
+
end
|
23
|
+
|
24
|
+
class TryAgainError < SocketSwitcherError
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'serialport'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
class SocketSwitcher::Port
|
5
|
+
def initialize(specifier, debug: false, timeout: 2_000, attempts: 3)
|
6
|
+
@serial_port = SerialPort.new(
|
7
|
+
specifier,
|
8
|
+
"baud" => 9600,
|
9
|
+
"data_bits" => 8,
|
10
|
+
"stop_bits" => 1,
|
11
|
+
"parity" => 0
|
12
|
+
)
|
13
|
+
@debug = debug
|
14
|
+
@timeout = timeout
|
15
|
+
@attempts = attempts
|
16
|
+
@devices = {}
|
17
|
+
@mutex = Mutex.new
|
18
|
+
rescue => e
|
19
|
+
raise SocketSwitcher::CommunicationError.wrap(nil, e)
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_accessor :debug
|
23
|
+
|
24
|
+
attr_accessor :timeout
|
25
|
+
|
26
|
+
def ready?
|
27
|
+
request do |response|
|
28
|
+
if response =~ /^RDY (\d+) (\d+)/
|
29
|
+
# initalize all devices
|
30
|
+
($1.to_i..$2.to_i).each { |i| device(i) }
|
31
|
+
return true
|
32
|
+
else
|
33
|
+
try_again or return false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def devices(range = nil)
|
39
|
+
if range
|
40
|
+
devices.select { |d| range.member?(d.number) }
|
41
|
+
else
|
42
|
+
ready?
|
43
|
+
@devices.values
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def device(number)
|
48
|
+
@devices[number] ||= SocketSwitcher::Device.new(self, number)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def debug_output(message)
|
54
|
+
if debug
|
55
|
+
STDERR.puts message
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def set_state(device, state)
|
60
|
+
request(device, state) do |response|
|
61
|
+
case response
|
62
|
+
when /^ACK/
|
63
|
+
return true
|
64
|
+
when /^RDY/
|
65
|
+
try_again SocketSwitcher::TryAgainError.for_device(
|
66
|
+
device, "not ready after #@attempt attempts"
|
67
|
+
)
|
68
|
+
when /^NAK device/
|
69
|
+
raise SocketSwitcher::InvalidResponse.for_device(
|
70
|
+
device, "invalid device number: #{device.number}")
|
71
|
+
when /^NAK state/
|
72
|
+
raise SocketSwitcher::InvalidResponse.for_device(
|
73
|
+
device, "invalid state number: #{state}")
|
74
|
+
else
|
75
|
+
try_again SocketSwitcher::TryAgainError.for_device(
|
76
|
+
device, "unexpected response #{response.inspect} after #@attempt attempts")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def synchronize(&block)
|
82
|
+
@mutex.synchronize(&block)
|
83
|
+
end
|
84
|
+
|
85
|
+
def try_again(exception = nil)
|
86
|
+
if @attempt < @attempts
|
87
|
+
@attempt += 1
|
88
|
+
sleep @timeout.to_f / 1000
|
89
|
+
throw :again
|
90
|
+
elsif exception
|
91
|
+
raise exception
|
92
|
+
else
|
93
|
+
return false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def set_timeout
|
98
|
+
@serial_port.read_timeout = @timeout
|
99
|
+
begin
|
100
|
+
@serial_port.write_timeout = @timeout
|
101
|
+
rescue NotImplementedError
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def request(device = nil, state = nil, &block)
|
106
|
+
synchronize do
|
107
|
+
begin
|
108
|
+
@attempt = 1
|
109
|
+
loop do
|
110
|
+
set_timeout
|
111
|
+
catch :again do
|
112
|
+
query = ''
|
113
|
+
device && state and query << "#{device.number} #{state}"
|
114
|
+
query << "\r\n"
|
115
|
+
debug_output "<< #{query.inspect}"
|
116
|
+
@serial_port.print(query)
|
117
|
+
unless response = @serial_port.gets
|
118
|
+
try_again SocketSwitcher::TryAgainError.for_device(
|
119
|
+
device, "timeout after #@attempt attempts"
|
120
|
+
)
|
121
|
+
end
|
122
|
+
debug_output ">> #{response.inspect}"
|
123
|
+
block[response]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
rescue => e
|
127
|
+
unless SocketSwitcher::SocketSwitcherError === e
|
128
|
+
e = SocketSwitcher::CommunicationError.wrap(device, e)
|
129
|
+
end
|
130
|
+
raise e
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
module SocketSwitcher
|
2
|
+
# SocketSwitcher version
|
3
|
+
VERSION = '0.1.0'
|
4
|
+
VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
|
5
|
+
VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
|
6
|
+
VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
|
7
|
+
VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
|
8
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# stub: socket_switcher 0.1.0 ruby lib
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "socket_switcher"
|
6
|
+
s.version = "0.1.0"
|
7
|
+
|
8
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
|
+
s.require_paths = ["lib"]
|
10
|
+
s.authors = ["Florian Frank"]
|
11
|
+
s.date = "2015-01-02"
|
12
|
+
s.description = "Switches devices on and off. Yes, it does\u{2026}"
|
13
|
+
s.email = "flori@ping.de"
|
14
|
+
s.extra_rdoc_files = ["README.md", "lib/socket_switcher.rb", "lib/socket_switcher/device.rb", "lib/socket_switcher/errors.rb", "lib/socket_switcher/port.rb", "lib/socket_switcher/version.rb"]
|
15
|
+
s.files = [".gitignore", ".rspec", ".utilsrc", "Gemfile", "README.md", "Rakefile", "VERSION", "arduino-receiver/receiver/receiver.ino", "arduino/lib/.holder", "arduino/lib/RCSwitch/RCSwitch.cpp", "arduino/lib/RCSwitch/RCSwitch.h", "arduino/lib/RCSwitch/examples/ReceiveDemo_Advanced/ReceiveDemo_Advanced.pde", "arduino/lib/RCSwitch/examples/ReceiveDemo_Advanced/helperfunctions.ino", "arduino/lib/RCSwitch/examples/ReceiveDemo_Advanced/output.ino", "arduino/lib/RCSwitch/examples/ReceiveDemo_Simple/ReceiveDemo_Simple.pde", "arduino/lib/RCSwitch/examples/SendDemo/SendDemo.pde", "arduino/lib/RCSwitch/examples/TypeA_WithDIPSwitches/TypeA_WithDIPSwitches.pde", "arduino/lib/RCSwitch/examples/TypeA_WithDIPSwitches_Lightweight/TypeA_WithDIPSwitches_Lightweight.ino", "arduino/lib/RCSwitch/examples/TypeB_WithRotaryOrSlidingSwitches/TypeB_WithRotaryOrSlidingSwitches.pde", "arduino/lib/RCSwitch/examples/TypeC_Intertechno/TypeC_Intertechno.pde", "arduino/lib/RCSwitch/examples/TypeD_REV/TypeD_REV.ino", "arduino/lib/RCSwitch/examples/Webserver/Webserver.pde", "arduino/lib/RCSwitch/keywords.txt", "arduino/src/switcher/switcher.ino.erb", "config/default.yml", "config/traffic_lights.yml", "examples/blinkenlights.rb", "lib/socket_switcher.rb", "lib/socket_switcher/device.rb", "lib/socket_switcher/errors.rb", "lib/socket_switcher/port.rb", "lib/socket_switcher/version.rb", "socket_switcher.gemspec", "spec/socket_switcher/device_spec.rb", "spec/socket_switcher/port_spec.rb", "spec/spec_helper.rb"]
|
16
|
+
s.homepage = "http://github.com/flori/socket_switcher"
|
17
|
+
s.licenses = ["GPL-2"]
|
18
|
+
s.rdoc_options = ["--title", "SocketSwitcher - Switches devices on and off", "--main", "README.md"]
|
19
|
+
s.rubygems_version = "2.2.2"
|
20
|
+
s.summary = "Switches devices on and off"
|
21
|
+
s.test_files = ["spec/socket_switcher/device_spec.rb", "spec/socket_switcher/port_spec.rb", "spec/spec_helper.rb"]
|
22
|
+
|
23
|
+
if s.respond_to? :specification_version then
|
24
|
+
s.specification_version = 4
|
25
|
+
|
26
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
27
|
+
s.add_development_dependency(%q<gem_hadar>, ["~> 1.1.2"])
|
28
|
+
s.add_development_dependency(%q<simplecov>, ["~> 0.9"])
|
29
|
+
s.add_development_dependency(%q<rspec>, ["~> 3.0"])
|
30
|
+
s.add_runtime_dependency(%q<tins>, ["~> 1.0"])
|
31
|
+
s.add_runtime_dependency(%q<serialport>, ["~> 1.3"])
|
32
|
+
s.add_runtime_dependency(%q<complex_config>, [">= 0"])
|
33
|
+
else
|
34
|
+
s.add_dependency(%q<gem_hadar>, ["~> 1.1.2"])
|
35
|
+
s.add_dependency(%q<simplecov>, ["~> 0.9"])
|
36
|
+
s.add_dependency(%q<rspec>, ["~> 3.0"])
|
37
|
+
s.add_dependency(%q<tins>, ["~> 1.0"])
|
38
|
+
s.add_dependency(%q<serialport>, ["~> 1.3"])
|
39
|
+
s.add_dependency(%q<complex_config>, [">= 0"])
|
40
|
+
end
|
41
|
+
else
|
42
|
+
s.add_dependency(%q<gem_hadar>, ["~> 1.1.2"])
|
43
|
+
s.add_dependency(%q<simplecov>, ["~> 0.9"])
|
44
|
+
s.add_dependency(%q<rspec>, ["~> 3.0"])
|
45
|
+
s.add_dependency(%q<tins>, ["~> 1.0"])
|
46
|
+
s.add_dependency(%q<serialport>, ["~> 1.3"])
|
47
|
+
s.add_dependency(%q<complex_config>, [">= 0"])
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SocketSwitcher::Device do
|
4
|
+
let :port do
|
5
|
+
double('Port')
|
6
|
+
end
|
7
|
+
|
8
|
+
let :device do
|
9
|
+
SocketSwitcher::Device.new(port, 23)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'knows about port' do
|
13
|
+
expect(device.port).to eq port
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'knows its own number' do
|
17
|
+
expect(device.number).to eq 23
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'sets state to 1 after receiving on' do
|
21
|
+
expect(port).to receive(:set_state).with(device, 1)
|
22
|
+
device.on
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'sets state to 0 after receiving off' do
|
26
|
+
expect(port).to receive(:set_state).with(device, 0)
|
27
|
+
device.off
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'has a nice #to_s' do
|
31
|
+
expect(device.to_s).to eq '#<SocketSwitcher::Device number=23>'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'has a nice #inspect' do
|
35
|
+
expect(device.inspect).to eq '#<SocketSwitcher::Device number=23>'
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SocketSwitcher::Port do
|
4
|
+
let :serial_port do
|
5
|
+
double('SerialPort').tap do |sp|
|
6
|
+
allow(sp).to receive(:read_timeout=)
|
7
|
+
allow(sp).to receive(:write_timeout=)
|
8
|
+
allow(sp).to receive(:print).with("\r\n")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
before do
|
13
|
+
allow(SerialPort).to receive(:new).and_return serial_port
|
14
|
+
end
|
15
|
+
|
16
|
+
let :port do
|
17
|
+
SocketSwitcher::Port.new('foo')
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'instantiation and configuration' do
|
21
|
+
it 'can be instantiated' do
|
22
|
+
expect(port).to be_a SocketSwitcher::Port
|
23
|
+
expect(port.debug).to eq false
|
24
|
+
expect(port.timeout).to eq 2_000
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'can be instantiated in debugging mode' do
|
28
|
+
expect(SocketSwitcher::Port.new('foo', debug: true).debug).to eq true
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'has a configurable debugging mode' do
|
32
|
+
port.debug = true
|
33
|
+
expect(port.debug).to eq true
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'can be instantiated with a timeout' do
|
37
|
+
expect(SocketSwitcher::Port.new('foo', timeout: 666).timeout).to eq 666
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'has a configurable timeout' do
|
41
|
+
port.timeout = 4_000
|
42
|
+
expect(port.timeout).to eq 4_000
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'wraps all unknown errors in SocketSwitcher::CommunicationError' do
|
46
|
+
expect(SerialPort).to receive(:new).and_raise(Errno::ENXIO)
|
47
|
+
expect { port }.to raise_error SocketSwitcher::CommunicationError
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#ready?' do
|
52
|
+
context 'sucessfull' do
|
53
|
+
before do
|
54
|
+
allow(serial_port).to receive(:gets).and_return("RDY 0 3\r\n")
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'can query the ready state' do
|
58
|
+
expect(port).to be_ready
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'with debugging' do
|
62
|
+
let :port do
|
63
|
+
SocketSwitcher::Port.new('foo', debug: true)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'can query the ready state with debugging' do
|
67
|
+
expect(STDERR).to receive(:puts).at_least(1)
|
68
|
+
expect(port).to receive(:debug_output).with('<< "\r\n"').and_call_original
|
69
|
+
expect(port).to receive(:debug_output).with('>> "RDY 0 3\r\n"').and_call_original
|
70
|
+
expect(port).to be_ready
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'some problem' do
|
76
|
+
it 'does not handle too many garbled responses, but returns false' do
|
77
|
+
expect(serial_port).to receive(:print).with("\r\n").at_least(1)
|
78
|
+
expect(serial_port).to receive(:gets).and_return("RD…garbled…").at_least(1)
|
79
|
+
expect(port).to receive(:sleep).with(port.timeout.to_f / 1000).at_least(1)
|
80
|
+
expect(port).not_to be_ready
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'timeout' do
|
86
|
+
let :serial_port do
|
87
|
+
double('SerialPort').tap do |sp|
|
88
|
+
allow(sp).to receive(:print).with("\r\n")
|
89
|
+
allow(sp).to receive(:gets).and_return("RDY 0 3\r\n")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'sets the read_timeout and write_timeout' do
|
94
|
+
expect(serial_port).to receive(:read_timeout=)
|
95
|
+
expect(serial_port).to receive(:write_timeout=)
|
96
|
+
expect(port).to be_ready
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'ingores not implemented write_timeout' do
|
100
|
+
expect(serial_port).to receive(:read_timeout=)
|
101
|
+
expect(serial_port).to receive(:write_timeout=).and_raise(NotImplementedError)
|
102
|
+
expect(port).to be_ready
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#devices' do
|
107
|
+
context 'successful' do
|
108
|
+
before do
|
109
|
+
allow(serial_port).to receive(:gets).and_return("RDY 0 3\r\n")
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'returns all supported devices' do
|
113
|
+
expect(port.devices.size).to eq 4
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'can return a range of devices' do
|
117
|
+
expect(port.devices(0..1).size).to eq 2
|
118
|
+
expect(port.devices([0, 3]).size).to eq 2
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'some problem' do
|
123
|
+
it 'returns all supported devices' do
|
124
|
+
expect(serial_port).to receive(:gets).and_return("RD…garbled…")
|
125
|
+
expect(serial_port).to receive(:gets).and_return("RDY 0 3\r\n")
|
126
|
+
expect(port).to receive(:sleep).with(port.timeout.to_f / 1000)
|
127
|
+
expect(port).to receive(:try_again).and_call_original
|
128
|
+
expect(port.devices.size).to eq 4
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe '#device' do
|
134
|
+
let :device do
|
135
|
+
port.device(23)
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'returns a device for number' do
|
139
|
+
expect(device.number).to eq 23
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'can be switched on' do
|
143
|
+
expect(serial_port).to receive(:print).with("23 1\r\n")
|
144
|
+
expect(serial_port).to receive(:gets).and_return("ACK\r\n")
|
145
|
+
expect(device.on).to eq true
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'can be switched off' do
|
149
|
+
expect(serial_port).to receive(:print).with("23 0\r\n")
|
150
|
+
expect(serial_port).to receive(:gets).and_return("ACK\r\n")
|
151
|
+
expect(device.off).to eq true
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'throws exceptions for device errors' do
|
155
|
+
expect(serial_port).to receive(:print).with("23 0\r\n")
|
156
|
+
expect(serial_port).to receive(:gets).and_return("NAK device\r\n")
|
157
|
+
expect { device.off }.to raise_error SocketSwitcher::InvalidResponse
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'throws exceptions for state errors' do
|
161
|
+
expect(serial_port).to receive(:print).with("23 1\r\n")
|
162
|
+
expect(serial_port).to receive(:gets).and_return("NAK state\r\n")
|
163
|
+
expect { device.on }.to raise_error SocketSwitcher::InvalidResponse
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'handles some garbled responses' do
|
167
|
+
expect(serial_port).to receive(:print).with("23 1\r\n").twice
|
168
|
+
expect(serial_port).to receive(:gets).and_return("RD…garbled…")
|
169
|
+
expect(port).to receive(:sleep).with(port.timeout.to_f / 1000)
|
170
|
+
expect(serial_port).to receive(:gets).and_return("ACK\r\n")
|
171
|
+
expect(device.on).to eq true
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'does not handle too many unexpected responses' do
|
175
|
+
expect(serial_port).to receive(:print).with("23 1\r\n").at_least(1)
|
176
|
+
expect(serial_port).to receive(:gets).and_return("RD…garbled…").at_least(1)
|
177
|
+
expect(port).to receive(:sleep).with(port.timeout.to_f / 1000).at_least(1)
|
178
|
+
expect { device.on }.to raise_error SocketSwitcher::TryAgainError
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'can handle some ready responses' do
|
182
|
+
expect(serial_port).to receive(:print).with("23 0\r\n").twice
|
183
|
+
expect(serial_port).to receive(:gets).and_return("RDY 0 3\r\n")
|
184
|
+
expect(port).to receive(:sleep).with(port.timeout.to_f / 1000)
|
185
|
+
expect(serial_port).to receive(:gets).and_return("ACK\r\n")
|
186
|
+
expect(device.off).to eq true
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'does not handle too many ready responses' do
|
190
|
+
expect(serial_port).to receive(:print).with("23 0\r\n").at_least(1)
|
191
|
+
expect(serial_port).to receive(:gets).and_return("RDY 0 3\r\n").at_least(1)
|
192
|
+
expect(port).to receive(:sleep).with(port.timeout.to_f / 1000).at_least(1)
|
193
|
+
expect { device.off }.to raise_error SocketSwitcher::TryAgainError
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'can handle some timeouts' do
|
197
|
+
expect(serial_port).to receive(:print).with("23 0\r\n").twice
|
198
|
+
expect(serial_port).to receive(:gets).and_return(nil)
|
199
|
+
expect(port).to receive(:sleep).with(port.timeout.to_f / 1000)
|
200
|
+
expect(serial_port).to receive(:gets).and_return("ACK\r\n")
|
201
|
+
expect(device.off).to eq true
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'does not handle too many ready responses' do
|
205
|
+
expect(serial_port).to receive(:print).with("23 0\r\n").at_least(1)
|
206
|
+
expect(serial_port).to receive(:gets).and_return(nil).at_least(1)
|
207
|
+
expect(port).to receive(:sleep).with(port.timeout.to_f / 1000).at_least(1)
|
208
|
+
expect { device.off }.to raise_error SocketSwitcher::TryAgainError
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'wraps all unknown errors in SocketSwitcher::CommunicationError' do
|
212
|
+
expect(serial_port).to receive(:print).and_raise(Errno::ENXIO)
|
213
|
+
expect { device.on }.to raise_error SocketSwitcher::CommunicationError
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|