hybridgroup-firmata 0.4.2 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -3
- data/README.md +1 -1
- data/examples/blink_led.rb +10 -5
- data/examples/blink_led_socket.rb +6 -5
- data/examples/digital_read.rb +15 -5
- data/examples/digital_read_socket.rb +12 -5
- data/examples/wiichuck_read.rb +8 -10
- data/examples/wiichuck_read_socket.rb +29 -0
- data/firmata.gemspec +2 -2
- data/lib/firmata/board.rb +234 -260
- data/lib/firmata/constants.rb +80 -0
- data/lib/firmata/event.rb +1 -1
- data/lib/firmata/version.rb +1 -1
- data/lib/firmata.rb +2 -1
- data/test/board_test.rb +153 -149
- data/test/fake_serial_port.rb +49 -48
- metadata +7 -4
data/lib/firmata/board.rb
CHANGED
@@ -1,89 +1,22 @@
|
|
1
1
|
require 'stringio'
|
2
|
-
require '
|
3
|
-
require "firmata/event"
|
2
|
+
require 'event_emitter'
|
4
3
|
|
5
4
|
module Firmata
|
6
5
|
class Board
|
7
|
-
include
|
6
|
+
include EventEmitter
|
8
7
|
|
9
8
|
# Internal: Data structure representing a pin on Arduino.
|
10
9
|
Pin = Struct.new(:supported_modes, :mode, :value, :analog_channel)
|
11
10
|
|
12
|
-
# Public: Fixnum byte for pin mode input.
|
13
|
-
INPUT = 0x00
|
14
|
-
# Public: Fixnum byte for pin mode output.
|
15
|
-
OUTPUT = 0x01
|
16
|
-
# Public: Fixnum byte for pin mode analog.
|
17
|
-
ANALOG = 0x02
|
18
|
-
# Public: Fixnum byte for pin mode pulse width modulation.
|
19
|
-
PWM = 0x03
|
20
|
-
# Public: Fixnum byte for pin mode servo.
|
21
|
-
SERVO = 0x04
|
22
|
-
|
23
|
-
LOW = 0
|
24
|
-
HIGH = 1
|
25
|
-
|
26
|
-
# Internal: Fixnum byte command for protocol version
|
27
|
-
REPORT_VERSION = 0xF9
|
28
|
-
# Internal: Fixnum byte command for system reset
|
29
|
-
SYSTEM_RESET = 0xFF
|
30
|
-
# Internal: Fixnum byte command for digital I/O message
|
31
|
-
DIGITAL_MESSAGE = 0x90
|
32
|
-
# Pubilc: Fixnum byte for range for digital pins for digital 2 byte data format
|
33
|
-
DIGITAL_MESSAGE_RANGE = 0x90..0x9F
|
34
|
-
# Internal: Fixnum byte command for an analog I/O message
|
35
|
-
ANALOG_MESSAGE = 0xE0
|
36
|
-
# Internal: Fixnum byte range for analog pins for analog 14-bit data format
|
37
|
-
ANALOG_MESSAGE_RANGE = 0xE0..0xEF
|
38
|
-
# Internal: Fixnum byte command to report analog pin
|
39
|
-
REPORT_ANALOG = 0xC0
|
40
|
-
# Internal: Fixnum byte command to report digital port
|
41
|
-
REPORT_DIGITAL = 0xD0
|
42
|
-
# Internal: Fixnum byte command to set pin mode (I/O)
|
43
|
-
PIN_MODE = 0xF4
|
44
|
-
|
45
|
-
# Internal: Fixnum byte command for start of Sysex message
|
46
|
-
START_SYSEX = 0xF0
|
47
|
-
# Internal: Fixnum byte command for end of Sysex message
|
48
|
-
END_SYSEX = 0xF7
|
49
|
-
# Internal: Fixnum byte sysex command for capabilities query
|
50
|
-
CAPABILITY_QUERY = 0x6B
|
51
|
-
# Internal: Fixnum byte sysex command for capabilities response
|
52
|
-
CAPABILITY_RESPONSE = 0x6C
|
53
|
-
# Internal: Fixnum byte sysex command for pin state query
|
54
|
-
PIN_STATE_QUERY = 0x6D
|
55
|
-
# Internal: Fixnum byte sysex command for pin state response
|
56
|
-
PIN_STATE_RESPONSE = 0x6E
|
57
|
-
# Internal: Fixnum byte sysex command for analog mapping query
|
58
|
-
ANALOG_MAPPING_QUERY = 0x69
|
59
|
-
# Internal: Fixnum byte sysex command for analog mapping response
|
60
|
-
ANALOG_MAPPING_RESPONSE = 0x6A
|
61
|
-
# Internal: Fixnum byte sysex command for i2c request
|
62
|
-
I2C_REQUEST = 0x76
|
63
|
-
# Internal: Fixnum byte sysex command for i2c reply
|
64
|
-
I2C_REPLY = 0x77
|
65
|
-
# Internal: Fixnum byte sysex command for i2c config
|
66
|
-
I2C_CONFIG = 0x78
|
67
|
-
# Internal: Fixnum byte sysex command for firmware query and response
|
68
|
-
FIRMWARE_QUERY = 0x79
|
69
|
-
# Internal: Fixnum byte i2c mode write
|
70
|
-
I2C_MODE_WRITE = 0x00
|
71
|
-
# Internal: Fixnum byte i2c mode read
|
72
|
-
I2C_MODE_READ = 0x01
|
73
|
-
# Internal: Fixnum byte i2c mode continous read
|
74
|
-
I2C_MODE_CONTINUOUS_READ = 0x02
|
75
|
-
# Internal: Fixnum byte i2c mode stop reading
|
76
|
-
I2C_MODE_STOP_READING = 0x03
|
77
|
-
|
78
11
|
# Public: Returns the SerialPort port the Arduino is attached to.
|
79
12
|
attr_reader :serial_port
|
80
13
|
# Public: Returns the Array of pins on Arduino.
|
81
14
|
attr_reader :pins
|
82
15
|
# Public: Returns the Array of analog pins on Arduino.
|
83
16
|
attr_reader :analog_pins
|
84
|
-
# Public: Returns the String firmware name of
|
17
|
+
# Public: Returns the String firmware name of Arduino.
|
85
18
|
attr_reader :firmware_name
|
86
|
-
# Public: Returns array of any Events returned from
|
19
|
+
# Public: Returns array of any Events returned from ????
|
87
20
|
attr_reader :async_events
|
88
21
|
|
89
22
|
# Public: Initialize a Board
|
@@ -98,219 +31,45 @@ module Firmata
|
|
98
31
|
@serial_port = port
|
99
32
|
end
|
100
33
|
|
34
|
+
@serial_port_status = Port::OPEN
|
101
35
|
@major_version = 0
|
102
36
|
@minor_version = 0
|
37
|
+
@firmware_name = nil
|
103
38
|
@pins = []
|
104
39
|
@analog_pins = []
|
105
40
|
@connected = false
|
106
41
|
@async_events = []
|
42
|
+
|
43
|
+
trap_signals 'SIGHUP', 'SIGINT', 'SIGKILL', 'SIGTERM'
|
107
44
|
rescue LoadError
|
108
45
|
puts "Please 'gem install hybridgroup-serialport' for serial port support."
|
109
46
|
end
|
110
47
|
|
111
|
-
#
|
48
|
+
# Public: Check if a connection to Arduino has been made.
|
112
49
|
#
|
113
50
|
# Returns Boolean connected state.
|
114
51
|
def connected?
|
115
52
|
@connected
|
116
53
|
end
|
117
54
|
|
118
|
-
def event(name, *data)
|
119
|
-
async_events << Event.new(name, *data)
|
120
|
-
emit(name, *data)
|
121
|
-
end
|
122
|
-
|
123
55
|
# Public: Make connection to Arduino.
|
124
56
|
#
|
125
57
|
# Returns Firmata::Board board.
|
126
58
|
def connect
|
127
59
|
unless @connected
|
128
|
-
once('report_version', ->() do
|
129
|
-
once('firmware_query', ->() do
|
130
|
-
once('capability_query', ->() do
|
131
|
-
once('analog_mapping_query', ->() do
|
132
|
-
|
133
|
-
2.times { |i| toggle_pin_reporting(i) }
|
134
|
-
|
135
|
-
@connected = true
|
136
|
-
event('ready')
|
137
|
-
end)
|
138
|
-
query_analog_mapping
|
139
|
-
end)
|
140
|
-
query_capabilities
|
141
|
-
end)
|
142
|
-
end)
|
143
|
-
|
144
|
-
until connected?
|
145
|
-
read_and_process
|
146
|
-
delay(0.5)
|
147
|
-
end
|
148
|
-
end
|
149
60
|
|
150
|
-
|
151
|
-
end
|
61
|
+
handle_events!
|
152
62
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
#
|
159
|
-
# write(START_SYSEX, CAPABILITY_QUERY, END_SYSEX)
|
160
|
-
#
|
161
|
-
# Returns nothing.
|
162
|
-
def write(*commands)
|
163
|
-
serial_port.write_nonblock(commands.map(&:chr).join)
|
164
|
-
end
|
165
|
-
|
166
|
-
# Internal: Read data from the underlying serial port.
|
167
|
-
#
|
168
|
-
# Returns String data read for serial port.
|
169
|
-
def read
|
170
|
-
return serial_port.read_nonblock(1024)
|
171
|
-
rescue EOFError
|
172
|
-
rescue Errno::EAGAIN
|
173
|
-
end
|
174
|
-
|
175
|
-
# Internal: Process a series of bytes.
|
176
|
-
#
|
177
|
-
# data: The String data to process.
|
178
|
-
#
|
179
|
-
# Returns nothing.
|
180
|
-
def process(data)
|
181
|
-
bytes = StringIO.new(String(data))
|
182
|
-
while byte = bytes.getbyte
|
183
|
-
case byte
|
184
|
-
when REPORT_VERSION
|
185
|
-
@major_version = bytes.getbyte
|
186
|
-
@minor_version = bytes.getbyte
|
187
|
-
event('report_version')
|
188
|
-
|
189
|
-
when ANALOG_MESSAGE_RANGE
|
190
|
-
least_significant_byte = bytes.getbyte
|
191
|
-
most_significant_byte = bytes.getbyte
|
192
|
-
|
193
|
-
value = least_significant_byte | (most_significant_byte << 7)
|
194
|
-
pin = byte & 0x0F
|
195
|
-
|
196
|
-
if analog_pin = analog_pins[pin]
|
197
|
-
pins[analog_pin].value = value
|
198
|
-
|
199
|
-
event('analog-read', pin, value)
|
200
|
-
event("analog-read-#{pin}", value)
|
201
|
-
end
|
202
|
-
|
203
|
-
when DIGITAL_MESSAGE_RANGE
|
204
|
-
port = byte & 0x0F
|
205
|
-
first_bitmask = bytes.getbyte
|
206
|
-
second_bitmask = bytes.getbyte
|
207
|
-
port_value = first_bitmask | (second_bitmask << 7)
|
208
|
-
|
209
|
-
8.times do |i|
|
210
|
-
pin_number = 8 * port + i
|
211
|
-
if pin = pins[pin_number] and pin.mode == INPUT
|
212
|
-
value = (port_value >> (i & 0x07)) & 0x01
|
213
|
-
pin.value = value
|
214
|
-
event('digital-read', pin_number, value)
|
215
|
-
event("digital-read-#{pin_number}", value)
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
when START_SYSEX
|
220
|
-
current_buffer = [byte]
|
221
|
-
begin
|
222
|
-
current_buffer.push(bytes.getbyte)
|
223
|
-
end until current_buffer.last == END_SYSEX
|
224
|
-
|
225
|
-
command = current_buffer[1]
|
226
|
-
|
227
|
-
case command
|
228
|
-
when CAPABILITY_RESPONSE
|
229
|
-
supported_modes = 0
|
230
|
-
n = 0
|
231
|
-
|
232
|
-
current_buffer.slice(2, current_buffer.length - 3).each do |byte|
|
233
|
-
if byte == 127
|
234
|
-
modes = []
|
235
|
-
# the pin modes
|
236
|
-
[ INPUT, OUTPUT, ANALOG, PWM, SERVO ].each do |mode|
|
237
|
-
modes.push(mode) unless (supported_modes & (1 << mode)).zero?
|
238
|
-
end
|
239
|
-
|
240
|
-
@pins.push(Pin.new(modes, OUTPUT, 0))
|
241
|
-
|
242
|
-
supported_modes = 0
|
243
|
-
n = 0
|
244
|
-
next
|
245
|
-
end
|
246
|
-
|
247
|
-
supported_modes |= (1 << byte) if n.zero?
|
248
|
-
|
249
|
-
n ^= 1
|
250
|
-
end
|
251
|
-
|
252
|
-
event('capability_query')
|
253
|
-
|
254
|
-
when ANALOG_MAPPING_RESPONSE
|
255
|
-
pin_index = 0
|
256
|
-
|
257
|
-
current_buffer.slice(2, current_buffer.length - 3).each do |byte|
|
258
|
-
|
259
|
-
@pins[pin_index].analog_channel = byte
|
260
|
-
|
261
|
-
@analog_pins.push(pin_index) unless byte == 127
|
262
|
-
|
263
|
-
pin_index += 1
|
264
|
-
end
|
265
|
-
|
266
|
-
event('analog_mapping_query')
|
267
|
-
|
268
|
-
when PIN_STATE_RESPONSE
|
269
|
-
pin = pins[current_buffer[2]]
|
270
|
-
pin.mode = current_buffer[3]
|
271
|
-
pin.value = current_buffer[4]
|
272
|
-
|
273
|
-
pin.value |= (current_buffer[5] << 7) if current_buffer.size > 6
|
274
|
-
|
275
|
-
pin.value |= (current_buffer[6] << 14) if current_buffer.size > 7
|
276
|
-
|
277
|
-
when I2C_REPLY
|
278
|
-
# I2C reply
|
279
|
-
# 0 START_SYSEX (0xF0) (MIDI System Exclusive)
|
280
|
-
# 1 I2C_REPLY (0x77)
|
281
|
-
# 2 slave address (LSB)
|
282
|
-
# 3 slave address (MSB)
|
283
|
-
# 4 register (LSB)
|
284
|
-
# 5 register (MSB)
|
285
|
-
# 6 data 0 LSB
|
286
|
-
# 7 data 0 MSB
|
287
|
-
# n END_SYSEX (0xF7)
|
288
|
-
i2c_reply = {
|
289
|
-
:slave_address => current_buffer[2,2].pack("CC").unpack("v").first,
|
290
|
-
:register => current_buffer[4,2].pack("CC").unpack("v").first,
|
291
|
-
:data => [current_buffer[6,2].pack("CC").unpack("v").first]
|
292
|
-
}
|
293
|
-
i = 8
|
294
|
-
while current_buffer[i] != "0xF7".hex do
|
295
|
-
break if !(!current_buffer[i,2].nil? && current_buffer[i,2].count == 2)
|
296
|
-
i2c_reply[:data].push(current_buffer[i,2].pack("CC").unpack("v").first)
|
297
|
-
i += 2
|
298
|
-
end
|
299
|
-
event('i2c_reply', i2c_reply)
|
300
|
-
|
301
|
-
when FIRMWARE_QUERY
|
302
|
-
@firmware_name = current_buffer.slice(4, current_buffer.length - 5).reject { |b| b.zero? }.map(&:chr).join
|
303
|
-
event('firmware_query')
|
304
|
-
|
305
|
-
else
|
306
|
-
puts 'bad byte'
|
63
|
+
catch(:initialized) do
|
64
|
+
loop do
|
65
|
+
query_report_version #unless @major_version.zero?
|
66
|
+
sleep 0.1
|
67
|
+
read_and_process
|
307
68
|
end
|
308
69
|
end
|
309
70
|
end
|
310
|
-
|
311
|
-
|
312
|
-
rescue NoMethodError
|
313
|
-
# got some bad data or something? hack to just skip to next attempt to process...
|
71
|
+
|
72
|
+
self
|
314
73
|
end
|
315
74
|
|
316
75
|
# Public: Read the serial port and process the results
|
@@ -408,7 +167,7 @@ module Firmata
|
|
408
167
|
#
|
409
168
|
# Returns nothing.
|
410
169
|
def query_firmware
|
411
|
-
write(FIRMWARE_QUERY)
|
170
|
+
write(START_SYSEX, FIRMWARE_QUERY, END_SYSEX)
|
412
171
|
end
|
413
172
|
|
414
173
|
# Public: Ask the Arduino for the current configuration of any pin.
|
@@ -420,6 +179,11 @@ module Firmata
|
|
420
179
|
write(START_SYSEX, PIN_STATE_QUERY, pin.to_i, END_SYSEX)
|
421
180
|
end
|
422
181
|
|
182
|
+
#
|
183
|
+
def query_report_version
|
184
|
+
write REPORT_VERSION
|
185
|
+
end
|
186
|
+
|
423
187
|
# Public: Ask the Arduino about its capabilities and current state.
|
424
188
|
#
|
425
189
|
# Returns nothing.
|
@@ -470,7 +234,7 @@ module Firmata
|
|
470
234
|
|
471
235
|
def i2c_write_request(slave_address, *data)
|
472
236
|
address = [slave_address].pack("v")
|
473
|
-
ret = [START_SYSEX, I2C_REQUEST, address[0], (I2C_MODE_WRITE << 3)]
|
237
|
+
ret = [START_SYSEX, I2C_REQUEST, address[0], (I2C_MODE_WRITE << 3)]
|
474
238
|
data.each do |n|
|
475
239
|
ret.push([n].pack("v")[0])
|
476
240
|
ret.push([n].pack("v")[1])
|
@@ -496,5 +260,215 @@ module Firmata
|
|
496
260
|
ret.push(END_SYSEX)
|
497
261
|
write(*ret)
|
498
262
|
end
|
263
|
+
|
264
|
+
protected
|
265
|
+
# Dispatches an event
|
266
|
+
def event(name, *data)
|
267
|
+
async_events << Event.new(name, *data)
|
268
|
+
emit(name, *data)
|
269
|
+
end
|
270
|
+
|
271
|
+
private
|
272
|
+
def close
|
273
|
+
return if @serial_port_status == Port::CLOSE
|
274
|
+
@serial_port.close
|
275
|
+
@serial_port_status = Port::CLOSE
|
276
|
+
loop do
|
277
|
+
break if @serial_port.closed?
|
278
|
+
sleep 0.01
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
# Internal: Write data to the underlying serial port.
|
283
|
+
#
|
284
|
+
# commands - Zero or more byte commands to be written.
|
285
|
+
#
|
286
|
+
# Examples
|
287
|
+
#
|
288
|
+
# write(START_SYSEX, CAPABILITY_QUERY, END_SYSEX)
|
289
|
+
#
|
290
|
+
# Returns nothing.
|
291
|
+
def write(*commands)
|
292
|
+
serial_port.write_nonblock(commands.map(&:chr).join)
|
293
|
+
end
|
294
|
+
|
295
|
+
# Internal: Read data from the underlying serial port.
|
296
|
+
#
|
297
|
+
# Returns String data read for serial port.
|
298
|
+
def read
|
299
|
+
return serial_port.read_nonblock(1024)
|
300
|
+
rescue EOFError
|
301
|
+
rescue Errno::EAGAIN
|
302
|
+
end
|
303
|
+
|
304
|
+
# Internal: Process a series of bytes.
|
305
|
+
#
|
306
|
+
# data: The String data to process.
|
307
|
+
#
|
308
|
+
# Returns nothing.
|
309
|
+
def process(data)
|
310
|
+
bytes = StringIO.new(String(data))
|
311
|
+
while byte = bytes.getbyte
|
312
|
+
case byte
|
313
|
+
when REPORT_VERSION
|
314
|
+
@major_version = bytes.getbyte
|
315
|
+
@minor_version = bytes.getbyte
|
316
|
+
event :report_version
|
317
|
+
when ANALOG_MESSAGE_RANGE
|
318
|
+
least_significant_byte = bytes.getbyte
|
319
|
+
most_significant_byte = bytes.getbyte
|
320
|
+
|
321
|
+
value = least_significant_byte | (most_significant_byte << 7)
|
322
|
+
pin = byte & 0x0F
|
323
|
+
|
324
|
+
if analog_pin = analog_pins[pin]
|
325
|
+
pins[analog_pin].value = value
|
326
|
+
|
327
|
+
event :analog_read, pin, value
|
328
|
+
event("analog_read_#{pin}", value)
|
329
|
+
end
|
330
|
+
|
331
|
+
when DIGITAL_MESSAGE_RANGE
|
332
|
+
port = byte & 0x0F
|
333
|
+
first_bitmask = bytes.getbyte
|
334
|
+
second_bitmask = bytes.getbyte
|
335
|
+
port_value = first_bitmask | (second_bitmask << 7)
|
336
|
+
|
337
|
+
8.times do |i|
|
338
|
+
pin_number = 8 * port + i
|
339
|
+
if pin = pins[pin_number] and pin.mode == INPUT
|
340
|
+
value = (port_value >> (i & 0x07)) & 0x01
|
341
|
+
pin.value = value
|
342
|
+
event :digital_read, pin_number, value
|
343
|
+
event "digital_read_#{pin_number}", value
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
when START_SYSEX
|
348
|
+
current_buffer = [byte]
|
349
|
+
begin
|
350
|
+
current_buffer.push(bytes.getbyte)
|
351
|
+
end until current_buffer.last == END_SYSEX
|
352
|
+
|
353
|
+
command = current_buffer[1]
|
354
|
+
|
355
|
+
case command
|
356
|
+
when CAPABILITY_RESPONSE
|
357
|
+
supported_modes = 0
|
358
|
+
n = 0
|
359
|
+
|
360
|
+
current_buffer.slice(2, current_buffer.length - 3).each do |byte|
|
361
|
+
if byte == 127
|
362
|
+
modes = []
|
363
|
+
# the pin modes
|
364
|
+
[ INPUT, OUTPUT, ANALOG, PWM, SERVO ].each do |mode|
|
365
|
+
modes.push(mode) unless (supported_modes & (1 << mode)).zero?
|
366
|
+
end
|
367
|
+
|
368
|
+
@pins.push(Pin.new(modes, OUTPUT, 0))
|
369
|
+
|
370
|
+
supported_modes = 0
|
371
|
+
n = 0
|
372
|
+
next
|
373
|
+
end
|
374
|
+
|
375
|
+
supported_modes |= (1 << byte) if n.zero?
|
376
|
+
|
377
|
+
n ^= 1
|
378
|
+
end
|
379
|
+
|
380
|
+
event :capability_query
|
381
|
+
|
382
|
+
when ANALOG_MAPPING_RESPONSE
|
383
|
+
pin_index = 0
|
384
|
+
|
385
|
+
current_buffer.slice(2, current_buffer.length - 3).each do |byte|
|
386
|
+
|
387
|
+
@pins[pin_index].analog_channel = byte
|
388
|
+
|
389
|
+
@analog_pins.push(pin_index) unless byte == 127
|
390
|
+
|
391
|
+
pin_index += 1
|
392
|
+
end
|
393
|
+
|
394
|
+
event :analog_mapping_query
|
395
|
+
|
396
|
+
when PIN_STATE_RESPONSE
|
397
|
+
pin = pins[current_buffer[2]]
|
398
|
+
pin.mode = current_buffer[3]
|
399
|
+
pin.value = current_buffer[4]
|
400
|
+
|
401
|
+
pin.value |= (current_buffer[5] << 7) if current_buffer.size > 6
|
402
|
+
|
403
|
+
pin.value |= (current_buffer[6] << 14) if current_buffer.size > 7
|
404
|
+
|
405
|
+
when I2C_REPLY
|
406
|
+
# I2C reply
|
407
|
+
# 0 START_SYSEX (0xF0) (MIDI System Exclusive)
|
408
|
+
# 1 I2C_REPLY (0x77)
|
409
|
+
# 2 slave address (LSB)
|
410
|
+
# 3 slave address (MSB)
|
411
|
+
# 4 register (LSB)
|
412
|
+
# 5 register (MSB)
|
413
|
+
# 6 data 0 LSB
|
414
|
+
# 7 data 0 MSB
|
415
|
+
# n END_SYSEX (0xF7)
|
416
|
+
i2c_reply = {
|
417
|
+
:slave_address => current_buffer[2,2].pack("CC").unpack("v").first,
|
418
|
+
:register => current_buffer[4,2].pack("CC").unpack("v").first,
|
419
|
+
:data => [current_buffer[6,2].pack("CC").unpack("v").first]
|
420
|
+
}
|
421
|
+
i = 8
|
422
|
+
while current_buffer[i] != "0xF7".hex do
|
423
|
+
break if !(!current_buffer[i,2].nil? && current_buffer[i,2].count == 2)
|
424
|
+
i2c_reply[:data].push(current_buffer[i,2].pack("CC").unpack("v").first)
|
425
|
+
i += 2
|
426
|
+
end
|
427
|
+
event :i2c_reply, i2c_reply
|
428
|
+
|
429
|
+
when FIRMWARE_QUERY
|
430
|
+
@firmware_name = current_buffer.slice(4, current_buffer.length - 5).reject { |b| b.zero? }.map(&:chr).join
|
431
|
+
event :firmware_query
|
432
|
+
else
|
433
|
+
puts 'bad byte'
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
437
|
+
rescue StopIteration
|
438
|
+
# do nadda
|
439
|
+
rescue NoMethodError
|
440
|
+
# got some bad data or something? hack to just skip to next attempt to process...
|
441
|
+
end
|
442
|
+
|
443
|
+
def trap_signals(*signals)
|
444
|
+
signals.each do |signal|
|
445
|
+
trap signal do
|
446
|
+
close
|
447
|
+
exit
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
def handle_events!
|
453
|
+
once :report_version do
|
454
|
+
query_firmware unless @firmware_name
|
455
|
+
end
|
456
|
+
|
457
|
+
once :firmware_query do
|
458
|
+
query_capabilities
|
459
|
+
end
|
460
|
+
|
461
|
+
once :capability_query do
|
462
|
+
query_analog_mapping
|
463
|
+
end
|
464
|
+
|
465
|
+
once :analog_mapping_query do
|
466
|
+
2.times { |i| toggle_pin_reporting(i) }
|
467
|
+
|
468
|
+
@connected = true
|
469
|
+
event :ready
|
470
|
+
throw :initialized
|
471
|
+
end
|
472
|
+
end
|
499
473
|
end
|
500
474
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Firmata
|
2
|
+
|
3
|
+
module Port
|
4
|
+
OPEN = 1
|
5
|
+
CLOSE = 0
|
6
|
+
end
|
7
|
+
|
8
|
+
module PinModes
|
9
|
+
INPUT = 0x00
|
10
|
+
OUTPUT = 0x01
|
11
|
+
ANALOG = 0x02
|
12
|
+
PWM = 0x03
|
13
|
+
SERVO = 0x04
|
14
|
+
end
|
15
|
+
|
16
|
+
module PinLevels
|
17
|
+
LOW = 0
|
18
|
+
HIGH = 1
|
19
|
+
end
|
20
|
+
|
21
|
+
module MidiMessages
|
22
|
+
# Internal: Fixnum byte command for protocol version
|
23
|
+
REPORT_VERSION = 0xF9
|
24
|
+
# Internal: Fixnum byte command for system reset
|
25
|
+
SYSTEM_RESET = 0xFF
|
26
|
+
# Internal: Fixnum byte command for digital I/O message
|
27
|
+
DIGITAL_MESSAGE = 0x90
|
28
|
+
# Pubilc: Fixnum byte for range for digital pins for digital 2 byte data format
|
29
|
+
DIGITAL_MESSAGE_RANGE = 0x90..0x9F
|
30
|
+
# Internal: Fixnum byte command for an analog I/O message
|
31
|
+
ANALOG_MESSAGE = 0xE0
|
32
|
+
# Internal: Fixnum byte range for analog pins for analog 14-bit data format
|
33
|
+
ANALOG_MESSAGE_RANGE = 0xE0..0xEF
|
34
|
+
# Internal: Fixnum byte command to report analog pin
|
35
|
+
REPORT_ANALOG = 0xC0
|
36
|
+
# Internal: Fixnum byte command to report digital port
|
37
|
+
REPORT_DIGITAL = 0xD0
|
38
|
+
# Internal: Fixnum byte command to set pin mode (I/O)
|
39
|
+
PIN_MODE = 0xF4
|
40
|
+
|
41
|
+
# Internal: Fixnum byte command for start of Sysex message
|
42
|
+
START_SYSEX = 0xF0
|
43
|
+
# Internal: Fixnum byte command for end of Sysex message
|
44
|
+
END_SYSEX = 0xF7
|
45
|
+
# Internal: Fixnum byte sysex command for capabilities query
|
46
|
+
CAPABILITY_QUERY = 0x6B
|
47
|
+
# Internal: Fixnum byte sysex command for capabilities response
|
48
|
+
CAPABILITY_RESPONSE = 0x6C
|
49
|
+
# Internal: Fixnum byte sysex command for pin state query
|
50
|
+
PIN_STATE_QUERY = 0x6D
|
51
|
+
# Internal: Fixnum byte sysex command for pin state response
|
52
|
+
PIN_STATE_RESPONSE = 0x6E
|
53
|
+
# Internal: Fixnum byte sysex command for analog mapping query
|
54
|
+
ANALOG_MAPPING_QUERY = 0x69
|
55
|
+
# Internal: Fixnum byte sysex command for analog mapping response
|
56
|
+
ANALOG_MAPPING_RESPONSE = 0x6A
|
57
|
+
# Internal: Fixnum byte sysex command for i2c request
|
58
|
+
I2C_REQUEST = 0x76
|
59
|
+
# Internal: Fixnum byte sysex command for i2c reply
|
60
|
+
I2C_REPLY = 0x77
|
61
|
+
# Internal: Fixnum byte sysex command for i2c config
|
62
|
+
I2C_CONFIG = 0x78
|
63
|
+
# Internal: Fixnum byte sysex command for firmware query and response
|
64
|
+
FIRMWARE_QUERY = 0x79
|
65
|
+
# Internal: Fixnum byte i2c mode write
|
66
|
+
I2C_MODE_WRITE = 0x00
|
67
|
+
# Internal: Fixnum byte i2c mode read
|
68
|
+
I2C_MODE_READ = 0x01
|
69
|
+
# Internal: Fixnum byte i2c mode continous read
|
70
|
+
I2C_MODE_CONTINUOUS_READ = 0x02
|
71
|
+
# Internal: Fixnum byte i2c mode stop reading
|
72
|
+
I2C_MODE_STOP_READING = 0x03
|
73
|
+
end
|
74
|
+
|
75
|
+
class Board
|
76
|
+
include PinModes
|
77
|
+
include PinLevels
|
78
|
+
include MidiMessages
|
79
|
+
end
|
80
|
+
end
|
data/lib/firmata/event.rb
CHANGED
data/lib/firmata/version.rb
CHANGED
data/lib/firmata.rb
CHANGED