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.
@@ -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