cresip 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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