monome_serial 1.0.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 @@
1
+ Sam Aaron - samaaron@gmail.com
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2009 Sam Aaron
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,79 @@
1
+ make some kind of use of these mappings...
2
+ MMAP_COORDS_256 = {
3
+ [0,0] => {
4
+ :top => ["00001111"],
5
+ :bottom => ["11110000"],
6
+ :left => ["00000000"],
7
+ :right => ["11111111"]
8
+ },
9
+
10
+ [15,15] => {
11
+ :top => ["11110000"],
12
+ :bottom => ["00001111"],
13
+ :left => ["11111111"],
14
+ :right => ["00000000"]
15
+ },
16
+
17
+ [7,7] => {
18
+ :top => ["01111000"],
19
+ :bottom => ["10000111"],
20
+ :left => ["01110111"],
21
+ :right => ["10001000"]
22
+ },
23
+
24
+ [2,9] => {
25
+ :top => ["10011101"],
26
+ :bottom => ["01100010"],
27
+ :left => ["00101001"],
28
+ :right => ["11010110"]
29
+ },
30
+
31
+ [10,4] => {
32
+ :top => ["01000101"],
33
+ :bottom => ["10111010"],
34
+ :left => ["10100100"],
35
+ :right => ["01011011"]
36
+ }
37
+ }
38
+
39
+ PMAP_COORDS_TO_MMAP_COORDS = {
40
+ #pmap #mmap
41
+ :top => :right,
42
+ :bottom => :left,
43
+ :left => :top,
44
+ :right => :bottom
45
+ }
46
+
47
+ MMAP_ROW_256 = {
48
+ [1,255] => {
49
+ #left to right, 11111111
50
+ :right => ["01001110", "11111111"],
51
+ :bottom => ["01011110", "11111111"],
52
+ :left => ["01000001", "11111111"],
53
+ :top => ["01010001", "11111111"]
54
+ },
55
+
56
+ [1,0] => {
57
+ #left to right, 00000000
58
+ :right => ["01001110", "00000000"],
59
+ :bottom => ["01011110", "00000000"],
60
+ :left => ["01000001", "00000000"],
61
+ :top => ["01010001", "00000000"]
62
+ },
63
+
64
+ [1,197] => {
65
+ #left to right, 10100011
66
+ :right => ["01001110", "10100011"],
67
+ :bottom => ["01011110", "11000101"],
68
+ :left => ["01000001", "11000101"],
69
+ :top => ["01010001", "10100011"]
70
+ },
71
+
72
+ [1, 197, 47] => {
73
+ #left to right, 1010001111110100
74
+ :right => ["01101110", "11110100", "10100011"],
75
+ :bottom => ["01111110", "11000101", "00101111"],
76
+ :left => ["01100001", "11000101", "00101111"],
77
+ :top => ["01110001", "11110100", "10100011"]
78
+ }
79
+ }
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'monome_serial'
3
+
4
+ thread = MonomeSerial::Examples::Toggle.new.start
5
+ thread.join
6
+
@@ -0,0 +1,40 @@
1
+ #require external libraries
2
+ require 'activesupport'
3
+ require 'fcntl'
4
+
5
+ require 'monome_serial/serial_communicator'
6
+ require 'monome_serial/serial_communicator/communicator'
7
+ require 'monome_serial/serial_communicator/dummy_communicator'
8
+ require 'monome_serial/serial_communicator/binary_patterns/series'
9
+ require 'monome_serial/serial_communicator/binary_patterns/fourtyh'
10
+ require 'monome_serial/monome_communicator'
11
+ require 'monome_serial/examples/toggle'
12
+
13
+ module MonomeSerial
14
+ class NoMonomesFoundError < StandardError ; end
15
+
16
+ def self.detect_monome
17
+ detect_monomes.first
18
+ end
19
+
20
+ def self.detect_monomes
21
+ find_ttys.map{|tty| MonomeCommunicator.new(tty)}
22
+ end
23
+
24
+ def self.find_ttys
25
+ possible_monome_io_file_matchers = ['/dev/ttyUSB*', '/dev/tty.usbserial-m*']
26
+ files = possible_monome_io_file_matchers.inject([]) do |files, to_try|
27
+ files << Dir[to_try]
28
+ end
29
+
30
+ files.flatten!
31
+
32
+ if files.empty? then
33
+ raise NoMonomesFoundError,
34
+ "No monomes were found connected to your computer"
35
+ end
36
+
37
+ files
38
+ end
39
+ end
40
+
@@ -0,0 +1,44 @@
1
+ module MonomeSerial
2
+ module Examples
3
+ class Toggle
4
+ def initialize
5
+
6
+ @monome = MonomeSerial.detect_monome
7
+ @light_lit = Hash.new(false)
8
+ end
9
+
10
+ # Enter a loop in which you read events from the monome and if the
11
+ # event is a :keypress, then toggle the led on the monome
12
+ def start
13
+ Thread.new do
14
+ loop do
15
+ action, x, y = @monome.read
16
+ toggle_led(x,y) if action == :keydown
17
+ end
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def toggle_led(x,y)
24
+ toggle_led_on_monome(x,y)
25
+ toggle_led_status(x,y)
26
+ end
27
+
28
+ # Depending on the state of the @light_lit hash for the given
29
+ # coordinates, extinguish or illuminate the monome's lamp
30
+ def toggle_led_on_monome(x,y)
31
+ if @light_lit[[x,y]]
32
+ @monome.extinguish_lamp(x,y)
33
+ else
34
+ @monome.illuminate_lamp(x,y)
35
+ end
36
+ end
37
+
38
+ def toggle_led_status(x,y)
39
+ @light_lit[[x,y]] = !@light_lit[[x,y]]
40
+ end
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,90 @@
1
+ module MonomeSerial
2
+ class MonomeCommunicator
3
+ #It's important to note that the vanilla behaviour of these methods
4
+ #doesn't match that of the OSC protocol specification as implemented
5
+ #by the original OS X MonomeSerial application. In order to match
6
+ #these behviours it is necessary to map the calls appropriately for
7
+ #the given device and rotation. This class just provides raw access
8
+ #to the serial protocol and serves it unadultered.
9
+
10
+ attr_reader :communicator, :serial, :protocol
11
+
12
+ def initialize(tty_path, protocol="series")
13
+ raise ArgumentError, "Unexpected protocol type: #{protocol}. Expected 40h or series" unless protocol == "40h" || protocol == "series"
14
+
15
+ @protocol = protocol
16
+
17
+ #try to pull out serial for the monome represented by
18
+ #this tty_path
19
+ match = tty_path.match /m(\d+h?)-(\d+)/
20
+ @serial = match ? match[2] : "Serial Unknown"
21
+
22
+ #get communicator (will return a DummyCommunicator if the path
23
+ #isn't correct)
24
+ @communicator = SerialCommunicator.get_communicator(tty_path)
25
+
26
+ #include the correct binary patterns
27
+ if @protocol == "40h"
28
+ extend SerialCommunicator::BinaryPatterns::Fourtyh
29
+ else
30
+ extend SerialCommunicator::BinaryPatterns::Series
31
+ end
32
+ end
33
+
34
+ def illuminate_lamp(x,y)
35
+ @communicator.write([led_on_pattern, x_y_coord_pattern(x,y)])
36
+ end
37
+
38
+ def extinguish_lamp(x,y)
39
+ @communicator.write([led_off_pattern, x_y_coord_pattern(x,y)])
40
+ end
41
+
42
+ def illuminate_row(row, pattern)
43
+ case pattern.size
44
+ when 8 then
45
+ @communicator.write([row_of_8_pattern(row), pattern])
46
+ when 16 then
47
+ @communicator.write([row_of_16_pattern(row), pattern[0..7], pattern[8..15]])
48
+ else
49
+ raise ArgumentError, "Incorrect length of pattern sent to MonomeSerial::Monome#illumninate_row. Expected 8 or 16, got #{pattern.size}"
50
+ end
51
+ end
52
+
53
+ def illuminate_column(col, pattern)
54
+ case pattern.size
55
+ when 8 then
56
+ @communicator.write([col_of_8_pattern(col), pattern])
57
+ when 16 then
58
+ @communicator.write([col_of_16_pattern(col), pattern[0..7], pattern[8..15]])
59
+ else
60
+ raise ArgumentError, "Incorrect length of pattern sent to MonomeSerial::Monome#illumninate_col. Expected 8 or 16, got #{pattern.size}"
61
+ end
62
+ end
63
+
64
+ def illuminate_all
65
+ @communicator.write([all_pattern])
66
+ end
67
+
68
+ def extinguish_all
69
+ @communicator.write([clear_pattern])
70
+ end
71
+
72
+ def illuminate_frame(quadrant, patterns)
73
+ raise ArgumentError, "Incorrect number of patterns sent to MonomeSerial::Monome#illuminate_frame. Expected 8, got #{patterns.size}" unless patterns.size == 8
74
+ reversed_patterns = patterns.map{|pat| pat.reverse}
75
+ @communicator.write([frame_pattern(quadrant), *reversed_patterns])
76
+ end
77
+
78
+ def brightness=(intensity)
79
+ @communicator.write([brightness_pattern(intensity)])
80
+ end
81
+
82
+ def read
83
+ @communicator.read
84
+ end
85
+
86
+ def is_real?
87
+ @communicator && @communicator.class != MonomeSerial::SerialCommunicator::DummyCommunicator
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,26 @@
1
+ module MonomeSerial
2
+ module SerialCommunicator
3
+ class << self
4
+ attr_accessor :suppress_warnings
5
+ end
6
+
7
+ def self.get_communicator(tty_path)
8
+ begin
9
+ raise IOError unless File.exists?(tty_path)
10
+ raise RuntimeError unless (RUBY_VERSION.split('.').join.to_i >= 191) && (Object.const_defined?("RUBY_ENGINE") && Object.const_get("RUBY_ENGINE") == "ruby")
11
+ require 'monome_serial/serial_communicator/real_communicator'
12
+ require 'termios'
13
+ return RealCommunicator.new(tty_path)
14
+ rescue IOError
15
+ puts "Supplied path tty IO file isn't valid, loading up DummyCommunicator instead of a real one" unless suppress_warnings
16
+ return DummyCommunicator.new
17
+ rescue RuntimeError
18
+ puts "Incorrect Ruby version (want MRI Ruby 1.9.1 or higher), loading up DummyCommunicator instead of a real one" unless suppress_warnings
19
+ return DummyCommunicator.new
20
+ rescue LoadError
21
+ puts "Could not load the termios extension. Please install it. Loading up DummyCommunicator instead of a real one" unless suppress_warnings
22
+ return DummyCommunicator.new
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,54 @@
1
+ module MonomeSerial
2
+ module SerialCommunicator
3
+ module BinaryPatterns
4
+ module Fourtyh
5
+ #please implement me
6
+ #http://docs.monome.org/doku.php?id=tech:protocol:40h
7
+
8
+ def led_on_pattern
9
+ raise NotImplementedError, "please implement me"
10
+ end
11
+
12
+ def led_off_pattern
13
+ raise NotImplementedError, "please implement me"
14
+ end
15
+
16
+ def x_y_coord_pattern(x,y)
17
+ raise NotImplementedError, "please implement me"
18
+ end
19
+
20
+ def row_of_8_pattern(row)
21
+ raise NotImplementedError, "please implement me"
22
+ end
23
+
24
+ def row_of_16_pattern(row)
25
+ raise NotImplementedError, "please implement me"
26
+ end
27
+
28
+ def col_of_8_pattern(col)
29
+ raise NotImplementedError, "please implement me"
30
+ end
31
+
32
+ def col_of_16_pattern(col)
33
+ raise NotImplementedError, "please implement me"
34
+ end
35
+
36
+ def clear_pattern
37
+ raise NotImplementedError, "please implement me"
38
+ end
39
+
40
+ def all_pattern
41
+ raise NotImplementedError, "please implement me"
42
+ end
43
+
44
+ def frame_pattern(quadrant)
45
+ raise NotImplementedError, "please implement me"
46
+ end
47
+
48
+ def brightness_pattern(brightness)
49
+ raise NotImplementedError, "please implement me"
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,283 @@
1
+ module MonomeSerial
2
+ module SerialCommunicator
3
+ module BinaryPatterns
4
+ module Series
5
+ # monmome serial protocol series 256/128/64
6
+ # brian crabtree - tehn@monome.org
7
+ #
8
+ # revision: 070903
9
+ #
10
+ #
11
+ # from device:
12
+ #
13
+ # message id: (0) keydown
14
+ # bytes: 2
15
+ # format: iiii.... xxxxyyyy
16
+ # i (message id) = 0
17
+ # x (x value) = 0-15 (four bits)
18
+ # y (y value) = 0-15 (four bits)
19
+ # decode: id match: byte 0 >> 4 == 0
20
+ # x: byte 1 >> 4
21
+ # y: byte 1 & 0x0f
22
+ #
23
+ #
24
+ # message id: (1) keyup
25
+ # bytes: 2
26
+ # format: iiii.... xxxxyyyy
27
+ # i (message id) = 1
28
+ # x (x value) = 0-15 (four bits)
29
+ # y (y value) = 0-15 (four bits)
30
+ # decode: id match: byte 0 >> 4 == 1
31
+ # x: byte 1 >> 4
32
+ # y: byte 1 & 0x0f
33
+ #
34
+ #
35
+ #
36
+ # to device:
37
+ #
38
+ # message id: (2) led_on
39
+ # bytes: 2
40
+ # format: iiii.... xxxxyyyy
41
+ # i (message id) = 2
42
+ # x (x value) = 0-15 (four bits)
43
+ # y (y value) = 0-15 (four bits)
44
+ # encode: byte 0 = (id) << 4 = 32
45
+ # byte 1 = (x << 4) | y
46
+ #
47
+ #
48
+ # message id: (3) led_off
49
+ # bytes: 2
50
+ # format: iiii.... xxxxyyyy
51
+ # i (message id) = 3
52
+ # x (x value) = 0-15 (four bits)
53
+ # y (y value) = 0-15 (four bits)
54
+ # encode: byte 0 = (id) << 4 = 48
55
+ # byte 1 = (x << 4) | y
56
+ #
57
+ #
58
+ # message id: (4) led_row1
59
+ # bytes: 2
60
+ # format: iiiiyyyy aaaaaaaa
61
+ # i (message id) = 4
62
+ # y (row to update) = 0-15 (4 bits)
63
+ # a (row data 0-7) = 0-255 (8 bits)
64
+ # encode: byte 0 = ((id) << 4) | y = 64 + y
65
+ # byte 1 = a
66
+ #
67
+ #
68
+ # message id: (5) led_col1
69
+ # bytes: 2
70
+ # format: iiiixxxx aaaaaaaa
71
+ # i (message id) = 5
72
+ # x (col to update) = 0-15 (4 bits)
73
+ # a (col data 0-7) = 0-255 (8 bits)
74
+ # encode: byte 0 = ((id) << 4) | x = 80 + x
75
+ # byte 1 = a
76
+ #
77
+ #
78
+ # message id: (6) led_row2
79
+ # bytes: 3
80
+ # format: iiiiyyyy aaaaaaaa bbbbbbbb
81
+ # i (message id) = 6
82
+ # y (row to update) = 0-15 (4 bits)
83
+ # a (row data 0-7) = 0-255 (8 bits)
84
+ # b (row data 8-15) = 0-255 (8 bits)
85
+ # encode: byte 0 = ((id) << 4) | y = 96 + y
86
+ # byte 1 = a
87
+ # byte 2 = b
88
+ #
89
+ #
90
+ # message id: (7) led_col2
91
+ # bytes: 3
92
+ # format: iiiixxxx aaaaaaaa bbbbbbbb
93
+ # i (message id) = 7
94
+ # x (col to update) = 0-15 (4 bits)
95
+ # a (col data 0-7) = 0-255 (8 bits)
96
+ # b (col data 8-15) = 0-255 (8 bits)
97
+ # encode: byte 0 = ((id) << 4) | x = 112 + x
98
+ # byte 1 = a
99
+ # byte 2 = b
100
+ #
101
+ #
102
+ # message id: (8) led_frame
103
+ # bytes: 9
104
+ # format: iiii..qq aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh
105
+ # i (message id) = 8
106
+ # q (quadrant) = 0-3 (2 bits)
107
+ # a-h (row data 0-7, per row) = 0-255 (8 bits)
108
+ # encode: byte 0 = ((id) << 4) | q = 128 + q
109
+ # byte 1,2,3,4,5,6,7,8 = a,b,c,d,e,f,g,h
110
+ # note: quadrants are from top left to bottom right, as shown:
111
+ # 0 1
112
+ # 2 3
113
+ #
114
+ # message id: (9) clear
115
+ # bytes: 1
116
+ # format: iiii---c
117
+ # i (message id) = 9
118
+ # c (clear state) = 0-1 (1 bit)
119
+ # encode: byte 0 = ((id) << 4) | c = 144 + c
120
+ # note: clear state of 0 turns off all leds.
121
+ # clear state of 1 turns on all leds.
122
+ #
123
+ #
124
+ # message id: (10) intensity
125
+ # bytes: 1
126
+ # format: iiiibbbb
127
+ # i (message id) = 10
128
+ # b (brightness) = 0-15 (4 bits)
129
+ # encode: byte 0 = ((id) << 4) | b = 160 + b
130
+ #
131
+ #
132
+ # message id: (11) mode
133
+ # bytes: 1
134
+ # format: iiii..mm
135
+ # i (message id) = 11
136
+ # m (mode) = 0-3 (2 bits)
137
+ # encode: byte 0 = ((id) << 4) | m = 176 + m
138
+ # note: mode = 0 : normal
139
+ # mode = 1 : test (all leds on)
140
+ # mode = 2 : shutdown (all leds off)
141
+ #
142
+ #
143
+ #
144
+ #
145
+ #
146
+ # auxiliary ports
147
+ #
148
+ # to device:
149
+ #
150
+ # message id: (12) activate port
151
+ # bytes: 1
152
+ # format: iiiiaaaa
153
+ # i (message id) = 12
154
+ # a (which port) = 0-15 (four bits)
155
+ # encode: byte 0 = (id) << 4 = 192 + a
156
+ #
157
+ #
158
+ # message id: (13) deactivate port
159
+ # bytes: 1
160
+ # format: iiiiaaaa
161
+ # i (message id) = 13
162
+ # a (which port) = 0-15 (four bits)
163
+ # encode: byte 0 = (id) << 4 = 208 + a
164
+ #
165
+ #
166
+ # from device:
167
+ #
168
+ # message id: (14) auxiliary input
169
+ # bytes: 2
170
+ # format: iiiiaaaa dddddddd
171
+ # i (message id) = 14
172
+ # a (port number) = 0-15 (four bits)
173
+ # d (data) = 0-255 (eight bits)
174
+ # decode: id match: byte 0 >> 4 == 1
175
+ # a: byte 0 & 0x0f
176
+ # d: byte 1
177
+ INT_TO_BIN_STRING = {
178
+ 0 => "0000",
179
+ 1 => "0001",
180
+ 2 => "0010",
181
+ 3 => "0011",
182
+ 4 => "0100",
183
+ 5 => "0101",
184
+ 6 => "0110",
185
+ 7 => "0111",
186
+ 8 => "1000",
187
+ 9 => "1001",
188
+ 10 => "1010",
189
+ 11 => "1011",
190
+ 12 => "1100",
191
+ 13 => "1101",
192
+ 14 => "1110",
193
+ 15 => "1111"
194
+ }
195
+
196
+ X_Y_COORD_PATTERNS = (0..15).inject({}) do |hash, x|
197
+ (0..15).each {|y| hash[[x,y]] = INT_TO_BIN_STRING[x] + INT_TO_BIN_STRING[y]}
198
+ hash
199
+ end
200
+
201
+ EIGHT_LIGHT_ROW_PATTTERNS = (0..15).inject({}) do |hash, row|
202
+ hash[row] = "0100" + INT_TO_BIN_STRING[row]
203
+ hash
204
+ end
205
+
206
+ SIXTEEN_LIGHT_ROW_PATTERNS = (0..15).inject({}) do |hash, row|
207
+ hash[row] = "0110" + INT_TO_BIN_STRING[row]
208
+ hash
209
+ end
210
+
211
+
212
+ EIGHT_LIGHT_COL_PATTERNS = (0..15).inject({}) do |hash, row|
213
+ hash[row] = "0101" + INT_TO_BIN_STRING[row]
214
+ hash
215
+ end
216
+
217
+ SIXTEEN_LIGHT_COL_PATTERNS = (0..15).inject({}) do |hash, row|
218
+ hash[row] = "0111" + INT_TO_BIN_STRING[row]
219
+ hash
220
+ end
221
+
222
+ def led_on_pattern
223
+ "00100000"
224
+ end
225
+
226
+ def led_off_pattern
227
+ "00110000"
228
+ end
229
+
230
+ def x_y_coord_pattern(x, y)
231
+ X_Y_COORD_PATTERNS[[x,y]]
232
+ end
233
+
234
+ def row_of_8_pattern(row)
235
+ EIGHT_LIGHT_ROW_PATTTERNS[row]
236
+ end
237
+
238
+ def col_of_8_pattern(col)
239
+ EIGHT_LIGHT_COL_PATTERNS[col]
240
+ end
241
+
242
+ def row_of_16_pattern(row)
243
+ SIXTEEN_LIGHT_ROW_PATTERNS[row]
244
+ end
245
+
246
+ def col_of_16_pattern(col)
247
+ SIXTEEN_LIGHT_COL_PATTERNS[col]
248
+ end
249
+
250
+ def clear_pattern
251
+ "10010000"
252
+ end
253
+
254
+ def all_pattern
255
+ "10010001"
256
+ end
257
+
258
+ def frame_pattern(quadrant)
259
+ unless quadrant >= 1 && quadrant <= 4 then
260
+ raise ArgumentError,
261
+ "Expecting quadrant to be between 1 and 4 inclusively, got #{quadrant}"
262
+ end
263
+
264
+ quadrant_pattern = case quadrant
265
+ when 1 then "00"
266
+ when 2 then "01"
267
+ when 3 then "10"
268
+ when 4 then "11"
269
+ end
270
+ "100000" + quadrant_pattern
271
+ end
272
+
273
+
274
+ def brightness_pattern(brightness)
275
+ raise ArgumentError, "Expecting a brightness between 0 and 15 inclusively, got #{brightness}" unless brightness >= 0 && brightness <= 15
276
+
277
+ "1010" + INT_TO_BIN_STRING[brightness]
278
+ end
279
+
280
+ end
281
+ end
282
+ end
283
+ end