hybridgroup-firmata 0.2.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.
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +55 -0
- data/Rakefile +11 -0
- data/examples/blink_led.rb +22 -0
- data/firmata.gemspec +21 -0
- data/lib/firmata.rb +2 -0
- data/lib/firmata/board.rb +403 -0
- data/lib/firmata/version.rb +3 -0
- data/test/board_test.rb +223 -0
- data/test/fake_serial_port.rb +55 -0
- metadata +91 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 'Mike Breen'
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Firmata
|
2
|
+
|
3
|
+
A Ruby implementation of the [Firmata protocol](http://firmata.org/wiki/V2.2ProtocolDetails).
|
4
|
+
|
5
|
+
This library is inspired by the awesome [firmata](http://jgautier.github.com/firmata/) by [jgautier](https://github.com/jgautier).
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'firmata'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install firmata
|
20
|
+
|
21
|
+
## Prerequisites
|
22
|
+
|
23
|
+
1. Download the [Arduio IDE](http://www.arduino.cc/en/Main/Software) for your OS
|
24
|
+
2. Plug in your Arduino via USB
|
25
|
+
3. Open the Arduino IDE, select: File > Examples > Firmata > StandardFirmata
|
26
|
+
4. Click the Upload button
|
27
|
+
5. Make note of the serial port: Tools > Serial Port
|
28
|
+
|
29
|
+
There have been reports of [issues](https://github.com/jgautier/firmata/issues/8) with Firmata 2.3.
|
30
|
+
Try downgrading to [Firmata 2.2](http://at.or.at/hans/pd/Firmata-2.2.zip) if you're having a problem.
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
Here is a simple example using IRB that will turn pin 13 on and off.
|
35
|
+
(Replace xxxxx with the USB port from step 5 in Prerequisites)
|
36
|
+
|
37
|
+
1.9.3p194 :001 > require 'firmata'
|
38
|
+
1.9.3p194 :002 > board = Firmata::Board.new('/dev/tty.usbmodemxxxxx')
|
39
|
+
1.9.3p194 :003 > board.connect
|
40
|
+
1.9.3p194 :004 > board.connected?
|
41
|
+
=> true
|
42
|
+
1.9.3p194 :005 > board.version
|
43
|
+
=> "2.3"
|
44
|
+
1.9.3p194 :006 > board.firmware_name
|
45
|
+
=> "StandardFirmata"
|
46
|
+
1.9.3p194 :007 > board.digital_write(13, Firmata::Board::HIGH)
|
47
|
+
1.9.3p194 :008 > board.digital_write(13, Firmata::Board::LOW)
|
48
|
+
|
49
|
+
## Contributing
|
50
|
+
|
51
|
+
1. Fork it
|
52
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
53
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
54
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
55
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'firmata'
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
sp = TCPSocket.open 'localhost', 4567
|
6
|
+
#sp = '/dev/tty.usbserial-A700636n'
|
7
|
+
board = Firmata::Board.new(sp)
|
8
|
+
|
9
|
+
board.connect
|
10
|
+
|
11
|
+
pin_number = 3
|
12
|
+
rate = 0.5
|
13
|
+
|
14
|
+
10.times do
|
15
|
+
board.digital_write pin_number, Firmata::Board::HIGH
|
16
|
+
puts '+'
|
17
|
+
board.delay rate
|
18
|
+
|
19
|
+
board.digital_write pin_number, Firmata::Board::LOW
|
20
|
+
puts '-'
|
21
|
+
board.delay rate
|
22
|
+
end
|
data/firmata.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/firmata/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["'Mike Breen', 'Adrian Zankich'"]
|
6
|
+
gem.email = ["info@hybridgroup.com"]
|
7
|
+
gem.description = %q{A lib for working with the Firmata protocol in Ruby.}
|
8
|
+
gem.summary = %q{}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "hybridgroup-firmata"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Firmata::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency("pry")
|
19
|
+
|
20
|
+
gem.add_runtime_dependency("event_spitter")
|
21
|
+
end
|
data/lib/firmata.rb
ADDED
@@ -0,0 +1,403 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'event_spitter'
|
3
|
+
|
4
|
+
module Firmata
|
5
|
+
class Board
|
6
|
+
include EventSpitter
|
7
|
+
|
8
|
+
# Internal: Data structure representing a pin on Arduino.
|
9
|
+
Pin = Struct.new(:supported_modes, :mode, :value, :analog_channel)
|
10
|
+
|
11
|
+
# Public: Fixnum byte for pin mode input.
|
12
|
+
INPUT = 0x00
|
13
|
+
# Public: Fixnum byte for pin mode output.
|
14
|
+
OUTPUT = 0x01
|
15
|
+
# Public: Fixnum byte for pin mode analog.
|
16
|
+
ANALOG = 0x02
|
17
|
+
# Public: Fixnum byte for pin mode pulse width modulation.
|
18
|
+
PWM = 0x03
|
19
|
+
# Public: Fixnum byte for pin mode servo.
|
20
|
+
SERVO = 0x04
|
21
|
+
|
22
|
+
LOW = 0
|
23
|
+
HIGH = 1
|
24
|
+
|
25
|
+
# Internal: Fixnum byte command for protocol version
|
26
|
+
REPORT_VERSION = 0xF9
|
27
|
+
# Internal: Fixnum byte command for system reset
|
28
|
+
SYSTEM_RESET = 0xFF
|
29
|
+
# Internal: Fixnum byte command for digital I/O message
|
30
|
+
DIGITAL_MESSAGE = 0x90
|
31
|
+
# Pubilc: Fixnum byte for range for digital pins for digital 2 byte data format
|
32
|
+
DIGITAL_MESSAGE_RANGE = 0x90..0x9F
|
33
|
+
# Internal: Fixnum byte command for an analog I/O message
|
34
|
+
ANALOG_MESSAGE = 0xE0
|
35
|
+
# Internal: Fixnum byte range for analog pins for analog 14-bit data format
|
36
|
+
ANALOG_MESSAGE_RANGE = 0xE0..0xEF
|
37
|
+
# Internal: Fixnum byte command to report analog pin
|
38
|
+
REPORT_ANALOG = 0xC0
|
39
|
+
# Internal: Fixnum byte command to report digital port
|
40
|
+
REPORT_DIGITAL = 0xD0
|
41
|
+
# Internal: Fixnum byte command to set pin mode (I/O)
|
42
|
+
PIN_MODE = 0xF4
|
43
|
+
|
44
|
+
# Internal: Fixnum byte command for start of Sysex message
|
45
|
+
START_SYSEX = 0xF0
|
46
|
+
# Internal: Fixnum byte command for end of Sysex message
|
47
|
+
END_SYSEX = 0xF7
|
48
|
+
# Internal: Fixnum byte sysex command for capabilities query
|
49
|
+
CAPABILITY_QUERY = 0x6B
|
50
|
+
# Internal: Fixnum byte sysex command for capabilities response
|
51
|
+
CAPABILITY_RESPONSE = 0x6C
|
52
|
+
# Internal: Fixnum byte sysex command for pin state query
|
53
|
+
PIN_STATE_QUERY = 0x6D
|
54
|
+
# Internal: Fixnum byte sysex command for pin state response
|
55
|
+
PIN_STATE_RESPONSE = 0x6E
|
56
|
+
# Internal: Fixnum byte sysex command for analog mapping query
|
57
|
+
ANALOG_MAPPING_QUERY = 0x69
|
58
|
+
# Internal: Fixnum byte sysex command for analog mapping response
|
59
|
+
ANALOG_MAPPING_RESPONSE = 0x6A
|
60
|
+
# Internal: Fixnum byte sysex command for firmware query and response
|
61
|
+
FIRMWARE_QUERY = 0x79
|
62
|
+
|
63
|
+
# Public: Returns the SerialPort port the Arduino is attached to.
|
64
|
+
attr_reader :serial_port
|
65
|
+
# Public: Returns the Array of pins on Arduino.
|
66
|
+
attr_reader :pins
|
67
|
+
# Public: Returns the Array of analog pins on Arduino.
|
68
|
+
attr_reader :analog_pins
|
69
|
+
# Public: Returns the String firmware name of Arduion.
|
70
|
+
attr_reader :firmware_name
|
71
|
+
|
72
|
+
# Public: Initialize a Board
|
73
|
+
#
|
74
|
+
# port - a String port or an Object that responds to read and write.
|
75
|
+
def initialize(port)
|
76
|
+
if port.is_a?(String)
|
77
|
+
require 'serialport'
|
78
|
+
@serial_port = SerialPort.new(port, 57600, 8, 1, SerialPort::NONE)
|
79
|
+
@serial_port.read_timeout = 2
|
80
|
+
else
|
81
|
+
@serial_port = port
|
82
|
+
end
|
83
|
+
|
84
|
+
@major_version = 0
|
85
|
+
@minor_version = 0
|
86
|
+
@pins = []
|
87
|
+
@analog_pins = []
|
88
|
+
@connected = false
|
89
|
+
rescue LoadError
|
90
|
+
puts "Please 'gem install hybridgroup-serialport' for serial port support."
|
91
|
+
end
|
92
|
+
|
93
|
+
# Pubilc: Check if a connection to Arduino has been made.
|
94
|
+
#
|
95
|
+
# Returns Boolean connected state.
|
96
|
+
def connected?
|
97
|
+
@connected
|
98
|
+
end
|
99
|
+
|
100
|
+
# Public: Make connection to Arduino.
|
101
|
+
#
|
102
|
+
# Returns Firmata::Board board.
|
103
|
+
def connect
|
104
|
+
unless @connected
|
105
|
+
once('report_version', ->() do
|
106
|
+
once('firmware_query', ->() do
|
107
|
+
once('capability_query', ->() do
|
108
|
+
once('analog_mapping_query', ->() do
|
109
|
+
|
110
|
+
2.times { |i| toggle_pin_reporting(i) }
|
111
|
+
|
112
|
+
@connected = true
|
113
|
+
emit('ready')
|
114
|
+
end)
|
115
|
+
query_analog_mapping
|
116
|
+
end)
|
117
|
+
query_capabilities
|
118
|
+
end)
|
119
|
+
end)
|
120
|
+
|
121
|
+
until connected?
|
122
|
+
read_and_process
|
123
|
+
delay(0.5)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
self
|
128
|
+
end
|
129
|
+
|
130
|
+
# Internal: Write data to the underlying serial port.
|
131
|
+
#
|
132
|
+
# commands - Zero or more byte commands to be written.
|
133
|
+
#
|
134
|
+
# Examples
|
135
|
+
#
|
136
|
+
# write(START_SYSEX, CAPABILITY_QUERY, END_SYSEX)
|
137
|
+
#
|
138
|
+
# Returns nothing.
|
139
|
+
def write(*commands)
|
140
|
+
serial_port.write_nonblock(commands.map(&:chr).join)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Internal: Read data from the underlying serial port.
|
144
|
+
#
|
145
|
+
# Returns String data read for serial port.
|
146
|
+
def read
|
147
|
+
serial_port.read_nonblock(4096)
|
148
|
+
rescue EOFError
|
149
|
+
rescue Errno::EAGAIN
|
150
|
+
end
|
151
|
+
|
152
|
+
# Internal: Process a series of bytes.
|
153
|
+
#
|
154
|
+
# data: The String data to process.
|
155
|
+
#
|
156
|
+
# Returns nothing.
|
157
|
+
def process(data)
|
158
|
+
bytes = StringIO.new(String(data)).bytes
|
159
|
+
bytes.each do |byte|
|
160
|
+
case byte
|
161
|
+
when REPORT_VERSION
|
162
|
+
@major_version = bytes.next
|
163
|
+
@minor_version = bytes.next
|
164
|
+
|
165
|
+
emit('report_version')
|
166
|
+
|
167
|
+
when ANALOG_MESSAGE_RANGE
|
168
|
+
least_significant_byte = bytes.next
|
169
|
+
most_significant_byte = bytes.next
|
170
|
+
|
171
|
+
value = least_significant_byte | (most_significant_byte << 7)
|
172
|
+
pin = byte & 0x0F
|
173
|
+
|
174
|
+
if analog_pin = analog_pins[pin]
|
175
|
+
pins[analog_pin].value = value
|
176
|
+
|
177
|
+
emit('analog-read', pin, value)
|
178
|
+
emit("analog-read-#{pin}", value)
|
179
|
+
end
|
180
|
+
|
181
|
+
when DIGITAL_MESSAGE_RANGE
|
182
|
+
port = byte & 0x0F
|
183
|
+
first_bitmask = bytes.next
|
184
|
+
second_bitmask = bytes.next
|
185
|
+
port_value = first_bitmask | (second_bitmask << 7)
|
186
|
+
|
187
|
+
8.times do |i|
|
188
|
+
pin_number = 8 * port + i
|
189
|
+
if pin = pins[pin_number] and pin.mode == INPUT
|
190
|
+
value = (port_value >> (i & 0x07)) & 0x01
|
191
|
+
pin.value = value
|
192
|
+
emit('digital-read', pin_number, value)
|
193
|
+
emit("digital-read-#{pin_number}", value)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
when START_SYSEX
|
198
|
+
current_buffer = [byte]
|
199
|
+
begin
|
200
|
+
current_buffer.push(bytes.next)
|
201
|
+
end until current_buffer.last == END_SYSEX
|
202
|
+
|
203
|
+
command = current_buffer[1]
|
204
|
+
|
205
|
+
case command
|
206
|
+
when CAPABILITY_RESPONSE
|
207
|
+
supported_modes = 0
|
208
|
+
n = 0
|
209
|
+
|
210
|
+
current_buffer.slice(2, current_buffer.length - 3).each do |byte|
|
211
|
+
if byte == 127
|
212
|
+
modes = []
|
213
|
+
# the pin modes
|
214
|
+
[ INPUT, OUTPUT, ANALOG, PWM, SERVO ].each do |mode|
|
215
|
+
modes.push(mode) unless (supported_modes & (1 << mode)).zero?
|
216
|
+
end
|
217
|
+
|
218
|
+
@pins.push(Pin.new(modes, OUTPUT, 0))
|
219
|
+
|
220
|
+
supported_modes = 0
|
221
|
+
n = 0
|
222
|
+
next
|
223
|
+
end
|
224
|
+
|
225
|
+
supported_modes |= (1 << byte) if n.zero?
|
226
|
+
|
227
|
+
n ^= 1
|
228
|
+
end
|
229
|
+
|
230
|
+
emit('capability_query')
|
231
|
+
|
232
|
+
when ANALOG_MAPPING_RESPONSE
|
233
|
+
pin_index = 0
|
234
|
+
|
235
|
+
current_buffer.slice(2, current_buffer.length - 3).each do |byte|
|
236
|
+
|
237
|
+
@pins[pin_index].analog_channel = byte
|
238
|
+
|
239
|
+
@analog_pins.push(pin_index) unless byte == 127
|
240
|
+
|
241
|
+
pin_index += 1
|
242
|
+
end
|
243
|
+
|
244
|
+
emit('analog_mapping_query')
|
245
|
+
|
246
|
+
when PIN_STATE_RESPONSE
|
247
|
+
pin = pins[current_buffer[2]]
|
248
|
+
pin.mode = current_buffer[3]
|
249
|
+
pin.value = current_buffer[4]
|
250
|
+
|
251
|
+
pin.value |= (current_buffer[5] << 7) if current_buffer.size > 6
|
252
|
+
|
253
|
+
pin.value |= (current_buffer[6] << 14) if current_buffer.size > 7
|
254
|
+
|
255
|
+
when FIRMWARE_QUERY
|
256
|
+
@firmware_name = current_buffer.slice(4, current_buffer.length - 5).reject { |b| b.zero? }.map(&:chr).join
|
257
|
+
emit('firmware_query')
|
258
|
+
|
259
|
+
else
|
260
|
+
puts 'bad byte'
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
rescue StopIteration
|
265
|
+
# do nadda
|
266
|
+
end
|
267
|
+
|
268
|
+
# Public: Read the serial port and process the results
|
269
|
+
#
|
270
|
+
# Returns nothing.
|
271
|
+
def read_and_process
|
272
|
+
process(read)
|
273
|
+
end
|
274
|
+
|
275
|
+
# Public: Send a SYSTEM_RESET to the Arduino
|
276
|
+
#
|
277
|
+
# Returns nothing.
|
278
|
+
def reset
|
279
|
+
write(SYSTEM_RESET)
|
280
|
+
end
|
281
|
+
|
282
|
+
# Public: Set the mode for a pin.
|
283
|
+
#
|
284
|
+
# pin - The Integer pin to set.
|
285
|
+
# mode - The Fixnum mode (INPUT, OUTPUT, ANALOG, PWM or SERVO)
|
286
|
+
#
|
287
|
+
# Examples
|
288
|
+
#
|
289
|
+
# set_pin_mode(13, OUTPUT)
|
290
|
+
#
|
291
|
+
# Returns nothing.
|
292
|
+
def set_pin_mode(pin, mode)
|
293
|
+
pins[pin].mode = mode
|
294
|
+
write(PIN_MODE, pin, mode)
|
295
|
+
end
|
296
|
+
|
297
|
+
# Public: Write a value to a digital pin.
|
298
|
+
#
|
299
|
+
# pin - The Integer pin to write to.
|
300
|
+
# value - The value to write (HIGH or LOW).
|
301
|
+
#
|
302
|
+
# Returns nothing.
|
303
|
+
def digital_write(pin, value)
|
304
|
+
port = (pin / 8).floor
|
305
|
+
port_value = 0
|
306
|
+
|
307
|
+
@pins[pin].value = value
|
308
|
+
|
309
|
+
8.times do |i|
|
310
|
+
port_value |= (1 << i) unless @pins[8 * port + i].value.zero?
|
311
|
+
end
|
312
|
+
|
313
|
+
write(DIGITAL_MESSAGE | port, port_value & 0x7F, (port_value >> 7) & 0x7F)
|
314
|
+
end
|
315
|
+
|
316
|
+
# Public: Write an analog messege.
|
317
|
+
#
|
318
|
+
# pin - The Integer pin to write to.
|
319
|
+
# value - The Integer value to write to the pin between 0-255.
|
320
|
+
#
|
321
|
+
# Returns nothing.
|
322
|
+
def analog_write(pin, value)
|
323
|
+
@pins[pin].value = value
|
324
|
+
write(ANALOG_MESSAGE | pin, value & 0x7F, (value >> 7) & 0x7F)
|
325
|
+
end
|
326
|
+
|
327
|
+
# Public: Write to a servo.
|
328
|
+
#
|
329
|
+
# pin - The Integer pin to write to.
|
330
|
+
# degrees - The Integer degrees to move the servo.
|
331
|
+
#
|
332
|
+
# Returns nothing.
|
333
|
+
alias_method :servo_write, :analog_write
|
334
|
+
|
335
|
+
# Public: Ask the Arduino to sleep for a number of seconds.
|
336
|
+
#
|
337
|
+
# seconds - The Integer seconds to sleep for.
|
338
|
+
#
|
339
|
+
# Returns nothing.
|
340
|
+
def delay(seconds)
|
341
|
+
sleep(seconds)
|
342
|
+
end
|
343
|
+
|
344
|
+
# Public: The major and minor firmware version on the board. Will report as
|
345
|
+
# "0.0" if report_version command has not been run.
|
346
|
+
#
|
347
|
+
# Returns String the firmware version as "minor.major".
|
348
|
+
def version
|
349
|
+
[@major_version, @minor_version].join('.')
|
350
|
+
end
|
351
|
+
|
352
|
+
# Public: Ask the Arduino to report its version.
|
353
|
+
#
|
354
|
+
# Returns nothing.
|
355
|
+
def report_version
|
356
|
+
write(REPORT_VERSION)
|
357
|
+
end
|
358
|
+
|
359
|
+
# Public: Ask the Ardution for its firmware name.
|
360
|
+
#
|
361
|
+
# Returns nothing.
|
362
|
+
def query_firmware
|
363
|
+
write(FIRMWARE_QUERY)
|
364
|
+
end
|
365
|
+
|
366
|
+
# Public: Ask the Arduino for the current configuration of any pin.
|
367
|
+
#
|
368
|
+
# pin - The Integer pin to query on the board.
|
369
|
+
#
|
370
|
+
# Returns nothing.
|
371
|
+
def query_pin_state(pin)
|
372
|
+
write(START_SYSEX, PIN_STATE_QUERY, pin.to_i, END_SYSEX)
|
373
|
+
end
|
374
|
+
|
375
|
+
# Public: Ask the Arduino about its capabilities and current state.
|
376
|
+
#
|
377
|
+
# Returns nothing.
|
378
|
+
def query_capabilities
|
379
|
+
write(START_SYSEX, CAPABILITY_QUERY, END_SYSEX)
|
380
|
+
end
|
381
|
+
|
382
|
+
# Public: Ask the Arduino which pins (used with pin mode message) correspond to the analog channels.
|
383
|
+
#
|
384
|
+
# Returns nothing.
|
385
|
+
def query_analog_mapping
|
386
|
+
write(START_SYSEX, ANALOG_MAPPING_QUERY, END_SYSEX)
|
387
|
+
end
|
388
|
+
|
389
|
+
# Public: Toggle pin reporting on or off.
|
390
|
+
#
|
391
|
+
# pin - The Integer pin to toggle.
|
392
|
+
# mode - The Integer mode the pin will report. The valid values are
|
393
|
+
# REPORT_DIGITAL or REPORT_ANALOG (default: REPORT_DIGITAL).
|
394
|
+
# state - The Integer state to toggle the pin. The valid value are
|
395
|
+
# HIGH or LOW (default: HIGH)
|
396
|
+
#
|
397
|
+
# Returns nothing.
|
398
|
+
def toggle_pin_reporting(pin, state = HIGH, mode = REPORT_DIGITAL)
|
399
|
+
write(mode | pin, state)
|
400
|
+
end
|
401
|
+
|
402
|
+
end
|
403
|
+
end
|
data/test/board_test.rb
ADDED
@@ -0,0 +1,223 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'minitest/pride'
|
3
|
+
|
4
|
+
require_relative '../lib/firmata'
|
5
|
+
require_relative 'fake_serial_port'
|
6
|
+
|
7
|
+
class BoardTest < MiniTest::Unit::TestCase
|
8
|
+
|
9
|
+
def mock_serial_port(*args, &block)
|
10
|
+
mock_port = MiniTest::Mock.new
|
11
|
+
mock_port.expect(:is_a?, false, [nil])
|
12
|
+
|
13
|
+
if block_given?
|
14
|
+
yield mock_port
|
15
|
+
else
|
16
|
+
expected = args.map(&:chr).join
|
17
|
+
mock_port.expect(:write_nonblock, 1, [expected])
|
18
|
+
end
|
19
|
+
|
20
|
+
mock_port
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_writing_report_version
|
24
|
+
mock_sp = mock_serial_port(Firmata::Board::REPORT_VERSION)
|
25
|
+
|
26
|
+
board = Firmata::Board.new(mock_sp)
|
27
|
+
board.report_version
|
28
|
+
|
29
|
+
mock_sp.verify
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_processing_report_version
|
33
|
+
board = Firmata::Board.new(FakeSerialPort.new)
|
34
|
+
board.report_version
|
35
|
+
board.read_and_process
|
36
|
+
|
37
|
+
assert_equal '2.3', board.version
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_writing_capability_query
|
41
|
+
mock_sp = mock_serial_port(Firmata::Board::START_SYSEX, Firmata::Board::CAPABILITY_QUERY, Firmata::Board::END_SYSEX)
|
42
|
+
|
43
|
+
board = Firmata::Board.new(mock_sp)
|
44
|
+
board.query_capabilities
|
45
|
+
|
46
|
+
mock_sp.verify
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_processing_capabilities_query
|
50
|
+
board = Firmata::Board.new(FakeSerialPort.new)
|
51
|
+
board.query_capabilities
|
52
|
+
board.read_and_process
|
53
|
+
|
54
|
+
assert_equal 20, board.pins.size
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_writing_analog_mapping_query
|
58
|
+
mock_sp = mock_serial_port(Firmata::Board::START_SYSEX, Firmata::Board::ANALOG_MAPPING_QUERY, Firmata::Board::END_SYSEX)
|
59
|
+
|
60
|
+
board = Firmata::Board.new(mock_sp)
|
61
|
+
board.query_analog_mapping
|
62
|
+
|
63
|
+
mock_sp.verify
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_processing_analog_mapping_query
|
67
|
+
board = Firmata::Board.new(FakeSerialPort.new)
|
68
|
+
board.query_capabilities
|
69
|
+
board.read_and_process
|
70
|
+
|
71
|
+
board.query_analog_mapping
|
72
|
+
board.read_and_process
|
73
|
+
|
74
|
+
assert_equal 6, board.analog_pins.size
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_processing_digital_message
|
78
|
+
board = Firmata::Board.new(FakeSerialPort.new)
|
79
|
+
|
80
|
+
board.query_capabilities
|
81
|
+
board.read_and_process
|
82
|
+
|
83
|
+
board.query_analog_mapping
|
84
|
+
board.read_and_process
|
85
|
+
|
86
|
+
pin = board.pins[8]
|
87
|
+
pin.mode = Firmata::Board::INPUT
|
88
|
+
|
89
|
+
board.process("\x91\x01\x00")
|
90
|
+
|
91
|
+
assert_equal Firmata::Board::HIGH, pin.value
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_set_pin_mode
|
95
|
+
mock_sp = mock_serial_port(Firmata::Board::PIN_MODE, 13, Firmata::Board::OUTPUT)
|
96
|
+
|
97
|
+
board = Firmata::Board.new(mock_sp)
|
98
|
+
board.pins[13] = Firmata::Board::Pin.new([0, 1, 4], 0, 0, nil)
|
99
|
+
|
100
|
+
board.set_pin_mode(13, Firmata::Board::OUTPUT)
|
101
|
+
|
102
|
+
assert_equal Firmata::Board::OUTPUT, board.pins[13].mode
|
103
|
+
mock_sp.verify
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_write_pin_state_query
|
107
|
+
mock_sp = mock_serial_port(Firmata::Board::START_SYSEX, Firmata::Board::PIN_STATE_QUERY, 13, Firmata::Board::END_SYSEX)
|
108
|
+
|
109
|
+
board = Firmata::Board.new(mock_sp)
|
110
|
+
board.query_pin_state(13)
|
111
|
+
|
112
|
+
mock_sp.verify
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_processing_pin_state_query
|
116
|
+
board = Firmata::Board.new(FakeSerialPort.new)
|
117
|
+
board.query_capabilities
|
118
|
+
board.read_and_process
|
119
|
+
|
120
|
+
board.pins[13].mode = Firmata::Board::INPUT
|
121
|
+
|
122
|
+
board.query_pin_state(13)
|
123
|
+
board.read_and_process
|
124
|
+
|
125
|
+
assert_equal Firmata::Board::OUTPUT, board.pins[13].mode
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
def test_toggling_pin_reporting
|
130
|
+
mock_sp = mock_serial_port do |mock|
|
131
|
+
mock.expect(:write_nonblock, 2, [[Firmata::Board::REPORT_DIGITAL | 13, 1].map(&:chr).join])
|
132
|
+
end
|
133
|
+
|
134
|
+
board = Firmata::Board.new(mock_sp)
|
135
|
+
|
136
|
+
board.toggle_pin_reporting(13)
|
137
|
+
mock_sp.verify
|
138
|
+
|
139
|
+
mock_sp.expect(:write_nonblock, 2, [[Firmata::Board::REPORT_DIGITAL | 13, 0].map(&:chr).join])
|
140
|
+
board.toggle_pin_reporting(13, 0)
|
141
|
+
mock_sp.verify
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_processing_analog_message
|
146
|
+
fake_port = FakeSerialPort.new
|
147
|
+
board = Firmata::Board.new(fake_port)
|
148
|
+
|
149
|
+
board.query_capabilities
|
150
|
+
board.read_and_process
|
151
|
+
|
152
|
+
board.query_analog_mapping
|
153
|
+
board.read_and_process
|
154
|
+
|
155
|
+
fake_port.buffer = "\xE0\e\u0005\xE1N\u0004\xE2A\u0004\xE3C\u0004\xE4o\u0004\xE5f\u0004\xE0w\u0004\xE1]\u0004\xE2N\u0004\xE3I\u0004\xE4x\u0004\xE5m\u0004\xE0m\u0004\xE1`\u0004\xE2T\u0004\xE3L\u0004\xE4s\u0004\xE5l\u0004\xE0i\u0004\xE1`\u0004\xE2V\u0004\xE3N\u0004\xE4m\u0004\xE5j\u0004\xE0f\u0004\xE1^\u0004\xE2U\u0004\xE3O\u0004\xE4h\u0004\xE5g\u0004\xE0d\u0004\xE1\\\u0004\xE2T\u0004\xE3O\u0004\xE4d\u0004\xE5d\u0004\xE0b\u0004\xE1Z\u0004\xE2S\u0004\xE3N\u0004\xE4`\u0004\xE5a\u0004\xE0_\u0004\xE1X\u0004\xE2Q\u0004\xE3L\u0004\xE4\\\u0004\xE5^\u0004\xE0\\\u0004\xE1T\u0004\xE2N\u0004\xE3J\u0004\xE4X\u0004\xE5Z\u0004\xE0X\u0004\xE1Q\u0004\xE2K\u0004\xE3G\u0004\xE4T\u0004\xE5W\u0004\xE0V\u0004\xE1O\u0004\xE2H\u0004\xE3D\u0004\xE4Q\u0004\xE5T\u0004\xE0S\u0004\xE1L\u0004\xE2F\u0004\xE3B\u0004\xE4N\u0004\xE5Q\u0004\xE0P\u0004\xE1J\u0004\xE2C\u0004\xE3@\u0004\xE4K\u0004\xE5N\u0004\xE0N\u0004\xE1G\u0004\xE2A\u0004\xE3>\u0004\xE4I\u0004\xE5L\u0004\xE0L\u0004\xE1D\u0004\xE2?\u0004\xE3<\u0004\xE4F\u0004\xE5I\u0004\xE0I\u0004\xE1B\u0004\xE2=\u0004\xE39\u0004\xE4C\u0004\xE5F\u0004\xE0F\u0004\xE1?\u0004\xE2:\u0004\xE37\u0004\xE4@\u0004\xE5C\u0004\xE0C\u0004\xE1<\u0004\xE28\u0004\xE34\u0004\xE4>\u0004\xE5A\u0004\xE0A\u0004\xE1:\u0004\xE26\u0004\xE32\u0004\xE4<\u0004\xE5?\u0004\xE0?\u0004\xE19\u0004\xE24\u0004\xE31\u0004\xE4:\u0004\xE5=\u0004\xE0>\u0004\xE17\u0004\xE22\u0004\xE3/\u0004\xE49\u0004\xE5;\u0004\xE0<\u0004\xE15\u0004\xE20\u0004\xE3-\u0004\xE46\u0004\xE59\u0004\xE09\u0004\xE12\u0004\xE2.\u0004\xE3+\u0004\xE44\u0004\xE57\u0004\xE07\u0004\xE10\u0004\xE2,\u0004\xE3)\u0004\xE42\u0004\xE55\u0004\xE05\u0004\xE1.\u0004\xE2*\u0004\xE3'\u0004\xE40\u0004\xE52\u0004\xE03\u0004\xE1-\u0004\xE2(\u0004\xE3&\u0004\xE4/\u0004\xE51\u0004\xE02\u0004\xE1+\u0004\xE2&\u0004\xE3$\u0004\xE4-\u0004\xE50\u0004\xE00\u0004\xE1*\u0004\xE2%\u0004\xE3#\u0004\xE4,\u0004\xE5.\u0004\xE0/\u0004\xE1(\u0004\xE2$\u0004\xE3!\u0004\xE4*\u0004\xE5,\u0004\xE0-\u0004\xE1&\u0004\xE2\"\u0004\xE3\u001F\u0004\xE4(\u0004\xE5*\u0004\xE0+\u0004\xE1$\u0004\xE2 \u0004\xE3\u001D\u0004\xE4&\u0004\xE5(\u0004\xE0)\u0004\xE1\"\u0004\xE2\u001F\u0004\xE3\u001C\u0004\xE4%\u0004\xE5'\u0004\xE0(\u0004\xE1!\u0004\xE2\u001D\u0004\xE3\e\u0004\xE4$\u0004\xE5&\u0004\xE0&\u0004\xE1 \u0004\xE2\u001C\u0004\xE3\u001A\u0004\xE4#\u0004\xE5%\u0004\xE0&\u0004\xE1\u001F\u0004\xE2\e\u0004\xE3\u0019\u0004\xE4\"\u0004\xE5$\u0004\xE0$\u0004\xE1\u001E\u0004\xE2\u0019\u0004\xE3\u0018\u0004\xE4 \u0004\xE5\"\u0004\xE0\"\u0004\xE1\u001C\u0004\xE2\u0018\u0004\xE3\u0016\u0004\xE4\u001F\u0004\xE5 \u0004\xE0!\u0004\xE1\u001A\u0004\xE2\u0017\u0004\xE3\u0014\u0004\xE4\u001D\u0004\xE5\u001E\u0004\xE0\u001F\u0004\xE1\u0019\u0004\xE2\u0015\u0004\xE3\u0013\u0004\xE4\u001C\u0004\xE5\u001D\u0004\xE0\u001E\u0004\xE1\u0018\u0004\xE2\u0013\u0004\xE3\u0012\u0004\xE4\e\u0004\xE5\u001C\u0004\xE0\u001D\u0004\xE1\u0017\u0004\xE2\u0014\u0004\xE3\u0012\u0004\xE4\e\u0004\xE5\u001C\u0004\xE0\u001D\u0004\xE1\u0016\u0004\xE2\u0013\u0004\xE3\u0011\u0004\xE4\u001A\u0004\xE5\e\u0004\xE0\u001C\u0004\xE1\u0015\u0004\xE2\u0011\u0004\xE3\u0010\u0004\xE4\u0018\u0004\xE5\u0019\u0004\xE0\u001A\u0004\xE1\u0014\u0004\xE2\u0010\u0004\xE3\u000E\u0004\xE4\u0017\u0004\xE5\u0018\u0004\xE0\u0018\u0004\xE1\u0012\u0004\xE2\u000E\u0004\xE3\r\u0004\xE4\u0015\u0004\xE5\u0016\u0004\xE0\u0017\u0004\xE1\u0011\u0004\xE2\u000E\u0004\xE3\f\u0004\xE4\u0015\u0004\xE5\u0016\u0004\xE0\u0016\u0004\xE1\u0010\u0004\xE2\f\u0004\xE3\v\u0004\xE4\u0014\u0004\xE5\u0015\u0004\xE0\u0016\u0004\xE1\u000F\u0004\xE2\v\u0004\xE3\n\u0004\xE4\u0013\u0004\xE5\u0014\u0004\xE0\u0015\u0004\xE1\u000F\u0004\xE2\v\u0004\xE3\t\u0004\xE4\u0012\u0004\xE5\u0013\u0004\xE0\u0014\u0004\xE1\u000E\u0004\xE2\n\u0004\xE3\t\u0004\xE4\u0012\u0004\xE5\u0012\u0004\xE0\u0013\u0004\xE1\f\u0004\xE2\t\u0004\xE3\a\u0004\xE4\u0010\u0004\xE5\u0011\u0004\xE0\u0011\u0004\xE1\v\u0004\xE2\b\u0004\xE3\u0006\u0004\xE4\u000F\u0004\xE5\u000F\u0004\xE0\u0010\u0004\xE1\n\u0004\xE2\u0006\u0004\xE3\u0005\u0004\xE4\u000E\u0004\xE5\u000F\u0004\xE0\u000F\u0004\xE1\t\u0004\xE2\u0006\u0004\xE3\u0004\u0004\xE4\r\u0004\xE5\u000E\u0004\xE0\u000F\u0004\xE1\t\u0004\xE2\u0006\u0004\xE3\u0004\u0004\xE4\r\u0004\xE5\u000E\u0004\xE0\u000E\u0004\xE1\b\u0004\xE2\u0004\u0004\xE3\u0003\u0004\xE4\f\u0004\xE5\r\u0004\xE0\u000E\u0004\xE1\a\u0004\xE2\u0004\u0004\xE3\u0003\u0004"
|
156
|
+
board.read_and_process
|
157
|
+
|
158
|
+
board.analog_pins.each do |pin|
|
159
|
+
refute_nil board.pins[pin].analog_channel, "Analog channel not set for pin #{pin}"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_reset
|
164
|
+
mock_sp = mock_serial_port(Firmata::Board::SYSTEM_RESET)
|
165
|
+
|
166
|
+
board = Firmata::Board.new(mock_sp)
|
167
|
+
board.reset
|
168
|
+
|
169
|
+
mock_sp.verify
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_write_firmware_query
|
173
|
+
mock_sp = mock_serial_port(Firmata::Board::FIRMWARE_QUERY)
|
174
|
+
|
175
|
+
board = Firmata::Board.new(mock_sp)
|
176
|
+
board.query_firmware
|
177
|
+
|
178
|
+
mock_sp.verify
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_process_firmware_query
|
182
|
+
fake_port = FakeSerialPort.new
|
183
|
+
fake_port.buffer = "\xF0y\u0002\u0003S\u0000t\u0000a\u0000n\u0000d\u0000a\u0000r\u0000d\u0000F\u0000i\u0000r\u0000m\u0000a\u0000t\u0000a\u0000\xF7"
|
184
|
+
board = Firmata::Board.new(fake_port)
|
185
|
+
|
186
|
+
board.read_and_process
|
187
|
+
|
188
|
+
assert_equal 'StandardFirmata', board.firmware_name, 'Firmware Name is incorrect'
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_digital_write
|
192
|
+
mock_sp = mock_serial_port(145, 127, 1)
|
193
|
+
board = Firmata::Board.new(mock_sp)
|
194
|
+
|
195
|
+
8.times do |x|
|
196
|
+
board.pins[x + 8] = Firmata::Board::Pin.new([], 0, 250 + x, nil)
|
197
|
+
end
|
198
|
+
|
199
|
+
board.digital_write(13, 1)
|
200
|
+
|
201
|
+
assert_equal 1, board.pins[13].value, "Pin value not set"
|
202
|
+
mock_sp.verify
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_analog_write
|
206
|
+
mock_sp = mock_serial_port(233, 127, 1)
|
207
|
+
board = Firmata::Board.new(mock_sp)
|
208
|
+
|
209
|
+
8.times do |x|
|
210
|
+
board.pins[x + 8] = Firmata::Board::Pin.new([], 0, 250 + x, nil)
|
211
|
+
end
|
212
|
+
|
213
|
+
board.analog_write(9, 255)
|
214
|
+
|
215
|
+
assert_equal 255, board.pins[9].value
|
216
|
+
mock_sp.verify
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_servo_write
|
220
|
+
board = Firmata::Board.new(FakeSerialPort.new)
|
221
|
+
assert board.respond_to? :servo_write
|
222
|
+
end
|
223
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
class FakeSerialPort
|
4
|
+
Board = Firmata::Board
|
5
|
+
|
6
|
+
attr_accessor :buffer
|
7
|
+
attr_accessor :read_timeout
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@buffer = ""
|
11
|
+
@read_timeout = 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def write(command)
|
15
|
+
val = case command.getbyte(0)
|
16
|
+
when Board::SYSTEM_RESET
|
17
|
+
""
|
18
|
+
when Board::REPORT_VERSION
|
19
|
+
"\xF9\u0002\u0003"
|
20
|
+
|
21
|
+
when Board::REPORT_DIGITAL, Board::REPORT_ANALOG
|
22
|
+
"\xE0\e\u0005\xE1N\u0004\xE2A\u0004\xE3C\u0004\xE4o\u0004\xE5f\u0004\xE0w\u0004\xE1]\u0004\xE2N\u0004\xE3I\u0004\xE4x\u0004\xE5m\u0004\xE0m\u0004\xE1`\u0004\xE2T\u0004\xE3L\u0004\xE4s\u0004\xE5l\u0004\xE0i\u0004\xE1`\u0004\xE2V\u0004\xE3N\u0004\xE4m\u0004\xE5j\u0004\xE0f\u0004\xE1^\u0004\xE2U\u0004\xE3O\u0004\xE4h\u0004\xE5g\u0004\xE0d\u0004\xE1\\\u0004\xE2T\u0004\xE3O\u0004\xE4d\u0004\xE5d\u0004\xE0b\u0004\xE1Z\u0004\xE2S\u0004\xE3N\u0004\xE4`\u0004\xE5a\u0004\xE0_\u0004\xE1X\u0004\xE2Q\u0004\xE3L\u0004\xE4\\\u0004\xE5^\u0004\xE0\\\u0004\xE1T\u0004\xE2N\u0004\xE3J\u0004\xE4X\u0004\xE5Z\u0004\xE0X\u0004\xE1Q\u0004\xE2K\u0004\xE3G\u0004\xE4T\u0004\xE5W\u0004\xE0V\u0004\xE1O\u0004\xE2H\u0004\xE3D\u0004\xE4Q\u0004\xE5T\u0004\xE0S\u0004\xE1L\u0004\xE2F\u0004\xE3B\u0004\xE4N\u0004\xE5Q\u0004\xE0P\u0004\xE1J\u0004\xE2C\u0004\xE3@\u0004\xE4K\u0004\xE5N\u0004\xE0N\u0004\xE1G\u0004\xE2A\u0004\xE3>\u0004\xE4I\u0004\xE5L\u0004\xE0L\u0004\xE1D\u0004\xE2?\u0004\xE3<\u0004\xE4F\u0004\xE5I\u0004\xE0I\u0004\xE1B\u0004\xE2=\u0004\xE39\u0004\xE4C\u0004\xE5F\u0004\xE0F\u0004\xE1?\u0004\xE2:\u0004\xE37\u0004\xE4@\u0004\xE5C\u0004\xE0C\u0004\xE1<\u0004\xE28\u0004\xE34\u0004\xE4>\u0004\xE5A\u0004\xE0A\u0004\xE1:\u0004\xE26\u0004\xE32\u0004\xE4<\u0004\xE5?\u0004\xE0?\u0004\xE19\u0004\xE24\u0004\xE31\u0004\xE4:\u0004\xE5=\u0004\xE0>\u0004\xE17\u0004\xE22\u0004\xE3/\u0004\xE49\u0004\xE5;\u0004\xE0<\u0004\xE15\u0004\xE20\u0004\xE3-\u0004\xE46\u0004\xE59\u0004\xE09\u0004\xE12\u0004\xE2.\u0004\xE3+\u0004\xE44\u0004\xE57\u0004\xE07\u0004\xE10\u0004\xE2,\u0004\xE3)\u0004\xE42\u0004\xE55\u0004\xE05\u0004\xE1.\u0004\xE2*\u0004\xE3'\u0004\xE40\u0004\xE52\u0004\xE03\u0004\xE1-\u0004\xE2(\u0004\xE3&\u0004\xE4/\u0004\xE51\u0004\xE02\u0004\xE1+\u0004\xE2&\u0004\xE3$\u0004\xE4-\u0004\xE50\u0004\xE00\u0004\xE1*\u0004\xE2%\u0004\xE3#\u0004\xE4,\u0004\xE5.\u0004\xE0/\u0004\xE1(\u0004\xE2$\u0004\xE3!\u0004\xE4*\u0004\xE5,\u0004\xE0-\u0004\xE1&\u0004\xE2\"\u0004\xE3\u001F\u0004\xE4(\u0004\xE5*\u0004\xE0+\u0004\xE1$\u0004\xE2 \u0004\xE3\u001D\u0004\xE4&\u0004\xE5(\u0004\xE0)\u0004\xE1\"\u0004\xE2\u001F\u0004\xE3\u001C\u0004\xE4%\u0004\xE5'\u0004\xE0(\u0004\xE1!\u0004\xE2\u001D\u0004\xE3\e\u0004\xE4$\u0004\xE5&\u0004\xE0&\u0004\xE1 \u0004\xE2\u001C\u0004\xE3\u001A\u0004\xE4#\u0004\xE5%\u0004\xE0&\u0004\xE1\u001F\u0004\xE2\e\u0004\xE3\u0019\u0004\xE4\"\u0004\xE5$\u0004\xE0$\u0004\xE1\u001E\u0004\xE2\u0019\u0004\xE3\u0018\u0004\xE4 \u0004\xE5\"\u0004\xE0\"\u0004\xE1\u001C\u0004\xE2\u0018\u0004\xE3\u0016\u0004\xE4\u001F\u0004\xE5 \u0004\xE0!\u0004\xE1\u001A\u0004\xE2\u0017\u0004\xE3\u0014\u0004\xE4\u001D\u0004\xE5\u001E\u0004\xE0\u001F\u0004\xE1\u0019\u0004\xE2\u0015\u0004\xE3\u0013\u0004\xE4\u001C\u0004\xE5\u001D\u0004\xE0\u001E\u0004\xE1\u0018\u0004\xE2\u0013\u0004\xE3\u0012\u0004\xE4\e\u0004\xE5\u001C\u0004\xE0\u001D\u0004\xE1\u0017\u0004\xE2\u0014\u0004\xE3\u0012\u0004\xE4\e\u0004\xE5\u001C\u0004\xE0\u001D\u0004\xE1\u0016\u0004\xE2\u0013\u0004\xE3\u0011\u0004\xE4\u001A\u0004\xE5\e\u0004\xE0\u001C\u0004\xE1\u0015\u0004\xE2\u0011\u0004\xE3\u0010\u0004\xE4\u0018\u0004\xE5\u0019\u0004\xE0\u001A\u0004\xE1\u0014\u0004\xE2\u0010\u0004\xE3\u000E\u0004\xE4\u0017\u0004\xE5\u0018\u0004\xE0\u0018\u0004\xE1\u0012\u0004\xE2\u000E\u0004\xE3\r\u0004\xE4\u0015\u0004\xE5\u0016\u0004\xE0\u0017\u0004\xE1\u0011\u0004\xE2\u000E\u0004\xE3\f\u0004\xE4\u0015\u0004\xE5\u0016\u0004\xE0\u0016\u0004\xE1\u0010\u0004\xE2\f\u0004\xE3\v\u0004\xE4\u0014\u0004\xE5\u0015\u0004\xE0\u0016\u0004\xE1\u000F\u0004\xE2\v\u0004\xE3\n\u0004\xE4\u0013\u0004\xE5\u0014\u0004\xE0\u0015\u0004\xE1\u000F\u0004\xE2\v\u0004\xE3\t\u0004\xE4\u0012\u0004\xE5\u0013\u0004\xE0\u0014\u0004\xE1\u000E\u0004\xE2\n\u0004\xE3\t\u0004\xE4\u0012\u0004\xE5\u0012\u0004\xE0\u0013\u0004\xE1\f\u0004\xE2\t\u0004\xE3\a\u0004\xE4\u0010\u0004\xE5\u0011\u0004\xE0\u0011\u0004\xE1\v\u0004\xE2\b\u0004\xE3\u0006\u0004\xE4\u000F\u0004\xE5\u000F\u0004\xE0\u0010\u0004\xE1\n\u0004\xE2\u0006\u0004\xE3\u0005\u0004\xE4\u000E\u0004\xE5\u000F\u0004\xE0\u000F\u0004\xE1\t\u0004\xE2\u0006\u0004\xE3\u0004\u0004\xE4\r\u0004\xE5\u000E\u0004\xE0\u000F\u0004\xE1\t\u0004\xE2\u0006\u0004\xE3\u0004\u0004\xE4\r\u0004\xE5\u000E\u0004\xE0\u000E\u0004\xE1\b\u0004\xE2\u0004\u0004\xE3\u0003\u0004\xE4\f\u0004\xE5\r\u0004\xE0\u000E\u0004\xE1\a\u0004\xE2\u0004\u0004\xE3\u0003\u0004"
|
23
|
+
|
24
|
+
when Board::FIRMWARE_QUERY
|
25
|
+
"\xF0y\u0002\u0003S\u0000t\u0000a\u0000n\u0000d\u0000a\u0000r\u0000d\u0000F\u0000i\u0000r\u0000m\u0000a\u0000t\u0000a\u0000\xF7"
|
26
|
+
|
27
|
+
when Board::START_SYSEX
|
28
|
+
case command.getbyte(1)
|
29
|
+
when Board::ANALOG_MAPPING_QUERY
|
30
|
+
"\xF0j\u007F\u007F\u007F\u007F\u007F\u007F\u007F\u007F\u007F\u007F\u007F\u007F\u007F\u007F\u0000\u0001\u0002\u0003\u0004\u0005\xF7"
|
31
|
+
|
32
|
+
when Board::CAPABILITY_QUERY
|
33
|
+
"\xF0l\u007F\u007F\u0000\u0001\u0001\u0001\u0004\u000E\u007F\u0000\u0001\u0001\u0001\u0003\b\u0004\u000E\u007F\u0000\u0001\u0001\u0001\u0004\u000E\u007F\u0000\u0001\u0001\u0001\u0003\b\u0004\u000E\u007F\u0000\u0001\u0001\u0001\u0003\b\u0004\u000E\u007F\u0000\u0001\u0001\u0001\u0004\u000E\u007F\u0000\u0001\u0001\u0001\u0004\u000E\u007F\u0000\u0001\u0001\u0001\u0003\b\u0004\u000E\u007F\u0000\u0001\u0001\u0001\u0003\b\u0004\u000E\u007F\u0000\u0001\u0001\u0001\u0003\b\u0004\u000E\u007F\u0000\u0001\u0001\u0001\u0004\u000E\u007F\u0000\u0001\u0001\u0001\u0004\u000E\u007F\u0000\u0001\u0001\u0001\u0002\n\u007F\u0000\u0001\u0001\u0001\u0002\n\u007F\u0000\u0001\u0001\u0001\u0002\n\u007F\u0000\u0001\u0001\u0001\u0002\n\u007F\u0000\u0001\u0001\u0001\u0002\n\u0006\u0001\u007F\u0000\u0001\u0001\u0001\u0002\n\u0006\u0001\u007F\xF7"
|
34
|
+
|
35
|
+
when Board::PIN_STATE_QUERY
|
36
|
+
"\xF0n\r\u0001\u0000\xF7"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
@buffer << val
|
41
|
+
val.length
|
42
|
+
end
|
43
|
+
alias_method :write_nonblock, :write
|
44
|
+
|
45
|
+
def bytes
|
46
|
+
bytes = StringIO.new(@buffer).bytes
|
47
|
+
@buffer = ""
|
48
|
+
bytes
|
49
|
+
end
|
50
|
+
|
51
|
+
def read(size)
|
52
|
+
@buffer
|
53
|
+
end
|
54
|
+
alias_method :read_nonblock, :read
|
55
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hybridgroup-firmata
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- ! '''Mike Breen'', ''Adrian Zankich'''
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-10 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: pry
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: event_spitter
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description: A lib for working with the Firmata protocol in Ruby.
|
47
|
+
email:
|
48
|
+
- info@hybridgroup.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .gitignore
|
54
|
+
- Gemfile
|
55
|
+
- LICENSE
|
56
|
+
- README.md
|
57
|
+
- Rakefile
|
58
|
+
- examples/blink_led.rb
|
59
|
+
- firmata.gemspec
|
60
|
+
- lib/firmata.rb
|
61
|
+
- lib/firmata/board.rb
|
62
|
+
- lib/firmata/version.rb
|
63
|
+
- test/board_test.rb
|
64
|
+
- test/fake_serial_port.rb
|
65
|
+
homepage: ''
|
66
|
+
licenses: []
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
requirements: []
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 1.8.23
|
86
|
+
signing_key:
|
87
|
+
specification_version: 3
|
88
|
+
summary: ''
|
89
|
+
test_files:
|
90
|
+
- test/board_test.rb
|
91
|
+
- test/fake_serial_port.rb
|