somfy_sdn 2.4.1 → 2.5.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 +4 -4
- data/exe/somfy_sdn +1 -0
- data/lib/sdn/cli/mqtt/group.rb +11 -0
- data/lib/sdn/cli/mqtt/motor.rb +25 -1
- data/lib/sdn/cli/mqtt/p_queue.rb +6 -0
- data/lib/sdn/cli/mqtt/read.rb +46 -47
- data/lib/sdn/cli/mqtt/subscriptions.rb +8 -0
- data/lib/sdn/cli/mqtt/write.rb +67 -27
- data/lib/sdn/cli/mqtt.rb +256 -198
- data/lib/sdn/cli/provisioner.rb +34 -1
- data/lib/sdn/cli/simulator.rb +78 -11
- data/lib/sdn/cli.rb +6 -0
- data/lib/sdn/client.rb +42 -2
- data/lib/sdn/message/control.rb +136 -12
- data/lib/sdn/message/get.rb +57 -0
- data/lib/sdn/message/helpers.rb +64 -0
- data/lib/sdn/message/ilt2/get.rb +24 -0
- data/lib/sdn/message/ilt2/master_control.rb +10 -0
- data/lib/sdn/message/ilt2/post.rb +79 -13
- data/lib/sdn/message/ilt2/set.rb +112 -7
- data/lib/sdn/message/post.rb +181 -20
- data/lib/sdn/message/set.rb +166 -8
- data/lib/sdn/message.rb +121 -14
- data/lib/sdn/version.rb +2 -1
- data/lib/sdn.rb +13 -5
- metadata +5 -18
data/lib/sdn/cli/provisioner.rb
CHANGED
|
@@ -4,9 +4,28 @@ require "curses"
|
|
|
4
4
|
|
|
5
5
|
module SDN
|
|
6
6
|
module CLI
|
|
7
|
+
# @!visibility private
|
|
7
8
|
class Provisioner
|
|
8
|
-
|
|
9
|
+
# @return [Curses::Window]
|
|
10
|
+
attr_reader :win
|
|
9
11
|
|
|
12
|
+
# @return [SDN::Client]
|
|
13
|
+
attr_reader :sdn
|
|
14
|
+
|
|
15
|
+
# Selected motor address as a three-byte array.
|
|
16
|
+
#
|
|
17
|
+
# @return [(Integer, Integer, Integer)]
|
|
18
|
+
attr_reader :addr
|
|
19
|
+
|
|
20
|
+
# Message namespace used for the current motor type (regular or ILT2).
|
|
21
|
+
#
|
|
22
|
+
# @return [Module]
|
|
23
|
+
attr_reader :ns
|
|
24
|
+
|
|
25
|
+
# Builds the interactive provisioning UI for a discovered motor.
|
|
26
|
+
#
|
|
27
|
+
# @param sdn [SDN::Client] SDN client connection
|
|
28
|
+
# @param addr [String, nil] optional motor address
|
|
10
29
|
def initialize(sdn, addr = nil)
|
|
11
30
|
@sdn = sdn
|
|
12
31
|
@reversed = false
|
|
@@ -71,6 +90,11 @@ module SDN
|
|
|
71
90
|
end
|
|
72
91
|
end
|
|
73
92
|
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
# Runs the key-driven event loop.
|
|
96
|
+
#
|
|
97
|
+
# @return [void]
|
|
74
98
|
def process
|
|
75
99
|
win.keypad = true
|
|
76
100
|
print_help
|
|
@@ -188,6 +212,9 @@ module SDN
|
|
|
188
212
|
win.refresh
|
|
189
213
|
end
|
|
190
214
|
|
|
215
|
+
# Polls the motor until movement stops, allowing escape to interrupt.
|
|
216
|
+
#
|
|
217
|
+
# @return [void]
|
|
191
218
|
def wait_for_stop
|
|
192
219
|
win.setpos(13, 0)
|
|
193
220
|
win.addstr("Moving...\n")
|
|
@@ -224,6 +251,9 @@ module SDN
|
|
|
224
251
|
end
|
|
225
252
|
end
|
|
226
253
|
|
|
254
|
+
# Refreshes the displayed motor position, limits, and direction state.
|
|
255
|
+
#
|
|
256
|
+
# @return [void]
|
|
227
257
|
def refresh
|
|
228
258
|
pos = sdn.ensure(ns::GetMotorPosition.new(addr))
|
|
229
259
|
@pos = pos.position_pulses
|
|
@@ -256,6 +286,9 @@ module SDN
|
|
|
256
286
|
ns == Message::ILT2
|
|
257
287
|
end
|
|
258
288
|
|
|
289
|
+
# Returns the reverse-direction flag as an integer for ILT2 settings writes.
|
|
290
|
+
#
|
|
291
|
+
# @return [Integer]
|
|
259
292
|
def reversed_int
|
|
260
293
|
@reversed ? 1 : 0
|
|
261
294
|
end
|
data/lib/sdn/cli/simulator.rb
CHANGED
|
@@ -2,26 +2,63 @@
|
|
|
2
2
|
|
|
3
3
|
module SDN
|
|
4
4
|
module CLI
|
|
5
|
+
# @!visibility private
|
|
5
6
|
class Simulator
|
|
7
|
+
# Simulated motor implementation that responds to a subset of SDN requests.
|
|
6
8
|
class MockMotor
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
:position_pulses,
|
|
12
|
-
:up_limit,
|
|
13
|
-
:down_limit,
|
|
14
|
-
:groups,
|
|
15
|
-
:network_lock_priority,
|
|
16
|
-
:lock_priority,
|
|
17
|
-
:ir_channels
|
|
9
|
+
# Simulated motor address.
|
|
10
|
+
#
|
|
11
|
+
# @return [(Integer, Integer, Integer)]
|
|
12
|
+
attr_accessor :address
|
|
18
13
|
|
|
14
|
+
# @return [:st30, :lt50]
|
|
15
|
+
attr_accessor :node_type
|
|
16
|
+
|
|
17
|
+
# @return [String]
|
|
18
|
+
attr_accessor :label
|
|
19
|
+
|
|
20
|
+
# Stored intermediate positions keyed by slot index.
|
|
21
|
+
#
|
|
22
|
+
# @return [<Integer, nil>]
|
|
23
|
+
attr_accessor :ips
|
|
24
|
+
|
|
25
|
+
# Current motor position in pulses from the upper limit.
|
|
26
|
+
#
|
|
27
|
+
# @return [Integer, nil]
|
|
28
|
+
attr_accessor :position_pulses
|
|
29
|
+
|
|
30
|
+
# @return [Integer, nil]
|
|
31
|
+
attr_accessor :up_limit
|
|
32
|
+
|
|
33
|
+
# @return [Integer, nil]
|
|
34
|
+
attr_accessor :down_limit
|
|
35
|
+
|
|
36
|
+
# Stored group memberships keyed by slot index.
|
|
37
|
+
#
|
|
38
|
+
# @return [<(Integer, Integer, Integer), nil>]
|
|
39
|
+
attr_accessor :groups
|
|
40
|
+
|
|
41
|
+
# @return [Integer, nil]
|
|
42
|
+
attr_accessor :network_lock_priority
|
|
43
|
+
|
|
44
|
+
# @return [Integer, nil]
|
|
45
|
+
attr_accessor :lock_priority
|
|
46
|
+
|
|
47
|
+
# Simulated ILT2 IR channel bitmask.
|
|
48
|
+
#
|
|
49
|
+
# @return [Integer]
|
|
50
|
+
attr_accessor :ir_channels
|
|
51
|
+
|
|
52
|
+
# Absolute move target types supported by the simulator implementation.
|
|
19
53
|
ALLOWED_MOVE_TYPES = %i[up_limit
|
|
20
54
|
down_limit
|
|
21
55
|
ip
|
|
22
56
|
position_pulses
|
|
23
57
|
position_percent].freeze
|
|
24
58
|
|
|
59
|
+
# Creates a simulated motor backed by an SDN client.
|
|
60
|
+
#
|
|
61
|
+
# @param client [SDN::Client] SDN client used to receive and send messages
|
|
25
62
|
def initialize(client)
|
|
26
63
|
@client = client
|
|
27
64
|
self.address = Message.parse_address("00.00.00")
|
|
@@ -33,6 +70,11 @@ module SDN
|
|
|
33
70
|
self.lock_priority = 0
|
|
34
71
|
end
|
|
35
72
|
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
# Starts processing incoming SDN messages for the simulated motor.
|
|
76
|
+
#
|
|
77
|
+
# @return [void]
|
|
36
78
|
def process
|
|
37
79
|
loop do
|
|
38
80
|
@client.receive do |message|
|
|
@@ -191,20 +233,41 @@ module SDN
|
|
|
191
233
|
end
|
|
192
234
|
end
|
|
193
235
|
|
|
236
|
+
# Converts a pulse position to a percentage using the configured down limit.
|
|
237
|
+
#
|
|
238
|
+
# @param pulses [Integer, nil] position in pulses
|
|
239
|
+
#
|
|
240
|
+
# @return [Numeric, nil]
|
|
194
241
|
def to_percent(pulses)
|
|
195
242
|
(pulses && down_limit) ? 100.0 * pulses / down_limit : nil
|
|
196
243
|
end
|
|
197
244
|
|
|
245
|
+
# Converts a percentage to a pulse position using the configured down limit.
|
|
246
|
+
#
|
|
247
|
+
# @param percent [Numeric, nil] position in percent
|
|
248
|
+
#
|
|
249
|
+
# @return [Numeric, nil]
|
|
198
250
|
def to_pulses(percent)
|
|
199
251
|
(percent && down_limit) ? down_limit * percent / 100 : nil
|
|
200
252
|
end
|
|
201
253
|
|
|
254
|
+
# Sends an acknowledgement for the supplied message when one was requested.
|
|
255
|
+
#
|
|
256
|
+
# @param message [SDN::Message] request message
|
|
257
|
+
#
|
|
258
|
+
# @return [void]
|
|
202
259
|
def ack(message)
|
|
203
260
|
return unless message.ack_requested
|
|
204
261
|
|
|
205
262
|
respond(Message::Ack.new(message.dest))
|
|
206
263
|
end
|
|
207
264
|
|
|
265
|
+
# Sends a negative acknowledgement for the supplied message when one was requested.
|
|
266
|
+
#
|
|
267
|
+
# @param message [SDN::Message] request message
|
|
268
|
+
# @param _error_code [nil] reserved error code argument
|
|
269
|
+
#
|
|
270
|
+
# @return [void]
|
|
208
271
|
def nack(message, _error_code = nil)
|
|
209
272
|
return unless message.ack_requested
|
|
210
273
|
|
|
@@ -219,6 +282,10 @@ module SDN
|
|
|
219
282
|
end
|
|
220
283
|
end
|
|
221
284
|
|
|
285
|
+
# Starts a simulator instance for a single mock motor.
|
|
286
|
+
#
|
|
287
|
+
# @param sdn [SDN::Client] SDN client connection
|
|
288
|
+
# @param address [String, nil] optional simulated motor address
|
|
222
289
|
def initialize(sdn, address = nil)
|
|
223
290
|
motor = MockMotor.new(sdn)
|
|
224
291
|
motor.address = Message.parse_address(address) if address
|
data/lib/sdn/cli.rb
ADDED
data/lib/sdn/client.rb
CHANGED
|
@@ -3,15 +3,22 @@
|
|
|
3
3
|
require "io/wait"
|
|
4
4
|
|
|
5
5
|
module SDN
|
|
6
|
+
# Transport client for sending and receiving SDN frames over serial, TCP, RFC2217, or PTY.
|
|
6
7
|
class Client
|
|
8
|
+
# Enables or disables raw byte tracing in the client logs.
|
|
9
|
+
#
|
|
10
|
+
# @return [true, false]
|
|
7
11
|
attr_writer :trace
|
|
8
12
|
|
|
13
|
+
# Opens a connection to an SDN bus over serial, TCP, RFC2217, or PTY.
|
|
14
|
+
#
|
|
15
|
+
# @param port [String] connection target URI or serial device path
|
|
9
16
|
def initialize(port)
|
|
10
17
|
uri = URI.parse(port)
|
|
11
18
|
@io = if uri.scheme == "tcp"
|
|
12
19
|
require "socket"
|
|
13
20
|
TCPSocket.new(uri.host, uri.port)
|
|
14
|
-
elsif
|
|
21
|
+
elsif %w[telnet rfc2217].include?(uri.scheme)
|
|
15
22
|
require "net/telnet/rfc2217"
|
|
16
23
|
Net::Telnet::RFC2217.new(host: uri.host,
|
|
17
24
|
port: uri.port || 23,
|
|
@@ -24,6 +31,10 @@ module SDN
|
|
|
24
31
|
io, slave = PTY.open
|
|
25
32
|
puts "Slave PTY available at #{slave.path}"
|
|
26
33
|
io
|
|
34
|
+
elsif uri.scheme == "esphome"
|
|
35
|
+
gem "esphome", "~> 1.1"
|
|
36
|
+
require "esphome/serial_proxy"
|
|
37
|
+
ESPHome::SerialProxy.open(uri, baud: 4800, data_bits: 8, parity: :odd, stop_bits: 1)
|
|
27
38
|
else
|
|
28
39
|
require "ccutrer-serialport"
|
|
29
40
|
CCutrer::SerialPort.new(port, baud: 4800, data_bits: 8, parity: :odd, stop_bits: 1)
|
|
@@ -31,21 +42,41 @@ module SDN
|
|
|
31
42
|
@buffer = +""
|
|
32
43
|
end
|
|
33
44
|
|
|
45
|
+
# Indicates whether raw byte tracing is enabled.
|
|
46
|
+
#
|
|
47
|
+
# @return [true, false]
|
|
34
48
|
def trace?
|
|
35
49
|
@trace
|
|
36
50
|
end
|
|
37
51
|
|
|
52
|
+
# Serializes and writes a message to the underlying transport.
|
|
53
|
+
#
|
|
54
|
+
# @param message [SDN::Message]
|
|
55
|
+
#
|
|
56
|
+
# @return [void]
|
|
38
57
|
def send(message)
|
|
39
58
|
SDN.logger.debug("Sending #{message.inspect}")
|
|
40
59
|
@io.write(message.serialize)
|
|
41
60
|
end
|
|
42
61
|
|
|
62
|
+
# Sends a message with acknowledgement requested and waits for an initial response batch.
|
|
63
|
+
#
|
|
64
|
+
# @param message [SDN::Message]
|
|
65
|
+
#
|
|
66
|
+
# @return [<SDN::Message>] received response messages
|
|
43
67
|
def transact(message)
|
|
44
68
|
message.ack_requested = true
|
|
45
69
|
send(message)
|
|
46
70
|
receive(1)
|
|
47
71
|
end
|
|
48
72
|
|
|
73
|
+
# Re-sends a request until an expected response is received.
|
|
74
|
+
#
|
|
75
|
+
# The expected response message is dependent on the message sent.
|
|
76
|
+
#
|
|
77
|
+
# @param message [SDN::Message]
|
|
78
|
+
#
|
|
79
|
+
# @return [SDN::Message] the message that is of the expected response type
|
|
49
80
|
def ensure(message)
|
|
50
81
|
loop do
|
|
51
82
|
messages = transact(message)
|
|
@@ -56,15 +87,24 @@ module SDN
|
|
|
56
87
|
end
|
|
57
88
|
end
|
|
58
89
|
|
|
90
|
+
# Default inter-read wait time, in seconds, while assembling a partial frame.
|
|
59
91
|
WAIT_TIME = 0.25
|
|
60
92
|
|
|
93
|
+
# Reads and parses messages from the transport until parsing is exhausted or a timeout occurs.
|
|
94
|
+
#
|
|
95
|
+
# @param timeout [Numeric, nil] optional read timeout in seconds
|
|
96
|
+
#
|
|
97
|
+
# @yield [message] yields each parsed message when a block is given
|
|
98
|
+
# @yieldparam message [SDN::Message] parsed message
|
|
99
|
+
#
|
|
100
|
+
# @return [<SDN::Message>] parsed messages when no block is given
|
|
61
101
|
def receive(timeout = nil)
|
|
62
102
|
messages = []
|
|
63
103
|
|
|
64
104
|
loop do
|
|
65
105
|
message, bytes_read = Message.parse(@buffer.bytes)
|
|
66
106
|
# discard how much we read
|
|
67
|
-
@buffer = @buffer[bytes_read
|
|
107
|
+
@buffer = @buffer[bytes_read..] if bytes_read
|
|
68
108
|
unless message
|
|
69
109
|
break unless messages.empty?
|
|
70
110
|
|
data/lib/sdn/message/control.rb
CHANGED
|
@@ -2,13 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
module SDN
|
|
4
4
|
class Message
|
|
5
|
+
# Command that applies or clears a positional motor lock.
|
|
5
6
|
class Lock < Message
|
|
7
|
+
# (see Ack::MSG)
|
|
6
8
|
MSG = 0x06
|
|
9
|
+
# (see Ack::PARAMS_LENGTH)
|
|
7
10
|
PARAMS_LENGTH = 5
|
|
11
|
+
# Mapping from symbolic lock targets to SDN parameter values.
|
|
8
12
|
TARGET_TYPE = { current: 0, up_limit: 1, down_limit: 2, ip: 4, unlock: 5, position_percent: 7 }.freeze
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
# @!attribute [rw] target_type
|
|
15
|
+
#
|
|
16
|
+
# @return [:current, :up_limit, :down_limit, :ip, :unlock, :position_percent]
|
|
17
|
+
attr_reader :target_type
|
|
18
|
+
|
|
19
|
+
# @!attribute [rw] target
|
|
20
|
+
#
|
|
21
|
+
# @return [Integer, nil]
|
|
22
|
+
attr_reader :target
|
|
23
|
+
|
|
24
|
+
# Requested lock priority.
|
|
25
|
+
#
|
|
26
|
+
# @return [Integer]
|
|
27
|
+
attr_reader :priority
|
|
28
|
+
|
|
29
|
+
# Creates a lock or unlock control message.
|
|
30
|
+
#
|
|
31
|
+
# @param dest [(Integer, Integer, Integer), nil] destination address
|
|
32
|
+
# @param target_type [:current, :up_limit, :down_limit, :ip, :unlock, :position_percent] lock target selector
|
|
33
|
+
# @param target [Integer, nil] lock target value
|
|
34
|
+
# @param priority [Integer] lock priority
|
|
35
|
+
# @param kwargs [Hash] additional message options
|
|
12
36
|
def initialize(dest = nil, target_type = :unlock, target = nil, priority = 1, **kwargs)
|
|
13
37
|
kwargs[:dest] ||= dest
|
|
14
38
|
super(**kwargs)
|
|
@@ -34,6 +58,7 @@ module SDN
|
|
|
34
58
|
@priority = value & 0xff
|
|
35
59
|
end
|
|
36
60
|
|
|
61
|
+
# (see Message#parse)
|
|
37
62
|
def parse(params)
|
|
38
63
|
super
|
|
39
64
|
self.target_type = TARGET_TYPE.invert[to_number(params[0])]
|
|
@@ -42,21 +67,50 @@ module SDN
|
|
|
42
67
|
self.priority = to_number(params[3])
|
|
43
68
|
end
|
|
44
69
|
|
|
70
|
+
# (see Message#params)
|
|
45
71
|
def params
|
|
46
72
|
transform_param(TARGET_TYPE[target_type]) + from_number(target,
|
|
47
73
|
2) + transform_param(priority) + transform_param(0)
|
|
48
74
|
end
|
|
49
75
|
end
|
|
50
76
|
|
|
51
|
-
#
|
|
77
|
+
# Command that moves a motor in momentary mode.
|
|
52
78
|
class Move < Message
|
|
79
|
+
# (see Ack::MSG)
|
|
53
80
|
MSG = 0x01
|
|
81
|
+
# (see Ack::PARAMS_LENGTH)
|
|
54
82
|
PARAMS_LENGTH = 3
|
|
83
|
+
# Mapping from symbolic directions to SDN parameter values.
|
|
55
84
|
DIRECTION = { down: 0x00, up: 0x01, cancel: 0x02 }.freeze
|
|
85
|
+
# Mapping from symbolic speed modes to SDN parameter values.
|
|
56
86
|
SPEED = { up: 0x00, down: 0x01, slow: 0x02 }.freeze
|
|
57
87
|
|
|
58
|
-
|
|
59
|
-
|
|
88
|
+
# @!attribute [rw] direction
|
|
89
|
+
#
|
|
90
|
+
# @return [:down, :up, :cancel]
|
|
91
|
+
attr_reader :direction
|
|
92
|
+
|
|
93
|
+
# @!attribute [rw] duration
|
|
94
|
+
#
|
|
95
|
+
# Requested movement duration in protocol units.
|
|
96
|
+
#
|
|
97
|
+
# @return [Integer, nil]
|
|
98
|
+
attr_reader :duration
|
|
99
|
+
|
|
100
|
+
# @!attribute [rw] speed
|
|
101
|
+
#
|
|
102
|
+
# Requested movement speed mode.
|
|
103
|
+
#
|
|
104
|
+
# @return [:up, :down, :slow]
|
|
105
|
+
attr_reader :speed
|
|
106
|
+
|
|
107
|
+
# Creates a momentary movement command.
|
|
108
|
+
#
|
|
109
|
+
# @param dest [(Integer, Integer, Integer), nil] destination address
|
|
110
|
+
# @param direction [:down, :up, :cancel] movement direction
|
|
111
|
+
# @param duration [Integer, nil] duration in protocol units
|
|
112
|
+
# @param speed [:up, :down, :slow] speed selector
|
|
113
|
+
# @param kwargs [Hash] additional message options
|
|
60
114
|
def initialize(dest = nil, direction = :cancel, duration: nil, speed: :up, **kwargs)
|
|
61
115
|
kwargs[:dest] ||= dest
|
|
62
116
|
super(**kwargs)
|
|
@@ -65,6 +119,7 @@ module SDN
|
|
|
65
119
|
self.speed = speed
|
|
66
120
|
end
|
|
67
121
|
|
|
122
|
+
# (see Message#parse)
|
|
68
123
|
def parse(params)
|
|
69
124
|
super
|
|
70
125
|
self.direction = DIRECTION.invert[to_number(params[0])]
|
|
@@ -98,6 +153,7 @@ module SDN
|
|
|
98
153
|
@speed = speed
|
|
99
154
|
end
|
|
100
155
|
|
|
156
|
+
# (see Message#params)
|
|
101
157
|
def params
|
|
102
158
|
transform_param(DIRECTION[direction]) +
|
|
103
159
|
transform_param(duration || 0) +
|
|
@@ -105,10 +161,13 @@ module SDN
|
|
|
105
161
|
end
|
|
106
162
|
end
|
|
107
163
|
|
|
108
|
-
#
|
|
164
|
+
# Command that moves a motor relative to its current position.
|
|
109
165
|
class MoveOf < Message
|
|
166
|
+
# (see Ack::MSG)
|
|
110
167
|
MSG = 0x04
|
|
168
|
+
# (see Ack::PARAMS_LENGTH)
|
|
111
169
|
PARAMS_LENGTH = 4
|
|
170
|
+
# Mapping from symbolic relative targets to SDN parameter values.
|
|
112
171
|
TARGET_TYPE = { next_ip: 0x00,
|
|
113
172
|
previous_ip: 0x01,
|
|
114
173
|
jog_down_pulses: 0x02,
|
|
@@ -116,8 +175,32 @@ module SDN
|
|
|
116
175
|
jog_down_ms: 0x04,
|
|
117
176
|
jog_up_ms: 0x05 }.freeze
|
|
118
177
|
|
|
119
|
-
|
|
120
|
-
|
|
178
|
+
# @!attribute [rw] target_type
|
|
179
|
+
#
|
|
180
|
+
# Requested relative target selector.
|
|
181
|
+
#
|
|
182
|
+
# @return [:next_ip, :previous_ip, :jog_down_pulses, :jog_up_pulses, :jog_down_ms, :jog_up_ms, nil]
|
|
183
|
+
attr_reader :target_type
|
|
184
|
+
|
|
185
|
+
# @!attribute [rw] target
|
|
186
|
+
#
|
|
187
|
+
# Requested relative target amount in pulses or milliseconds.
|
|
188
|
+
#
|
|
189
|
+
# @return [Integer, nil]
|
|
190
|
+
attr_reader :target
|
|
191
|
+
|
|
192
|
+
# Creates a relative movement command.
|
|
193
|
+
#
|
|
194
|
+
# @param dest [(Integer, Integer, Integer), nil] destination address
|
|
195
|
+
# @param target_type [:next_ip,
|
|
196
|
+
# :previous_ip,
|
|
197
|
+
# :jog_down_pulses,
|
|
198
|
+
# :jog_up_pulses,
|
|
199
|
+
# :jog_down_ms,
|
|
200
|
+
# :jog_up_ms,
|
|
201
|
+
# nil] relative target selector
|
|
202
|
+
# @param target [Integer, nil] pulses or milliseconds
|
|
203
|
+
# @param kwargs [Hash] additional message options
|
|
121
204
|
def initialize(dest = nil, target_type = nil, target = nil, **kwargs)
|
|
122
205
|
kwargs[:dest] ||= dest
|
|
123
206
|
super(**kwargs)
|
|
@@ -125,6 +208,7 @@ module SDN
|
|
|
125
208
|
self.target = target
|
|
126
209
|
end
|
|
127
210
|
|
|
211
|
+
# (see Message#parse)
|
|
128
212
|
def parse(params)
|
|
129
213
|
super
|
|
130
214
|
self.target_type = TARGET_TYPE.invert[to_number(params[0])]
|
|
@@ -147,6 +231,7 @@ module SDN
|
|
|
147
231
|
@target = value
|
|
148
232
|
end
|
|
149
233
|
|
|
234
|
+
# (see Message#params)
|
|
150
235
|
def params
|
|
151
236
|
param = target || 0xffff
|
|
152
237
|
param /= 10 if %I[jog_down_ms jog_up_ms].include?(target_type)
|
|
@@ -154,15 +239,43 @@ module SDN
|
|
|
154
239
|
end
|
|
155
240
|
end
|
|
156
241
|
|
|
157
|
-
#
|
|
242
|
+
# Command that moves a motor to an absolute target.
|
|
158
243
|
class MoveTo < Message
|
|
244
|
+
# (see Ack::MSG)
|
|
159
245
|
MSG = 0x03
|
|
246
|
+
# (see Ack::PARAMS_LENGTH)
|
|
160
247
|
PARAMS_LENGTH = 4
|
|
248
|
+
# Mapping from symbolic absolute targets to SDN parameter values.
|
|
161
249
|
TARGET_TYPE = { down_limit: 0x00, up_limit: 0x01, ip: 0x02, position_pulses: 0x03, position_percent: 0x04 }.freeze
|
|
250
|
+
# Mapping from symbolic speed modes to SDN parameter values.
|
|
162
251
|
SPEED = { up: 0x00, down: 0x01, slow: 0x02 }.freeze
|
|
163
252
|
|
|
164
|
-
|
|
165
|
-
|
|
253
|
+
# @!attribute [rw] target_type
|
|
254
|
+
#
|
|
255
|
+
# Requested absolute target selector.
|
|
256
|
+
#
|
|
257
|
+
# @return [:down_limit, :up_limit, :ip, :position_pulses, :position_percent]
|
|
258
|
+
attr_reader :target_type
|
|
259
|
+
|
|
260
|
+
# @!attribute [rw] target
|
|
261
|
+
#
|
|
262
|
+
# @return [Integer, nil]
|
|
263
|
+
attr_reader :target
|
|
264
|
+
|
|
265
|
+
# @!attribute [rw] speed
|
|
266
|
+
#
|
|
267
|
+
# Requested movement speed mode.
|
|
268
|
+
#
|
|
269
|
+
# @return [:up, :down, :slow]
|
|
270
|
+
attr_reader :speed
|
|
271
|
+
|
|
272
|
+
# Creates an absolute movement command.
|
|
273
|
+
#
|
|
274
|
+
# @param dest [(Integer, Integer, Integer), nil] destination address
|
|
275
|
+
# @param target_type [:down_limit, :up_limit, :ip, :position_pulses, :position_percent] absolute target selector
|
|
276
|
+
# @param target [Integer, nil] target value
|
|
277
|
+
# @param speed [:up, :down, :slow] speed selector
|
|
278
|
+
# @param kwargs [Hash] additional message options
|
|
166
279
|
def initialize(dest = nil, target_type = :down_limit, target = nil, speed = :up, **kwargs)
|
|
167
280
|
kwargs[:dest] ||= dest
|
|
168
281
|
super(**kwargs)
|
|
@@ -171,6 +284,7 @@ module SDN
|
|
|
171
284
|
self.speed = speed
|
|
172
285
|
end
|
|
173
286
|
|
|
287
|
+
# (see Message#parse)
|
|
174
288
|
def parse(params)
|
|
175
289
|
super
|
|
176
290
|
self.target_type = TARGET_TYPE.invert[to_number(params[0])]
|
|
@@ -198,27 +312,37 @@ module SDN
|
|
|
198
312
|
@speed = value
|
|
199
313
|
end
|
|
200
314
|
|
|
315
|
+
# (see Message#params)
|
|
201
316
|
def params
|
|
202
317
|
transform_param(TARGET_TYPE[target_type]) + from_number(target || 0xffff, 2) + transform_param(SPEED[speed])
|
|
203
318
|
end
|
|
204
319
|
end
|
|
205
320
|
|
|
206
|
-
#
|
|
321
|
+
# Command that stops motor movement.
|
|
207
322
|
class Stop < Message
|
|
323
|
+
# (see Ack::MSG)
|
|
208
324
|
MSG = 0x02
|
|
325
|
+
# (see Ack::PARAMS_LENGTH)
|
|
209
326
|
PARAMS_LENGTH = 1
|
|
210
327
|
|
|
328
|
+
# Creates a stop command for the specified destination.
|
|
329
|
+
#
|
|
330
|
+
# @param dest [(Integer, Integer, Integer), nil] destination address
|
|
331
|
+
# @param kwargs [Hash] additional message options
|
|
211
332
|
def initialize(dest = nil, **kwargs)
|
|
212
333
|
kwargs[:dest] ||= dest
|
|
213
334
|
super(**kwargs)
|
|
214
335
|
end
|
|
215
336
|
|
|
337
|
+
# (see Message#params)
|
|
216
338
|
def params
|
|
217
339
|
transform_param(0)
|
|
218
340
|
end
|
|
219
341
|
end
|
|
220
342
|
|
|
343
|
+
# Command that triggers the motor's wink or identify behavior.
|
|
221
344
|
class Wink < SimpleRequest
|
|
345
|
+
# (see Ack::MSG)
|
|
222
346
|
MSG = 0x05
|
|
223
347
|
end
|
|
224
348
|
end
|