cresip 0.9.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/README.md +69 -0
- data/cresip.gemspec +28 -0
- data/lib/cresip.rb +67 -0
- data/lib/cresip/action.rb +191 -0
- data/lib/cresip/echo.rb +36 -0
- data/lib/cresip/header.rb +33 -0
- data/lib/cresip/register.rb +73 -0
- data/lib/cresip/serial.rb +40 -0
- data/spec/cresip_spec.rb +212 -0
- metadata +112 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 43fd46eee2a87a033259dde9c85f15fff84eaa1c
|
4
|
+
data.tar.gz: 81b6b036ad0218f1f5f9ef53a339393311224fbe
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f119fc6dc874f74a4ff0a157dd80871b3843276d24008ce688c7c6552376205c7f50de34f62cd4a757b366aeb0d04346d27fb2f964df3461fa19f05c971a33ca
|
7
|
+
data.tar.gz: 5e45fe866d284a4fb7d2d79a94467330ff32b9b62c827ab7aa951247f51ce6a9b8412d5cfef74dd16dc151f2f4880b8a75a89fccf8d3944d6b05984845e764d4
|
data/README.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# Ruby CresIP
|
2
|
+
|
3
|
+
Constructs and parses Crestron IP protocol packets that make it easier to communicate with Crestron devices that would otherwise require a crestron controller.
|
4
|
+
It does not implement the transport layer so you can use it with native ruby, eventmachine, celluloid or the like.
|
5
|
+
|
6
|
+
[](https://travis-ci.org/acaprojects/ruby-cresip)
|
7
|
+
|
8
|
+
You'll still need to use Crestron Toolbox software to configure the devices.
|
9
|
+
|
10
|
+
|
11
|
+
## Install the gem
|
12
|
+
|
13
|
+
Install it with [RubyGems](https://rubygems.org/)
|
14
|
+
|
15
|
+
gem install cresip
|
16
|
+
|
17
|
+
or add this to your Gemfile if you use [Bundler](http://gembundler.com/):
|
18
|
+
|
19
|
+
gem 'cresip'
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require 'cresip'
|
27
|
+
|
28
|
+
values = {}
|
29
|
+
cresip = CresIP.new do |message|
|
30
|
+
case message
|
31
|
+
when Action
|
32
|
+
if message.feedback?
|
33
|
+
values[message.join] = message.value
|
34
|
+
else
|
35
|
+
values[message.join] = message.value
|
36
|
+
# The request is a set value so maybe perform some action
|
37
|
+
end
|
38
|
+
when Echo
|
39
|
+
if not message.is_response?
|
40
|
+
# Send a response using you TCP transport
|
41
|
+
message.response.to_binary_s
|
42
|
+
end
|
43
|
+
when Register
|
44
|
+
if not message.reg_success?
|
45
|
+
# Send a response using you TCP transport
|
46
|
+
message.register.to_binary_s
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
cresip.read(byte_string)
|
51
|
+
|
52
|
+
|
53
|
+
# You can also generate your own actions
|
54
|
+
act = CresIP::Action.new
|
55
|
+
|
56
|
+
# Supports Strings, Integers and true / false values
|
57
|
+
act.value = 'hello crestron'
|
58
|
+
act.join = 123
|
59
|
+
|
60
|
+
# Send this string over the wire to communicate
|
61
|
+
act.to_binary_s
|
62
|
+
|
63
|
+
```
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
## License and copyright
|
68
|
+
|
69
|
+
MIT
|
data/cresip.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "cresip"
|
5
|
+
s.version = '0.9.0'
|
6
|
+
s.authors = ["Stephen von Takach"]
|
7
|
+
s.email = ["steve@cotag.me"]
|
8
|
+
s.licenses = ["MIT"]
|
9
|
+
s.homepage = "https://github.com/advancedcontrol/ruby-crescip"
|
10
|
+
s.summary = "Crestron IP protocol on Ruby"
|
11
|
+
s.description = <<-EOF
|
12
|
+
Constructs and parses Crestron IP packets allowing you to communicate with Crestron devices without a controller
|
13
|
+
EOF
|
14
|
+
|
15
|
+
|
16
|
+
s.add_dependency 'bindata', '~> 2.3'
|
17
|
+
|
18
|
+
s.add_development_dependency 'rspec', '~> 3.5'
|
19
|
+
s.add_development_dependency 'yard', '~> 0'
|
20
|
+
s.add_development_dependency 'rake', '~> 11'
|
21
|
+
|
22
|
+
|
23
|
+
s.files = Dir["{lib}/**/*"] + %w(cresip.gemspec README.md)
|
24
|
+
s.test_files = Dir["spec/**/*"]
|
25
|
+
s.extra_rdoc_files = ["README.md"]
|
26
|
+
|
27
|
+
s.require_paths = ["lib"]
|
28
|
+
end
|
data/lib/cresip.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true, encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'bindata'
|
4
|
+
|
5
|
+
require 'cresip/header'
|
6
|
+
require 'cresip/register'
|
7
|
+
require 'cresip/action'
|
8
|
+
require 'cresip/echo'
|
9
|
+
require 'cresip/serial'
|
10
|
+
|
11
|
+
|
12
|
+
=begin
|
13
|
+
For testing 3series device control you can use the reserved joins
|
14
|
+
Analog Joins: 17201 == LCD Brightness
|
15
|
+
Digital Joins: 17229 == LCD Backlight On
|
16
|
+
17230 == LCD Backlight Off
|
17
|
+
=end
|
18
|
+
|
19
|
+
|
20
|
+
class CresIP
|
21
|
+
HeartBeatRate = 5000 #ms
|
22
|
+
DefaultPort = 41794
|
23
|
+
TLSPort = 41796
|
24
|
+
|
25
|
+
def initialize(callback = nil, &block)
|
26
|
+
@callback = callback || block
|
27
|
+
@buffer = String.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def read(data)
|
31
|
+
@buffer << data
|
32
|
+
while @buffer.length >= 3 do
|
33
|
+
header = PacketHeader.new
|
34
|
+
header.read(@buffer[0..2])
|
35
|
+
length = header.packet_size + 3
|
36
|
+
|
37
|
+
break if @buffer.length < length
|
38
|
+
|
39
|
+
payload = @buffer[3...length]
|
40
|
+
@buffer = @buffer[length..-1]
|
41
|
+
|
42
|
+
parse_packet(header, payload)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse_packet(header, payload)
|
47
|
+
case header.type
|
48
|
+
when :register, :register_response, :register_success
|
49
|
+
@callback.call Register.new(header, payload)
|
50
|
+
|
51
|
+
when :program_stopping
|
52
|
+
# Should we bother with a callback?
|
53
|
+
|
54
|
+
when :echo_request, :echo_response
|
55
|
+
@callback.call Echo.new(header, payload)
|
56
|
+
|
57
|
+
when :action_info
|
58
|
+
action_header = ActionHeader.new
|
59
|
+
action_header.read(payload)
|
60
|
+
@callback.call Action.new(header, action_header)
|
61
|
+
|
62
|
+
when :serial_data
|
63
|
+
@callback.call SerialData.new(header, payload)
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
# frozen_string_literal: true, encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
class CresIP
|
4
|
+
PayloadType = {
|
5
|
+
0x00 => :digital_feedback,
|
6
|
+
0x01 => :analog_feedback,
|
7
|
+
0x02 => :serial_feedback,
|
8
|
+
0x03 => :update_request_incomming, # seems pointless and can be ignored
|
9
|
+
0x08 => :date_and_time,
|
10
|
+
0x27 => :digital_set,
|
11
|
+
0x14 => :analog_set,
|
12
|
+
0x12 => :serial_set
|
13
|
+
#0x20 => :??
|
14
|
+
}
|
15
|
+
PayloadType.merge!(PayloadType.invert)
|
16
|
+
|
17
|
+
class ActionHeader < BinData::Record
|
18
|
+
endian :big
|
19
|
+
|
20
|
+
uint8 :reserved
|
21
|
+
uint16 :payload_size, :value => lambda { payload.length + 1 }
|
22
|
+
uint8 :payload_type
|
23
|
+
string :payload, :read_length => lambda { payload_size - 1 }
|
24
|
+
|
25
|
+
def type
|
26
|
+
PayloadType[payload_type]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
# Digital Feedback: 05 0006 000003 00 1300
|
32
|
+
# Analog Set: 05 0008 000005 14 004204d2
|
33
|
+
# Date & Time:(dev) 05 000b 000008 08 0e230710092216
|
34
|
+
# (controller) 05 000b 000008 08 0e230709092216
|
35
|
+
# Unknown: (dev) 05 0009 000006 20 0103009201
|
36
|
+
# (dev) 05 000a 000007 20 01041500f203
|
37
|
+
# (controller) 05 0014 000011 20 110e1c050000444d204f757470757473
|
38
|
+
# Update Incomming: 05 0005 000002 03 00 (device & server)
|
39
|
+
# 05 0006 000003 03 2107 (device)
|
40
|
+
# 05 0005 000002 03 16 (server)
|
41
|
+
# Serial Set: (dev) 05 0013 000010 12 03444d2d54582d344b2d3330322d43
|
42
|
+
class Action
|
43
|
+
def initialize(header = PacketHeader.new, action = ActionHeader.new)
|
44
|
+
@header = header
|
45
|
+
@action = action
|
46
|
+
@header.packet_type = PacketTypes[:action_info]
|
47
|
+
|
48
|
+
if action.type && self.respond_to?(action.type, true)
|
49
|
+
@join, @value = self.send(action.type, action.payload)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
attr_reader :header, :action, :join, :value
|
54
|
+
|
55
|
+
def type
|
56
|
+
@action.type
|
57
|
+
end
|
58
|
+
|
59
|
+
def payload
|
60
|
+
@action.payload
|
61
|
+
end
|
62
|
+
|
63
|
+
Feedback = [:analog_feedback, :digital_feedback, :serial_feedback]
|
64
|
+
def feedback?
|
65
|
+
Feedback.include? @action.type
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_binary_s
|
69
|
+
action_resp = @action.to_binary_s
|
70
|
+
@header.packet_size = action_resp.length
|
71
|
+
"#{@header.to_binary_s}#{action_resp}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def set_value(data, type: :set, join: @join)
|
75
|
+
case data
|
76
|
+
when String
|
77
|
+
@action.payload_type = type == :set ? PayloadType[:serial_set] : PayloadType[:serial_feedback]
|
78
|
+
@action.payload = encode_serial_set(join, data)
|
79
|
+
when Integer
|
80
|
+
@action.payload_type = type == :set ? PayloadType[:analog_set] : PayloadType[:analog_feedback]
|
81
|
+
@action.payload = encode_analog_set(join, data)
|
82
|
+
when true, false
|
83
|
+
@action.payload_type = type == :set ? PayloadType[:digital_set] : PayloadType[:digital_feedback]
|
84
|
+
@action.payload = encode_digital_set(join, data)
|
85
|
+
else
|
86
|
+
raise 'invalid data type'
|
87
|
+
end
|
88
|
+
|
89
|
+
@join = join
|
90
|
+
@value = data
|
91
|
+
end
|
92
|
+
|
93
|
+
def set_join(number)
|
94
|
+
@join = number
|
95
|
+
# this keeps the binary representation up to date
|
96
|
+
set_value(@value)
|
97
|
+
number
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
protected
|
102
|
+
|
103
|
+
|
104
|
+
def digital_feedback(string)
|
105
|
+
bytes = string.bytes
|
106
|
+
|
107
|
+
join = 1 + ((bytes[1] & 0x7F) << 8) + bytes[0]
|
108
|
+
# value == true, high/press
|
109
|
+
# value == false, low/release
|
110
|
+
value = (bytes[1] & 0x80) == 0
|
111
|
+
|
112
|
+
[join, value]
|
113
|
+
end
|
114
|
+
alias_method :digital_set, :digital_feedback
|
115
|
+
|
116
|
+
def encode_digital_set(join, value)
|
117
|
+
join -= 1
|
118
|
+
high = (join & 0x7F00) >> 8
|
119
|
+
high = high | 0x80 unless value
|
120
|
+
low = join & 0xFF
|
121
|
+
[low, high].pack('c*')
|
122
|
+
end
|
123
|
+
|
124
|
+
def analog_feedback(string)
|
125
|
+
bytes = string.bytes
|
126
|
+
|
127
|
+
if bytes.length == 4
|
128
|
+
join = 1 + (bytes[0] << 8) + bytes[1]
|
129
|
+
value = (bytes[2] << 8) + bytes[3]
|
130
|
+
else
|
131
|
+
join = 1 + bytes[0]
|
132
|
+
value = (bytes[1] << 8) + bytes[2]
|
133
|
+
end
|
134
|
+
|
135
|
+
[join, value]
|
136
|
+
end
|
137
|
+
alias_method :analog_set, :analog_feedback
|
138
|
+
|
139
|
+
def encode_analog_set(join, value)
|
140
|
+
output = []
|
141
|
+
join -= 1
|
142
|
+
output << ((join & 0xFF00) >> 8)
|
143
|
+
output << (join & 0xFF)
|
144
|
+
output << ((value & 0xFF00) >> 8)
|
145
|
+
output << (value & 0xFF)
|
146
|
+
output.pack('c*')
|
147
|
+
end
|
148
|
+
|
149
|
+
# NOTE:: Have not seen this returned, untested
|
150
|
+
# Ref: https://github.com/CommandFusion/CIP/blob/master/CommandFusion/CIPv1.1.js#L165
|
151
|
+
def serial_feedback(string)
|
152
|
+
rows = string.split("\r")
|
153
|
+
joinLength = rows[0].index(',');
|
154
|
+
join = rows[0][1...joinLength].to_i
|
155
|
+
|
156
|
+
value = String.new
|
157
|
+
rows.each_with_index do |row, i|
|
158
|
+
text = row[(joinLength + 1)..-1];
|
159
|
+
if row == 0
|
160
|
+
if row[0] == '#'
|
161
|
+
value << "\r#{row}" if row.length > 0
|
162
|
+
elsif row[0] == '@'
|
163
|
+
value << row
|
164
|
+
end
|
165
|
+
else
|
166
|
+
if row.empty? && !(i == (rows.length - 1) && value.empty?)
|
167
|
+
value << "\r"
|
168
|
+
else
|
169
|
+
value << row
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
[join, value]
|
175
|
+
end
|
176
|
+
|
177
|
+
def serial_set(string)
|
178
|
+
join = string.getbyte(0)
|
179
|
+
value = string[1..-1]
|
180
|
+
[join, value]
|
181
|
+
end
|
182
|
+
|
183
|
+
def encode_serial_set(join, value)
|
184
|
+
output = String.new
|
185
|
+
output << join
|
186
|
+
output << value
|
187
|
+
output
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
data/lib/cresip/echo.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true, encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
=begin Example Data
|
4
|
+
Device sent: 0d 0002 0000
|
5
|
+
Controller sent: 0e 0002 0000
|
6
|
+
=end
|
7
|
+
|
8
|
+
class CresIP
|
9
|
+
class Echo
|
10
|
+
def initialize(header, payload)
|
11
|
+
@header = header
|
12
|
+
@payload = payload
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :header, :payload
|
16
|
+
|
17
|
+
def type
|
18
|
+
@header.type
|
19
|
+
end
|
20
|
+
|
21
|
+
def is_response?
|
22
|
+
@header.type == :echo_response
|
23
|
+
end
|
24
|
+
|
25
|
+
def response
|
26
|
+
head = PacketHeader.new
|
27
|
+
head.packet_type = PacketTypes[:echo_response]
|
28
|
+
head.packet_size = @payload.length
|
29
|
+
Echo.new(head, @payload)
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_binary_s
|
33
|
+
"#{@header.to_binary_s}#{@payload}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true, encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
class CresIP
|
4
|
+
PacketTypes = {
|
5
|
+
# Registering
|
6
|
+
0x0f => :register,
|
7
|
+
0x01 => :register_response, # panel
|
8
|
+
0x0a => :register_response, # device
|
9
|
+
0x02 => :register_success,
|
10
|
+
|
11
|
+
0x03 => :program_stopping,
|
12
|
+
|
13
|
+
# Feeback and requests
|
14
|
+
0x05 => :action_info,
|
15
|
+
0x12 => :serial_data,
|
16
|
+
|
17
|
+
# Used for heartbeat
|
18
|
+
0x0d => :echo_request,
|
19
|
+
0x0e => :echo_response
|
20
|
+
}
|
21
|
+
PacketTypes.merge!(PacketTypes.invert)
|
22
|
+
|
23
|
+
class PacketHeader < BinData::Record
|
24
|
+
endian :big
|
25
|
+
|
26
|
+
uint8 :packet_type
|
27
|
+
uint16 :packet_size
|
28
|
+
|
29
|
+
def type
|
30
|
+
PacketTypes[packet_type]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true, encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
=begin Example Data
|
4
|
+
server:
|
5
|
+
0f 0001 02 (request IP ID Register, switch should send IPID)
|
6
|
+
switch:
|
7
|
+
0a 000a 00 05 a34240 02 00000000
|
8
|
+
(IPID: 0x03 to 0xFE === 05) (byte 5)
|
9
|
+
(RESP: 0x02)
|
10
|
+
server:
|
11
|
+
02 0004 00000003 (IP ID registry success)
|
12
|
+
failed response: 02 0003 ffff02
|
13
|
+
=end
|
14
|
+
|
15
|
+
class CresIP
|
16
|
+
class Register
|
17
|
+
def initialize(header = PacketHeader.new, payload = "\x02")
|
18
|
+
@header = header
|
19
|
+
@payload = payload
|
20
|
+
|
21
|
+
if @header.type == nil
|
22
|
+
@header.packet_type = PacketTypes[:register]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :header, :payload
|
27
|
+
|
28
|
+
def type
|
29
|
+
@header.type
|
30
|
+
end
|
31
|
+
|
32
|
+
def registering?
|
33
|
+
@header.type == :register_response
|
34
|
+
end
|
35
|
+
|
36
|
+
def reg_success?
|
37
|
+
@header.type == :register_success && @payload.length == 4
|
38
|
+
end
|
39
|
+
|
40
|
+
def respond(success = true)
|
41
|
+
head = PacketHeader.new
|
42
|
+
head.packet_type = PacketTypes[:register_success]
|
43
|
+
|
44
|
+
if success
|
45
|
+
Register.new(head, "\x00\x00\x00\x03")
|
46
|
+
else
|
47
|
+
Register.new(head, "\xff\xff\x02")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def register(ipid = 5, type = 0x0a)
|
52
|
+
# IPID Range: 0x03..0xFE
|
53
|
+
|
54
|
+
head = PacketHeader.new
|
55
|
+
# I think 0x0A is a switcher register response
|
56
|
+
# and 0x01 is touch screen
|
57
|
+
head.packet_type = type
|
58
|
+
payload = if type == 0x0a
|
59
|
+
# 0a000a00 ipid a342400200000000
|
60
|
+
"\x00#{ipid.chr}\xa3\x42\x40\x02\x00\x00\x00\x00"
|
61
|
+
else
|
62
|
+
# 0100077F00000100 ipid 40
|
63
|
+
"\x7F\x00\x00\x01\x00#{ipid.chr}\x40"
|
64
|
+
end
|
65
|
+
Register.new(head, payload)
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_binary_s
|
69
|
+
@header.packet_size = @payload.bytesize
|
70
|
+
"#{@header.to_binary_s}#{@payload}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true, encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
# NOTE:: No example data
|
4
|
+
|
5
|
+
class CresIP
|
6
|
+
class SerialData
|
7
|
+
def initialize(header, payload)
|
8
|
+
@header = header
|
9
|
+
@payload = payload
|
10
|
+
|
11
|
+
@value = parse_serial_data(payload.bytes)
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :header, :payload
|
15
|
+
|
16
|
+
def type
|
17
|
+
@header.type
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
|
24
|
+
Encodings = {
|
25
|
+
3 => 'ASCII-8BIT',
|
26
|
+
7 => 'UTF-16BE'
|
27
|
+
}
|
28
|
+
def parse_serial_data(bytes)
|
29
|
+
len = (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3]
|
30
|
+
join = 1 + (bytes[5] << 8) + bytes[6]
|
31
|
+
encoding = bytes[7]
|
32
|
+
string = bytes[8...(len + 4)].pack('c*')
|
33
|
+
enc = Encodings[encoding]
|
34
|
+
|
35
|
+
# Not sure if this will work as don't have any sample data.
|
36
|
+
# Reference: https://github.com/ironiridis/control4go/blob/master/crestron/packets.go#L149
|
37
|
+
string.force_encoding(enc) if enc
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/spec/cresip_spec.rb
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
# frozen_string_literal: true, encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'cresip'
|
4
|
+
|
5
|
+
|
6
|
+
describe CresIP do
|
7
|
+
before :each do
|
8
|
+
@packets = []
|
9
|
+
@cip = CresIP.new do |packet|
|
10
|
+
@packets << packet
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should parse echo requests" do
|
15
|
+
@cip.read("\x0d\x00\x02\x00\x00")
|
16
|
+
expect(@packets.length).to be(1)
|
17
|
+
|
18
|
+
echo = @packets[0]
|
19
|
+
expect(echo.to_binary_s).to eq("\x0d\x00\x02\x00\x00")
|
20
|
+
expect(echo.is_response?).to be(false)
|
21
|
+
expect(echo.response.is_response?).to be(true)
|
22
|
+
expect(echo.response.to_binary_s).to eq("\x0e\x00\x02\x00\x00")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should perform registration tasks" do
|
26
|
+
req = CresIP::Register.new
|
27
|
+
expect(req.to_binary_s).to eq("\x0f\x00\x01\x02")
|
28
|
+
|
29
|
+
@cip.read(req.to_binary_s)
|
30
|
+
expect(@packets.length).to be(1)
|
31
|
+
|
32
|
+
# Test basic parsing
|
33
|
+
req = @packets[0]
|
34
|
+
expect(req.to_binary_s).to eq("\x0f\x00\x01\x02")
|
35
|
+
expect(req.registering?).to be(false)
|
36
|
+
expect(req.reg_success?).to be(false)
|
37
|
+
|
38
|
+
# Test responding to the registration request
|
39
|
+
resp = req.register
|
40
|
+
expect(resp.to_binary_s).to eq("\x0a\x00\x0a\x00\x05\xa3\x42\x40\x02\x00\x00\x00\x00")
|
41
|
+
@cip.read(resp.to_binary_s)
|
42
|
+
expect(@packets.length).to be(2)
|
43
|
+
req = @packets[-1]
|
44
|
+
expect(req.to_binary_s).to eq("\x0a\x00\x0a\x00\x05\xa3\x42\x40\x02\x00\x00\x00\x00")
|
45
|
+
expect(req.registering?).to be(true)
|
46
|
+
expect(req.reg_success?).to be(false)
|
47
|
+
|
48
|
+
# Test responding to the registration request
|
49
|
+
resp = req.respond
|
50
|
+
expect(resp.to_binary_s).to eq("\x02\x00\x04\x00\x00\x00\x03")
|
51
|
+
@cip.read(resp.to_binary_s)
|
52
|
+
expect(@packets.length).to be(3)
|
53
|
+
req = @packets[-1]
|
54
|
+
expect(req.to_binary_s).to eq("\x02\x00\x04\x00\x00\x00\x03")
|
55
|
+
expect(req.registering?).to be(false)
|
56
|
+
expect(req.reg_success?).to be(true)
|
57
|
+
|
58
|
+
# Test a failed response
|
59
|
+
resp = req.respond false
|
60
|
+
expect(resp.to_binary_s).to eq("\x02\x00\x03\xff\xff\x02")
|
61
|
+
@cip.read(resp.to_binary_s)
|
62
|
+
expect(@packets.length).to be(4)
|
63
|
+
req = @packets[-1]
|
64
|
+
expect(req.to_binary_s).to eq("\x02\x00\x03\xff\xff\x02")
|
65
|
+
expect(req.registering?).to be(false)
|
66
|
+
expect(req.reg_success?).to be(false)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should parse digital requests" do
|
70
|
+
@cip.read("\x05\x00\x06\x00\x00\x03\x00\x13\x00")
|
71
|
+
expect(@packets.length).to be(1)
|
72
|
+
|
73
|
+
# Test basic parsing
|
74
|
+
req = @packets[0]
|
75
|
+
expect(req.to_binary_s).to eq("\x05\x00\x06\x00\x00\x03\x00\x13\x00")
|
76
|
+
expect(req.feedback?).to be(true)
|
77
|
+
expect(req.join).to be(20)
|
78
|
+
expect(req.value).to be(true)
|
79
|
+
|
80
|
+
# Test changing the value and type
|
81
|
+
req.set_value(false)
|
82
|
+
expect(req.value).to be(false)
|
83
|
+
expect(req.join).to be(20)
|
84
|
+
expect(req.feedback?).to be(false)
|
85
|
+
expect(req.to_binary_s).to eq("\x05\x00\x06\x00\x00\x03\x27\x13\x80")
|
86
|
+
|
87
|
+
# Test changing the join value and type
|
88
|
+
req.set_value(false, type: :feedback, join: 22)
|
89
|
+
expect(req.value).to be(false)
|
90
|
+
expect(req.join).to be(22)
|
91
|
+
expect(req.feedback?).to be(true)
|
92
|
+
expect(req.to_binary_s).to eq("\x05\x00\x06\x00\x00\x03\x00\x15\x80")
|
93
|
+
|
94
|
+
# Test generated values parse properly
|
95
|
+
@cip.read(req.to_binary_s)
|
96
|
+
expect(@packets.length).to be(2)
|
97
|
+
|
98
|
+
req2 = @packets[-1]
|
99
|
+
expect(req2.value).to be(false)
|
100
|
+
expect(req2.join).to be(22)
|
101
|
+
expect(req2.feedback?).to be(true)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should parse analog requests" do
|
105
|
+
@cip.read("\x05\x00\x08\x00\x00\x05\x14\x00\x42\x04\xd2")
|
106
|
+
expect(@packets.length).to be(1)
|
107
|
+
|
108
|
+
# Test basic parsing
|
109
|
+
req = @packets[0]
|
110
|
+
expect(req.to_binary_s).to eq("\x05\x00\x08\x00\x00\x05\x14\x00\x42\x04\xd2")
|
111
|
+
expect(req.feedback?).to be(false)
|
112
|
+
expect(req.join).to be(67)
|
113
|
+
expect(req.value).to be(1234)
|
114
|
+
|
115
|
+
# Test changing the value
|
116
|
+
req.set_value(45)
|
117
|
+
expect(req.value).to be(45)
|
118
|
+
expect(req.join).to be(67)
|
119
|
+
expect(req.feedback?).to be(false)
|
120
|
+
expect(req.to_binary_s).to eq("\x05\x00\x08\x00\x00\x05\x14\x00\x42\x00\x2d")
|
121
|
+
|
122
|
+
# Test changing the value, type and join
|
123
|
+
req.set_value(46, type: :feedback, join: 22)
|
124
|
+
expect(req.value).to be(46)
|
125
|
+
expect(req.join).to be(22)
|
126
|
+
expect(req.feedback?).to be(true)
|
127
|
+
expect(req.to_binary_s).to eq("\x05\x00\x08\x00\x00\x05\x01\x00\x15\x00\x2e")
|
128
|
+
|
129
|
+
# Test generated values parse properly
|
130
|
+
@cip.read(req.to_binary_s)
|
131
|
+
expect(@packets.length).to be(2)
|
132
|
+
|
133
|
+
req2 = @packets[-1]
|
134
|
+
expect(req2.value).to be(46)
|
135
|
+
expect(req2.join).to be(22)
|
136
|
+
expect(req2.feedback?).to be(true)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should parse serial requests" do
|
140
|
+
@cip.read("\x05\x00\x18\x00\x00\x15\x12\x15\x53\x74\x72\x65\x61\x6d\x69\x6e\x67\x20\x44\x6f\x77\x6e\x73\x63\x61\x6c\x65")
|
141
|
+
expect(@packets.length).to be(1)
|
142
|
+
|
143
|
+
# Test basic parsing
|
144
|
+
req = @packets[0]
|
145
|
+
expect(req.to_binary_s).to eq("\x05\x00\x18\x00\x00\x15\x12\x15\x53\x74\x72\x65\x61\x6d\x69\x6e\x67\x20\x44\x6f\x77\x6e\x73\x63\x61\x6c\x65")
|
146
|
+
expect(req.feedback?).to be(false)
|
147
|
+
expect(req.join).to be(21)
|
148
|
+
expect(req.value).to eq('Streaming Downscale')
|
149
|
+
|
150
|
+
# Test changing the value
|
151
|
+
req.set_value('Input 16', join: 15)
|
152
|
+
expect(req.value).to eq('Input 16')
|
153
|
+
expect(req.join).to be(15)
|
154
|
+
expect(req.feedback?).to be(false)
|
155
|
+
expect(req.to_binary_s).to eq("\x05\x00\x0d\x00\x00\x0a\x12\x0f\x49\x6e\x70\x75\x74\x20\x31\x36")
|
156
|
+
|
157
|
+
# Test generated values parse properly
|
158
|
+
@cip.read(req.to_binary_s)
|
159
|
+
expect(@packets.length).to be(2)
|
160
|
+
|
161
|
+
req2 = @packets[-1]
|
162
|
+
expect(req.value).to eq('Input 16')
|
163
|
+
expect(req.join).to be(15)
|
164
|
+
expect(req.feedback?).to be(false)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should work with unknown requests" do
|
168
|
+
# I don't know the format of the date and time data
|
169
|
+
@cip.read("\x05\x00\x0b\x00\x00\x08\x08\x0e\x23\x07\x10\x09\x22\x16")
|
170
|
+
expect(@packets.length).to be(1)
|
171
|
+
|
172
|
+
# Test basic parsing
|
173
|
+
req = @packets[0]
|
174
|
+
expect(req.to_binary_s).to eq("\x05\x00\x0b\x00\x00\x08\x08\x0e\x23\x07\x10\x09\x22\x16")
|
175
|
+
expect(req.feedback?).to be(false)
|
176
|
+
expect(req.join).to be(nil)
|
177
|
+
expect(req.value).to be(nil)
|
178
|
+
expect(req.type).to be(:date_and_time)
|
179
|
+
|
180
|
+
# Not sure what the point of the updates incomming packet are
|
181
|
+
@cip.read("\x05\x00\x06\x00\x00\x03\x03\x21\x07")
|
182
|
+
expect(@packets.length).to be(2)
|
183
|
+
|
184
|
+
# Test basic parsing
|
185
|
+
req = @packets[-1]
|
186
|
+
expect(req.to_binary_s).to eq("\x05\x00\x06\x00\x00\x03\x03\x21\x07")
|
187
|
+
expect(req.feedback?).to be(false)
|
188
|
+
expect(req.join).to be(nil)
|
189
|
+
expect(req.value).to be(nil)
|
190
|
+
expect(req.type).to be(:update_request_incomming)
|
191
|
+
|
192
|
+
# Pretty sure this is a DM switch packet...
|
193
|
+
@cip.read("\x05\x00\x0a\x00\x00\x07\x20\x01\x04\x15\x00\xf2\x03")
|
194
|
+
expect(@packets.length).to be(3)
|
195
|
+
|
196
|
+
# Test basic parsing
|
197
|
+
req = @packets[-1]
|
198
|
+
expect(req.to_binary_s).to eq("\x05\x00\x0a\x00\x00\x07\x20\x01\x04\x15\x00\xf2\x03")
|
199
|
+
expect(req.feedback?).to be(false)
|
200
|
+
expect(req.join).to be(nil)
|
201
|
+
expect(req.value).to be(nil)
|
202
|
+
expect(req.type).to be(nil)
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'should buffer messages' do
|
206
|
+
@cip.read("\x05\x00\x0b\x00\x00\x08\x08\x0e\x23\x07\x10\x09\x22")
|
207
|
+
expect(@packets.length).to be(0)
|
208
|
+
|
209
|
+
@cip.read("\x16\x05\x00\x0b\x00\x00\x08\x08\x0e\x23\x07\x10\x09\x22\x16")
|
210
|
+
expect(@packets.length).to be(2)
|
211
|
+
end
|
212
|
+
end
|
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cresip
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stephen von Takach
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bindata
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '11'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '11'
|
69
|
+
description: " Constructs and parses Crestron IP packets allowing you to communicate
|
70
|
+
with Crestron devices without a controller\n"
|
71
|
+
email:
|
72
|
+
- steve@cotag.me
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files:
|
76
|
+
- README.md
|
77
|
+
files:
|
78
|
+
- README.md
|
79
|
+
- cresip.gemspec
|
80
|
+
- lib/cresip.rb
|
81
|
+
- lib/cresip/action.rb
|
82
|
+
- lib/cresip/echo.rb
|
83
|
+
- lib/cresip/header.rb
|
84
|
+
- lib/cresip/register.rb
|
85
|
+
- lib/cresip/serial.rb
|
86
|
+
- spec/cresip_spec.rb
|
87
|
+
homepage: https://github.com/advancedcontrol/ruby-crescip
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.5.1
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: Crestron IP protocol on Ruby
|
111
|
+
test_files:
|
112
|
+
- spec/cresip_spec.rb
|