cresip 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/acaprojects/ruby-cresip.svg?branch=master)](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
|