somfy_sdn 1.0.12 → 2.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/somfy_sdn +60 -0
- data/lib/sdn/cli/mqtt/group.rb +31 -0
- data/lib/sdn/cli/mqtt/motor.rb +103 -0
- data/lib/sdn/cli/mqtt/read.rb +156 -0
- data/lib/sdn/cli/mqtt/subscriptions.rb +156 -0
- data/lib/sdn/cli/mqtt/write.rb +93 -0
- data/lib/sdn/cli/mqtt.rb +397 -0
- data/lib/sdn/cli/provisioner.rb +234 -0
- data/lib/sdn/cli/simulator.rb +197 -0
- data/lib/sdn/client.rb +86 -0
- data/lib/sdn/{messages → message}/control.rb +79 -38
- data/lib/sdn/{messages → message}/get.rb +48 -40
- data/lib/sdn/{messages → message}/helpers.rb +33 -3
- data/lib/sdn/message/ilt2/get.rb +48 -0
- data/lib/sdn/message/ilt2/master_control.rb +35 -0
- data/lib/sdn/message/ilt2/post.rb +127 -0
- data/lib/sdn/message/ilt2/set.rb +192 -0
- data/lib/sdn/{messages → message}/post.rb +127 -61
- data/lib/sdn/{messages → message}/set.rb +99 -84
- data/lib/sdn/message.rb +81 -30
- data/lib/sdn/version.rb +1 -1
- data/lib/sdn.rb +16 -1
- metadata +63 -26
- data/bin/sdn_mqtt_bridge +0 -5
- data/lib/sdn/messages/ilt2/get.rb +0 -9
- data/lib/sdn/messages/ilt2/post.rb +0 -18
- data/lib/sdn/messages/ilt2/set.rb +0 -59
- data/lib/sdn/mqtt_bridge.rb +0 -711
@@ -0,0 +1,197 @@
|
|
1
|
+
module SDN
|
2
|
+
module CLI
|
3
|
+
class Simulator
|
4
|
+
class MockMotor
|
5
|
+
attr_accessor :address, :node_type, :label, :ips, :position_pulses, :up_limit, :down_limit, :groups, :network_lock_priority, :lock_priority, :ir_channels
|
6
|
+
|
7
|
+
def initialize(client)
|
8
|
+
@client = client
|
9
|
+
self.address = Message.parse_address("00.00.00")
|
10
|
+
self.node_type = :st30
|
11
|
+
self.label = ""
|
12
|
+
self.ips = Array.new(16)
|
13
|
+
self.groups = Array.new(16)
|
14
|
+
self.ir_channels = 0
|
15
|
+
self.lock_priority = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def process
|
19
|
+
loop do
|
20
|
+
@client.receive do |message|
|
21
|
+
SDN.logger.info "Received #{message.inspect}"
|
22
|
+
next unless message.is_a?(Message::ILT2::MasterControl) ||
|
23
|
+
message.dest == address ||
|
24
|
+
message.dest == BROADCAST_ADDRESS
|
25
|
+
|
26
|
+
case message
|
27
|
+
when Message::GetGroupAddr
|
28
|
+
next nack(message) unless (1..16).include?(message.group_index)
|
29
|
+
respond(message.src, Message::PostGroupAddr.new(message.group_index, groups[message.group_index - 1]))
|
30
|
+
when Message::GetMotorIP
|
31
|
+
next nack(message) unless (1..16).include?(message.ip)
|
32
|
+
respond(message.src, Message::PostMotorIP.new(message.ip, ips[message.ip - 1], to_percent(ips[message.ip - 1])))
|
33
|
+
when Message::GetMotorLimits
|
34
|
+
respond(message.src, Message::PostMotorLimits.new(up_limit, down_limit))
|
35
|
+
when Message::GetMotorPosition
|
36
|
+
respond(message.src, Message::PostMotorPosition.new(
|
37
|
+
position_pulses,
|
38
|
+
to_percent(position_pulses),
|
39
|
+
ips.index(position_pulses)&.+(1)
|
40
|
+
))
|
41
|
+
when Message::GetNodeAddr; respond(message.src, Message::PostNodeAddr.new)
|
42
|
+
when Message::GetNodeLabel; respond(message.src, Message::PostNodeLabel.new(label))
|
43
|
+
when Message::ILT2::GetIRConfig; respond(message.src, Message::ILT2::PostIRConfig.new(ir_channels))
|
44
|
+
when Message::ILT2::GetLockStatus; respond(message.src, Message::ILT2::PostLockStatus.new(lock_priority))
|
45
|
+
when Message::ILT2::GetMotorIP; respond(message.src, Message::ILT2::PostMotorIP.new(message.ip, ips[message.ip - 1]))
|
46
|
+
when Message::ILT2::GetMotorPosition; respond(message.src, Message::ILT2::PostMotorPosition.new(position_pulses, to_percent(position_pulses)))
|
47
|
+
when Message::ILT2::GetMotorSettings; respond(message.src, Message::ILT2::PostMotorSettings.new(down_limit))
|
48
|
+
when Message::ILT2::SetIRConfig; self.ir_channels = message.channels
|
49
|
+
when Message::ILT2::SetLockStatus; self.lock_priority = message.priority
|
50
|
+
when Message::ILT2::SetMotorIP
|
51
|
+
next nack(message) unless (1..16).include?(message.ip)
|
52
|
+
ips[message.ip - 1] = message.value
|
53
|
+
ack(message)
|
54
|
+
when Message::ILT2::SetMotorPosition
|
55
|
+
next nack(message) unless down_limit
|
56
|
+
|
57
|
+
self.position_pulses = case message.target_type
|
58
|
+
when :up_limit; 0
|
59
|
+
when :down_limit; down_limit
|
60
|
+
when :ip
|
61
|
+
next nack(message) unless (1..16).include?(message.target)
|
62
|
+
next nack(message) unless ips[message.target]
|
63
|
+
ips[message.target]
|
64
|
+
when :position_pulses
|
65
|
+
next nack(message) if message.target - 1 > down_limit
|
66
|
+
message.target - 1
|
67
|
+
when :jog_up_pulses; [0, position_pulses - message.target].max
|
68
|
+
when :jog_down_pulses; [down_limit, position_pulses + message.target].min
|
69
|
+
when :position_percent
|
70
|
+
next nack(message) if message.target > 100
|
71
|
+
to_pulses(message.target.to_f)
|
72
|
+
end
|
73
|
+
ack(message)
|
74
|
+
when Message::ILT2::SetMotorSettings
|
75
|
+
if message.down_limit != 0
|
76
|
+
self.down_limit = message.down_limit
|
77
|
+
self.position_pulses = message.position_pulses
|
78
|
+
end
|
79
|
+
when Message::MoveTo
|
80
|
+
next nack(message) unless down_limit
|
81
|
+
next nack(message) unless %I{up_limit down_limit ip position_pulses position_percent}.include?(message.target_type)
|
82
|
+
|
83
|
+
self.position_pulses = case message.target_type
|
84
|
+
when :up_limit; 0
|
85
|
+
when :down_limit; down_limit;
|
86
|
+
when :ip
|
87
|
+
next nack(message) unless (1..16).include?(message.target)
|
88
|
+
next nack(message) unless ips[message.target - 1]
|
89
|
+
ips[message.target - 1]
|
90
|
+
when :position_pulses
|
91
|
+
next nack(message) if message.target > down_limit
|
92
|
+
message.target
|
93
|
+
when :position_percent
|
94
|
+
next nack(message) if message.target > 100
|
95
|
+
to_pulses(message.target)
|
96
|
+
end
|
97
|
+
ack(message)
|
98
|
+
when Message::SetGroupAddr
|
99
|
+
next nack(message) unless (1..16).include?(message.group_index)
|
100
|
+
groups[message.group_index - 1] = message.group_address == [0, 0, 0] ? nil : message.group_address
|
101
|
+
ack(message)
|
102
|
+
when Message::SetMotorIP
|
103
|
+
next nack(message) unless (1..16).include?(message.ip) || message.type == :distribute
|
104
|
+
|
105
|
+
case message.type
|
106
|
+
when :delete
|
107
|
+
ips[message.ip - 1] = nil
|
108
|
+
ack(message)
|
109
|
+
when :current_position
|
110
|
+
ips[message.ip - 1] = position_pulses
|
111
|
+
ack(message)
|
112
|
+
when :position_pulses
|
113
|
+
ips[message.ip - 1] = message.value
|
114
|
+
ack(message)
|
115
|
+
when :position_percent
|
116
|
+
pulses = to_pulses(message.value)
|
117
|
+
if pulses
|
118
|
+
ips[message.ip - 1] = pulses
|
119
|
+
ack(message)
|
120
|
+
else
|
121
|
+
nack(message)
|
122
|
+
end
|
123
|
+
when :distribute
|
124
|
+
next nack(message) unless down_limit
|
125
|
+
next nack(message) unless (1..15).include?(message.value)
|
126
|
+
span = down_limit / (message.value + 1)
|
127
|
+
current = 0
|
128
|
+
(0...message.value).each do |ip|
|
129
|
+
ips[ip] = (current += span)
|
130
|
+
end
|
131
|
+
(message.value...16).each do |ip|
|
132
|
+
ips[ip] = nil
|
133
|
+
end
|
134
|
+
ack(message)
|
135
|
+
end
|
136
|
+
when Message::SetMotorLimits
|
137
|
+
next nack(message) unless [:up, :down].include?(message.target)
|
138
|
+
next nack(message) unless [:jog_pulses].include?(message.type)
|
139
|
+
|
140
|
+
self.up_limit ||= 0
|
141
|
+
self.down_limit ||= 0
|
142
|
+
self.position_pulses ||= 0
|
143
|
+
|
144
|
+
next nack(message) if message.target == :up && position_pulses != 0
|
145
|
+
next nack(message) if message.target == :down && position_pulses != down_limit
|
146
|
+
|
147
|
+
case message.type
|
148
|
+
when :jog_pulses
|
149
|
+
self.down_limit += message.value
|
150
|
+
self.position_pulses += message.value if message.target == :down
|
151
|
+
end
|
152
|
+
ack(message)
|
153
|
+
when Message::SetNodeLabel; self.label = message.label; ack(message)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def to_percent(pulses)
|
160
|
+
pulses && down_limit ? 100.0 * pulses / down_limit : nil
|
161
|
+
end
|
162
|
+
|
163
|
+
def to_pulses(percent)
|
164
|
+
percent && down_limit ? down_limit * percent / 100 : nil
|
165
|
+
end
|
166
|
+
|
167
|
+
def ack(message)
|
168
|
+
return unless message.ack_requested
|
169
|
+
respond(Message::Ack.new(message.dest))
|
170
|
+
end
|
171
|
+
|
172
|
+
def nack(message, error_code = nil)
|
173
|
+
return unless message.ack_requested
|
174
|
+
respond(Message::Nack.new(message.dest))
|
175
|
+
end
|
176
|
+
|
177
|
+
def respond(dest, message)
|
178
|
+
message.src = address
|
179
|
+
message.node_type = node_type
|
180
|
+
message.dest = dest
|
181
|
+
SDN.logger.info "Sending #{message.inspect}"
|
182
|
+
@client.send(message)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def initialize(port, address = nil)
|
187
|
+
sdn = Client.new(port)
|
188
|
+
|
189
|
+
motor = MockMotor.new(sdn)
|
190
|
+
motor.address = Message.parse_address(address) if address
|
191
|
+
motor.node_type = :lt50
|
192
|
+
|
193
|
+
motor.process
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
data/lib/sdn/client.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'io/wait'
|
2
|
+
|
3
|
+
module SDN
|
4
|
+
class Client
|
5
|
+
def initialize(port)
|
6
|
+
uri = URI.parse(port)
|
7
|
+
@io = if uri.scheme == "tcp"
|
8
|
+
require 'socket'
|
9
|
+
TCPSocket.new(uri.host, uri.port)
|
10
|
+
elsif uri.scheme == "telnet" || uri.scheme == "rfc2217"
|
11
|
+
require 'net/telnet/rfc2217'
|
12
|
+
Net::Telnet::RFC2217.new(host: uri.host,
|
13
|
+
port: uri.port || 23,
|
14
|
+
baud: 4800,
|
15
|
+
data_bits: 8,
|
16
|
+
parity: :odd,
|
17
|
+
stop_bits: 1)
|
18
|
+
elsif port == "/dev/ptmx"
|
19
|
+
require 'pty'
|
20
|
+
io, slave = PTY.open
|
21
|
+
puts "Slave PTY available at #{slave.path}"
|
22
|
+
io
|
23
|
+
else
|
24
|
+
require 'ccutrer-serialport'
|
25
|
+
CCutrer::SerialPort.new(port, baud: 4800, data_bits: 8, parity: :odd, stop_bits: 1)
|
26
|
+
end
|
27
|
+
@buffer = ""
|
28
|
+
end
|
29
|
+
|
30
|
+
def send(message)
|
31
|
+
@io.write(message.serialize)
|
32
|
+
end
|
33
|
+
|
34
|
+
def transact(message)
|
35
|
+
message.ack_requested = true
|
36
|
+
send(message)
|
37
|
+
receive(1)
|
38
|
+
end
|
39
|
+
|
40
|
+
def ensure(message)
|
41
|
+
loop do
|
42
|
+
messages = transact(message)
|
43
|
+
next if messages.empty?
|
44
|
+
next unless message.class.expected_response?(messages.first)
|
45
|
+
return messages.first
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
WAIT_TIME = 0.25
|
50
|
+
|
51
|
+
def receive(timeout = nil)
|
52
|
+
messages = []
|
53
|
+
|
54
|
+
loop do
|
55
|
+
message, bytes_read = Message.parse(@buffer.bytes)
|
56
|
+
# discard how much we read
|
57
|
+
@buffer = @buffer[bytes_read..-1] if bytes_read
|
58
|
+
unless message
|
59
|
+
break unless messages.empty?
|
60
|
+
|
61
|
+
begin
|
62
|
+
block = @io.read_nonblock(64 * 1024)
|
63
|
+
SDN.logger.debug "read #{block.unpack("H*").first.gsub(/\h{2}/, "\\0 ")}"
|
64
|
+
@buffer.concat(block)
|
65
|
+
next
|
66
|
+
rescue IO::WaitReadable, EOFError
|
67
|
+
wait = @buffer.empty? ? timeout : WAIT_TIME
|
68
|
+
if @io.wait_readable(wait).nil?
|
69
|
+
# timed out; just discard everything
|
70
|
+
SDN.logger.debug "discarding #{@buffer.unpack("H*").first.gsub(/\h{2}/, "\\0 ")} due to timeout"
|
71
|
+
@buffer = ""
|
72
|
+
end
|
73
|
+
end
|
74
|
+
next
|
75
|
+
end
|
76
|
+
if block_given?
|
77
|
+
yield message
|
78
|
+
else
|
79
|
+
messages << message
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
messages
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -1,5 +1,46 @@
|
|
1
1
|
module SDN
|
2
2
|
class Message
|
3
|
+
class Lock < Message
|
4
|
+
MSG = 0x06
|
5
|
+
PARAMS_LENGTH = 5
|
6
|
+
TARGET_TYPE = { current: 0, up_limit: 1, down_limit: 2, ip: 4, unlock: 5, position_percent: 7 }
|
7
|
+
|
8
|
+
attr_reader :target_type, :target, :priority
|
9
|
+
|
10
|
+
def initialize(dest = nil, target_type = :unlock, target = nil, priority = 1, **kwargs)
|
11
|
+
kwargs[:dest] ||= dest
|
12
|
+
super(**kwargs)
|
13
|
+
self.target_type = target_type
|
14
|
+
self.target = target
|
15
|
+
self.priority = priority
|
16
|
+
end
|
17
|
+
|
18
|
+
def target_type=(value)
|
19
|
+
raise ArgumentError, "target_type must be one of :current, :up_limit, :down_limit, :ip, :unlock, or :position_percent" unless TARGET_TYPE.keys.include?(value)
|
20
|
+
@target_type = value
|
21
|
+
end
|
22
|
+
|
23
|
+
def target=(value)
|
24
|
+
@target = value&. & 0xffff
|
25
|
+
end
|
26
|
+
|
27
|
+
def priority=(value)
|
28
|
+
@priority = value & 0xff
|
29
|
+
end
|
30
|
+
|
31
|
+
def parse(params)
|
32
|
+
super
|
33
|
+
self.target_type = TARGET_TYPE.invert[to_number(params[0])]
|
34
|
+
target = to_number(params[1..2], nillable: true)
|
35
|
+
self.target = target
|
36
|
+
self.priority = to_number(params[3])
|
37
|
+
end
|
38
|
+
|
39
|
+
def params
|
40
|
+
transform_param(TARGET_TYPE[target_type]) + from_number(target, 2) + transform_param(priority) + transform_param(0)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
3
44
|
# Move in momentary mode
|
4
45
|
class Move < Message
|
5
46
|
MSG = 0x01
|
@@ -32,7 +73,7 @@ module SDN
|
|
32
73
|
end
|
33
74
|
|
34
75
|
def duration=(value)
|
35
|
-
raise ArgumentError, "duration must be in range 0x0a to 0xff (#{value})"
|
76
|
+
raise ArgumentError, "duration must be in range 0x0a to 0xff (#{value})" if value && (value < 0x0a || value > 0xff)
|
36
77
|
@duration = value
|
37
78
|
end
|
38
79
|
|
@@ -48,18 +89,43 @@ module SDN
|
|
48
89
|
end
|
49
90
|
end
|
50
91
|
|
51
|
-
#
|
52
|
-
class
|
53
|
-
MSG =
|
54
|
-
PARAMS_LENGTH =
|
92
|
+
# Move relative to current position
|
93
|
+
class MoveOf < Message
|
94
|
+
MSG = 0x04
|
95
|
+
PARAMS_LENGTH = 4
|
96
|
+
TARGET_TYPE = { next_ip: 0x00, previous_ip: 0x01, jog_down_pulses: 0x02, jog_up_pulses: 0x03, jog_down_ms: 0x04, jog_up_ms: 0x05 }
|
55
97
|
|
56
|
-
|
98
|
+
attr_reader :target_type, :target
|
99
|
+
|
100
|
+
def initialize(dest = nil, target_type = nil, target = nil, **kwargs)
|
57
101
|
kwargs[:dest] ||= dest
|
58
102
|
super(**kwargs)
|
103
|
+
self.target_type = target_type
|
104
|
+
self.target = target
|
105
|
+
end
|
106
|
+
|
107
|
+
def parse(params)
|
108
|
+
super
|
109
|
+
self.target_type = TARGET_TYPE.invert[to_number(params[0])]
|
110
|
+
target = to_number(params[1..2], nillable: true)
|
111
|
+
target *= 10 if %I{jog_down_ms jog_up_ms}.include?(target_type)
|
112
|
+
self.target = target
|
113
|
+
end
|
114
|
+
|
115
|
+
def target_type=(value)
|
116
|
+
raise ArgumentError, "target_type must be one of :next_ip, :previous_ip, :jog_down_pulses, :jog_up_pulses, :jog_down_ms, :jog_up_ms" unless value.nil? || TARGET_TYPE.keys.include?(value)
|
117
|
+
@target_type = value
|
118
|
+
end
|
119
|
+
|
120
|
+
def target=(value)
|
121
|
+
value &= 0xffff if value
|
122
|
+
@target = value
|
59
123
|
end
|
60
124
|
|
61
125
|
def params
|
62
|
-
|
126
|
+
param = target || 0xffff
|
127
|
+
param /= 10 if %I{jog_down_ms jog_up_ms}.include?(target_type)
|
128
|
+
transform_param(TARGET_TYPE[target_type]) + from_number(param, 2) + transform_param(0)
|
63
129
|
end
|
64
130
|
end
|
65
131
|
|
@@ -107,43 +173,18 @@ module SDN
|
|
107
173
|
end
|
108
174
|
end
|
109
175
|
|
110
|
-
#
|
111
|
-
class
|
112
|
-
MSG =
|
113
|
-
PARAMS_LENGTH =
|
114
|
-
TARGET_TYPE = { next_ip: 0x00, previous_ip: 0x01, jog_down_pulses: 0x02, jog_up_pulses: 0x03, jog_down_ms: 0x04, jog_up_ms: 0x05 }
|
115
|
-
|
116
|
-
attr_reader :target_type, :target
|
176
|
+
# Stop movement
|
177
|
+
class Stop < Message
|
178
|
+
MSG = 0x02
|
179
|
+
PARAMS_LENGTH = 1
|
117
180
|
|
118
|
-
def initialize(dest = nil,
|
181
|
+
def initialize(dest = nil, **kwargs)
|
119
182
|
kwargs[:dest] ||= dest
|
120
183
|
super(**kwargs)
|
121
|
-
self.target_type = target_type
|
122
|
-
self.target = target
|
123
|
-
end
|
124
|
-
|
125
|
-
def parse(params)
|
126
|
-
super
|
127
|
-
self.target_type = TARGET_TYPE.invert[to_number(params[0])]
|
128
|
-
target = to_number(params[1..2], nillable: true)
|
129
|
-
target *= 10 if %I{jog_down_ms jog_up_ms}.include?(target_type)
|
130
|
-
self.target = target
|
131
|
-
end
|
132
|
-
|
133
|
-
def target_type=(value)
|
134
|
-
raise ArgumentError, "target_type must be one of :next_ip, :previous_ip, :jog_down_pulses, :jog_up_pulses, :jog_down_ms, :jog_up_ms" unless value.nil? || TARGET_TYPE.keys.include?(value)
|
135
|
-
@target_type = value
|
136
|
-
end
|
137
|
-
|
138
|
-
def target=(value)
|
139
|
-
value &= 0xffff if value
|
140
|
-
@target = value
|
141
184
|
end
|
142
185
|
|
143
186
|
def params
|
144
|
-
|
145
|
-
param /= 10 if %I{jog_down_ms jog_up_ms}.include?(target_type)
|
146
|
-
transform_param(TARGET_TYPE[target_type]) + from_number(param, 2) + transform_param(0)
|
187
|
+
transform_param(0)
|
147
188
|
end
|
148
189
|
end
|
149
190
|
|
@@ -1,32 +1,43 @@
|
|
1
1
|
module SDN
|
2
2
|
class Message
|
3
|
-
class
|
4
|
-
MSG =
|
5
|
-
|
3
|
+
class GetGroupAddr < Message
|
4
|
+
MSG = 0x41
|
5
|
+
PARAMS_LENGTH = 1
|
6
6
|
|
7
|
-
|
8
|
-
MSG = 0x0e
|
9
|
-
end
|
7
|
+
attr_reader :group_index
|
10
8
|
|
11
|
-
|
12
|
-
|
9
|
+
def initialize(dest = nil, group_index = 1, **kwargs)
|
10
|
+
kwargs[:dest] ||= dest
|
11
|
+
super(**kwargs)
|
12
|
+
self.group_index = group_index
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse(params)
|
16
|
+
super
|
17
|
+
self.group_index = to_number(params[0]) + 1
|
18
|
+
end
|
19
|
+
|
20
|
+
def group_index=(value)
|
21
|
+
raise ArgumentError, "group_index is out of range" unless (1..16).include?(value)
|
22
|
+
@group_index = value
|
23
|
+
end
|
24
|
+
|
25
|
+
def params
|
26
|
+
transform_param(group_index - 1)
|
27
|
+
end
|
13
28
|
end
|
14
29
|
|
15
30
|
class GetMotorDirection < SimpleRequest
|
16
31
|
MSG = 0x22
|
17
32
|
end
|
18
33
|
|
19
|
-
class GetMotorRollingSpeed < SimpleRequest
|
20
|
-
MSG = 0x23
|
21
|
-
end
|
22
|
-
|
23
34
|
class GetMotorIP < Message
|
24
35
|
MSG = 0x25
|
25
36
|
PARAMS_LENGTH = 1
|
26
37
|
|
27
38
|
attr_reader :ip
|
28
39
|
|
29
|
-
def initialize(dest = nil, ip =
|
40
|
+
def initialize(dest = nil, ip = 1, **kwargs)
|
30
41
|
kwargs[:dest] ||= dest
|
31
42
|
super(**kwargs)
|
32
43
|
self.ip = ip
|
@@ -34,48 +45,37 @@ module SDN
|
|
34
45
|
|
35
46
|
def parse(params)
|
36
47
|
super
|
37
|
-
self.ip = to_number(params[0]
|
48
|
+
self.ip = to_number(params[0])
|
38
49
|
end
|
39
50
|
|
40
51
|
def ip=(value)
|
41
|
-
raise ArgumentError, "invalid IP #{
|
52
|
+
raise ArgumentError, "invalid IP #{value} (should be 1-16)" unless (1..16).include?(value)
|
42
53
|
@ip = value
|
43
54
|
end
|
44
55
|
|
45
56
|
def params
|
46
|
-
transform_param(
|
57
|
+
transform_param(ip)
|
47
58
|
end
|
48
59
|
end
|
49
60
|
|
50
|
-
class
|
51
|
-
MSG =
|
52
|
-
|
53
|
-
|
54
|
-
attr_reader :group_index
|
55
|
-
|
56
|
-
def initialize(dest = nil, group_index = 0, **kwargs)
|
57
|
-
kwargs[:dest] ||= dest
|
58
|
-
super(**kwargs)
|
59
|
-
self.group_index = group_index
|
60
|
-
end
|
61
|
+
class GetMotorLimits < SimpleRequest
|
62
|
+
MSG = 0x21
|
63
|
+
end
|
61
64
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
65
|
+
class GetMotorPosition < SimpleRequest
|
66
|
+
MSG = 0x0c
|
67
|
+
end
|
66
68
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
69
|
+
class GetMotorRollingSpeed < SimpleRequest
|
70
|
+
MSG = 0x23
|
71
|
+
end
|
71
72
|
|
72
|
-
|
73
|
-
|
74
|
-
end
|
73
|
+
class GetMotorStatus < SimpleRequest
|
74
|
+
MSG = 0x0e
|
75
75
|
end
|
76
76
|
|
77
|
-
class
|
78
|
-
MSG =
|
77
|
+
class GetNetworkLock < SimpleRequest
|
78
|
+
MSG = 0x26
|
79
79
|
end
|
80
80
|
|
81
81
|
class GetNodeAddr < Message
|
@@ -88,6 +88,14 @@ module SDN
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
91
|
+
class GetNodeAppVersion < SimpleRequest
|
92
|
+
MSG = 0x74
|
93
|
+
end
|
94
|
+
|
95
|
+
class GetNodeLabel < SimpleRequest
|
96
|
+
MSG = 0x45
|
97
|
+
end
|
98
|
+
|
91
99
|
class GetNodeSerialNumber < SimpleRequest
|
92
100
|
MSG = 0x4c
|
93
101
|
end
|
@@ -13,6 +13,34 @@ module SDN
|
|
13
13
|
addr_bytes[0..1] == [1, 1]
|
14
14
|
end
|
15
15
|
|
16
|
+
def node_type_from_number(number)
|
17
|
+
case number
|
18
|
+
when 1; :st50ilt2
|
19
|
+
when 2; :st30
|
20
|
+
when 6; :glydea
|
21
|
+
when 7; :st50ac
|
22
|
+
when 8; :st50dc
|
23
|
+
when 0x70; :lt50
|
24
|
+
else; number
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def node_type_to_number(type)
|
29
|
+
case type
|
30
|
+
when :st50ilt2; 1
|
31
|
+
when :st30; 2
|
32
|
+
when :glydea; 6
|
33
|
+
when :st50ac; 7
|
34
|
+
when :st50dc; 8
|
35
|
+
when :lt50; 0x70
|
36
|
+
else; type
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def node_type_to_string(type)
|
41
|
+
type.is_a?(Integer) ? "%02xh" % type : type.inspect
|
42
|
+
end
|
43
|
+
|
16
44
|
def transform_param(param)
|
17
45
|
Array(param).reverse.map { |byte| 0xff - byte }
|
18
46
|
end
|
@@ -23,7 +51,9 @@ module SDN
|
|
23
51
|
result
|
24
52
|
end
|
25
53
|
|
26
|
-
def from_number(number, bytes)
|
54
|
+
def from_number(number, bytes = 1)
|
55
|
+
number ||= 1 ** (bytes * 8) - 1
|
56
|
+
number = number.to_i
|
27
57
|
bytes.times.inject([]) do |res, _|
|
28
58
|
res << (0xff - number & 0xff)
|
29
59
|
number >>= 8
|
@@ -33,12 +63,12 @@ module SDN
|
|
33
63
|
|
34
64
|
def to_string(param)
|
35
65
|
chars = param.map { |b| 0xff - b }
|
36
|
-
chars
|
66
|
+
chars.pack("C*").sub(/\0+$/, '').strip
|
37
67
|
end
|
38
68
|
|
39
69
|
def from_string(string, bytes)
|
40
70
|
chars = string.bytes
|
41
|
-
chars = chars[0...
|
71
|
+
chars = chars[0...bytes].fill(' '.ord, chars.length, bytes - chars.length)
|
42
72
|
chars.map { |b| 0xff - b }
|
43
73
|
end
|
44
74
|
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module SDN
|
2
|
+
class Message
|
3
|
+
module ILT2
|
4
|
+
class GetIRConfig < SimpleRequest
|
5
|
+
MSG = 0x49
|
6
|
+
end
|
7
|
+
|
8
|
+
class GetLockStatus < SimpleRequest
|
9
|
+
MSG = 0x4b
|
10
|
+
end
|
11
|
+
|
12
|
+
class GetMotorIP < Message
|
13
|
+
MSG = 0x43
|
14
|
+
PARAMS_LENGTH = 1
|
15
|
+
|
16
|
+
attr_reader :ip
|
17
|
+
|
18
|
+
def initialize(dest = nil, ip = 1, **kwargs)
|
19
|
+
kwargs[:dest] ||= dest
|
20
|
+
super(**kwargs)
|
21
|
+
self.ip = ip
|
22
|
+
end
|
23
|
+
|
24
|
+
def ip=(value)
|
25
|
+
raise ArgumentError, "invalid IP #{value} (should be 1-16)" unless (1..16).include?(value)
|
26
|
+
@ip = value
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse(params)
|
30
|
+
super
|
31
|
+
self.ip = to_number(params[0]) + 1
|
32
|
+
end
|
33
|
+
|
34
|
+
def params
|
35
|
+
transform_param(@ip - 1)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class GetMotorPosition < SimpleRequest
|
40
|
+
MSG = 0x44
|
41
|
+
end
|
42
|
+
|
43
|
+
class GetMotorSettings < SimpleRequest
|
44
|
+
MSG = 0x42
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|