firmata 0.0.2
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 +18 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +52 -0
- data/Rakefile +11 -0
- data/firmata.gemspec +20 -0
- data/lib/firmata/board.rb +340 -0
- data/lib/firmata/version.rb +3 -0
- data/lib/firmata.rb +2 -0
- data/sample.rb +25 -0
- data/test/board_test.rb +198 -0
- data/test/fake_serial_port.rb +53 -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,52 @@
|
|
|
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
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
Here is a simple example using IRB that will turn pin 13 on and off.
|
|
32
|
+
(Replace xxxxx with the USB port from step 5 in Prerequisites)
|
|
33
|
+
|
|
34
|
+
1.9.3p194 :001 > require 'firmata'
|
|
35
|
+
1.9.3p194 :002 > board = Firmata::Board.new('/dev/tty.usbmodemxxxxx')
|
|
36
|
+
1.9.3p194 :003 > board.connect
|
|
37
|
+
1.9.3p194 :004 > board.connected?
|
|
38
|
+
=> true
|
|
39
|
+
1.9.3p194 :005 > board.version
|
|
40
|
+
=> "2.3"
|
|
41
|
+
1.9.3p194 :006 > board.firmware_name
|
|
42
|
+
=> "StandardFirmata"
|
|
43
|
+
1.9.3p194 :007 > board.digital_write(13, Firmata::Board::HIGH)
|
|
44
|
+
1.9.3p194 :008 > board.digital_write(13, Firmata::Board::LOW)
|
|
45
|
+
|
|
46
|
+
## Contributing
|
|
47
|
+
|
|
48
|
+
1. Fork it
|
|
49
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
50
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
|
51
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
52
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/firmata.gemspec
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
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'"]
|
|
6
|
+
gem.email = ["hardbap@gmail.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 = "firmata"
|
|
15
|
+
gem.require_paths = ["lib"]
|
|
16
|
+
gem.version = Firmata::VERSION
|
|
17
|
+
|
|
18
|
+
gem.add_runtime_dependency("serialport", ["~> 1.1.0"])
|
|
19
|
+
gem.add_runtime_dependency("event_spitter")
|
|
20
|
+
end
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
require 'serialport'
|
|
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(:supportedModes, :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
|
+
def initialize(port)
|
|
73
|
+
@serial_port = port.is_a?(String) ? SerialPort.new(port, 57600, 8, 1, SerialPort::NONE) : port
|
|
74
|
+
@serial_port.read_timeout = 2
|
|
75
|
+
@major_version = 0
|
|
76
|
+
@minor_version = 0
|
|
77
|
+
@pins = []
|
|
78
|
+
@analog_pins = []
|
|
79
|
+
@connected = false
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def connected?
|
|
83
|
+
@connected
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def connect
|
|
87
|
+
unless @connected
|
|
88
|
+
self.once('report_version', ->() do
|
|
89
|
+
self.once('firmware_query', ->() do
|
|
90
|
+
self.once('capability_query', ->() do
|
|
91
|
+
self.once('analog_mapping_query', ->() do
|
|
92
|
+
@connected = true
|
|
93
|
+
emit('ready')
|
|
94
|
+
end)
|
|
95
|
+
query_analog_mapping
|
|
96
|
+
end)
|
|
97
|
+
query_capabilities
|
|
98
|
+
end)
|
|
99
|
+
end)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Internal: Write data to the underlying serial port.
|
|
104
|
+
#
|
|
105
|
+
# commands - Zero or more byte commands to be written.
|
|
106
|
+
#
|
|
107
|
+
# Examples
|
|
108
|
+
#
|
|
109
|
+
# write(START_SYSEX, CAPABILITY_QUERY, END_SYSEX)
|
|
110
|
+
#
|
|
111
|
+
# Returns nothing.
|
|
112
|
+
def write(*commands)
|
|
113
|
+
serial_port.write(commands.map(&:chr).join)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Internal: Read data from the underlying serial port.
|
|
117
|
+
#
|
|
118
|
+
# Returns Enumerator of bytes.
|
|
119
|
+
def read
|
|
120
|
+
serial_port.bytes
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Internal: Process a series of bytes.
|
|
124
|
+
#
|
|
125
|
+
# bytes: An Enumerator of bytes (default: read())
|
|
126
|
+
#
|
|
127
|
+
# Returns nothing.
|
|
128
|
+
def process(bytes = read)
|
|
129
|
+
bytes.each do |byte|
|
|
130
|
+
case byte
|
|
131
|
+
when REPORT_VERSION
|
|
132
|
+
@major_version = bytes.next
|
|
133
|
+
@minor_version = bytes.next
|
|
134
|
+
|
|
135
|
+
emit('report_version')
|
|
136
|
+
|
|
137
|
+
when ANALOG_MESSAGE_RANGE
|
|
138
|
+
least_significant_byte = bytes.next
|
|
139
|
+
most_significant_byte = bytes.next
|
|
140
|
+
|
|
141
|
+
value = least_significant_byte | (most_significant_byte << 7)
|
|
142
|
+
pin = byte & 0x0F
|
|
143
|
+
|
|
144
|
+
if analog_pin = analog_pins[pin]
|
|
145
|
+
pins[analog_pin].value = value
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
when START_SYSEX
|
|
149
|
+
current_buffer = [byte]
|
|
150
|
+
begin
|
|
151
|
+
current_buffer.push(bytes.next)
|
|
152
|
+
end until current_buffer.last == END_SYSEX
|
|
153
|
+
|
|
154
|
+
command = current_buffer[1]
|
|
155
|
+
|
|
156
|
+
case command
|
|
157
|
+
when CAPABILITY_RESPONSE
|
|
158
|
+
supportedModes = 0
|
|
159
|
+
n = 0
|
|
160
|
+
|
|
161
|
+
current_buffer.slice(2, current_buffer.length - 3).each do |byte|
|
|
162
|
+
if byte == 127
|
|
163
|
+
modesArray = []
|
|
164
|
+
# the pin modes
|
|
165
|
+
[ INPUT, OUTPUT, ANALOG, PWM, SERVO ].each do |mode|
|
|
166
|
+
modesArray.push(mode) unless (supportedModes & (1 << mode)).zero?
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
@pins.push(Pin.new(modesArray, OUTPUT, 0))
|
|
170
|
+
|
|
171
|
+
supportedModes = 0
|
|
172
|
+
n = 0
|
|
173
|
+
next
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
supportedModes |= (1 << byte) if n.zero?
|
|
177
|
+
|
|
178
|
+
n ^= 1
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
emit('capability_query')
|
|
182
|
+
|
|
183
|
+
when ANALOG_MAPPING_RESPONSE
|
|
184
|
+
pin_index = 0
|
|
185
|
+
|
|
186
|
+
current_buffer.slice(2, current_buffer.length - 3).each do |byte|
|
|
187
|
+
|
|
188
|
+
@pins[pin_index].analog_channel = byte
|
|
189
|
+
|
|
190
|
+
@analog_pins.push(pin_index) unless byte == 127
|
|
191
|
+
|
|
192
|
+
pin_index += 1
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
emit('analog_mapping_query')
|
|
196
|
+
|
|
197
|
+
when PIN_STATE_RESPONSE
|
|
198
|
+
pin = pins[current_buffer[2]]
|
|
199
|
+
pin.mode = current_buffer[3]
|
|
200
|
+
pin.value = current_buffer[4]
|
|
201
|
+
|
|
202
|
+
pin.value |= (current_buffer[5] << 7) if current_buffer.size > 6
|
|
203
|
+
|
|
204
|
+
pin.value |= (current_buffer[6] << 14) if current_buffer.size > 7
|
|
205
|
+
|
|
206
|
+
when FIRMWARE_QUERY
|
|
207
|
+
@firmware_name = current_buffer.slice(4, current_buffer.length - 5).reject { |b| b.zero? }.map(&:chr).join
|
|
208
|
+
emit('firmware_query')
|
|
209
|
+
|
|
210
|
+
else
|
|
211
|
+
# TODO decide what to do with unknown message
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
rescue StopIteration
|
|
216
|
+
# do nadda
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Public: Send a SYSTEM_RESET to the Arduino
|
|
220
|
+
#
|
|
221
|
+
# Returns nothing.
|
|
222
|
+
def reset
|
|
223
|
+
write(SYSTEM_RESET)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Public: Set the mode for a pin.
|
|
227
|
+
#
|
|
228
|
+
# pin - The Integer pin to set.
|
|
229
|
+
# mode - The Fixnum mode (INPUT, OUTPUT, ANALOG, PWM or SERVO)
|
|
230
|
+
#
|
|
231
|
+
# Examples
|
|
232
|
+
#
|
|
233
|
+
# pin_mode(13, OUTPUT)
|
|
234
|
+
#
|
|
235
|
+
# Returns nothing.
|
|
236
|
+
def pin_mode(pin, mode)
|
|
237
|
+
pins[pin].mode = mode
|
|
238
|
+
write(PIN_MODE, pin, mode)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Public: Write a value to a digital pin.
|
|
242
|
+
#
|
|
243
|
+
# pin - The Integer pin to write to.
|
|
244
|
+
# value - The value to write (HIGH or LOW).
|
|
245
|
+
#
|
|
246
|
+
# Returns nothing.
|
|
247
|
+
def digital_write(pin, value)
|
|
248
|
+
port = (pin / 8).floor
|
|
249
|
+
port_value = 0
|
|
250
|
+
|
|
251
|
+
@pins[pin].value = value
|
|
252
|
+
|
|
253
|
+
8.times do |i|
|
|
254
|
+
port_value |= (1 << i) unless @pins[8 * port + i].value.zero?
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
write(DIGITAL_MESSAGE | port, port_value & 0x7F, (port_value >> 7) & 0x7F)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Public: Ask the Arduino to sleep for a number of seconds.
|
|
261
|
+
#
|
|
262
|
+
# seconds - The Integer seconds to sleep for.
|
|
263
|
+
#
|
|
264
|
+
# Returns nothing.
|
|
265
|
+
def delay(seconds)
|
|
266
|
+
sleep(seconds)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# Public: The major and minor firmware version on the board. Will report as
|
|
270
|
+
# "0.0" if report_version command has not been run.
|
|
271
|
+
#
|
|
272
|
+
# Returns String the firmware version as "minor.major".
|
|
273
|
+
def version
|
|
274
|
+
[@major_version, @minor_version].join('.')
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Public: Ask the Arduino to report its version.
|
|
278
|
+
#
|
|
279
|
+
# Returns nothing.
|
|
280
|
+
def report_version
|
|
281
|
+
write(REPORT_VERSION)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Public: Ask the Ardution for its firmware name.
|
|
285
|
+
#
|
|
286
|
+
# Returns nothing.
|
|
287
|
+
def query_firmware
|
|
288
|
+
write(FIRMWARE_QUERY)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Public: Ask the Arduino for the current configuration of any pin.
|
|
292
|
+
#
|
|
293
|
+
# pin - The Integer pin to query on the board.
|
|
294
|
+
#
|
|
295
|
+
# Returns nothing.
|
|
296
|
+
def query_pin_state(pin)
|
|
297
|
+
write(START_SYSEX, PIN_STATE_QUERY, pin.to_i, END_SYSEX)
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Public: Ask the Arduino about its capabilities and current state.
|
|
301
|
+
#
|
|
302
|
+
# Returns nothing.
|
|
303
|
+
def query_capabilities
|
|
304
|
+
write(START_SYSEX, CAPABILITY_QUERY, END_SYSEX)
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# Public: Ask the Arduino which pins (used with pin mode message) correspond to the analog channels.
|
|
308
|
+
#
|
|
309
|
+
# Returns nothing.
|
|
310
|
+
def query_analog_mapping
|
|
311
|
+
write(START_SYSEX, ANALOG_MAPPING_QUERY, END_SYSEX)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# Internal: Toggle the pin analog and digtal reporting off and on.
|
|
315
|
+
#
|
|
316
|
+
# state - The Integer to turn the pin on (1) or off (0).
|
|
317
|
+
#
|
|
318
|
+
# Returns nothing.
|
|
319
|
+
def toggle_pin_reporting(state)
|
|
320
|
+
16.times do |i|
|
|
321
|
+
write(REPORT_DIGITAL | i, state)
|
|
322
|
+
write(REPORT_ANALOG | i, state)
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# Public: Turn pin analog and digital reporting on.
|
|
327
|
+
#
|
|
328
|
+
# Returns nothing.
|
|
329
|
+
def turn_pin_reporting_on
|
|
330
|
+
toggle_pin_reporting(1)
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# Public: Turn pin analog and digital reporting off.
|
|
334
|
+
#
|
|
335
|
+
# Returns nothing.
|
|
336
|
+
def turn_pin_reporting_off
|
|
337
|
+
toggle_pin_reporting(0)
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
data/lib/firmata.rb
ADDED
data/sample.rb
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'bundler/setup'
|
|
2
|
+
require 'firmata'
|
|
3
|
+
|
|
4
|
+
board = Firmata::Board.new('/dev/tty.usbmodemfa131')
|
|
5
|
+
|
|
6
|
+
board.on('ready', ->() do
|
|
7
|
+
|
|
8
|
+
10.times do
|
|
9
|
+
board.digital_write 13, Firmata::Board::HIGH
|
|
10
|
+
board.delay 1
|
|
11
|
+
|
|
12
|
+
board.digital_write 13, Firmata::Board::LOW
|
|
13
|
+
board.delay 1
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end)
|
|
17
|
+
|
|
18
|
+
board.connect
|
|
19
|
+
|
|
20
|
+
Thread.new do
|
|
21
|
+
loop do
|
|
22
|
+
board.read
|
|
23
|
+
sleep 1
|
|
24
|
+
end
|
|
25
|
+
end
|
data/test/board_test.rb
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
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(:read_timeout=, 2, [2])
|
|
12
|
+
mock_port.expect(:is_a?, false, [nil])
|
|
13
|
+
|
|
14
|
+
if block_given?
|
|
15
|
+
yield mock_port
|
|
16
|
+
else
|
|
17
|
+
expected = args.map(&:chr).join
|
|
18
|
+
mock_port.expect(:write, 1, [expected])
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
mock_port
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_writing_report_version
|
|
25
|
+
mock_sp = mock_serial_port(Firmata::Board::REPORT_VERSION)
|
|
26
|
+
|
|
27
|
+
board = Firmata::Board.new(mock_sp)
|
|
28
|
+
board.report_version
|
|
29
|
+
|
|
30
|
+
mock_sp.verify
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_processing_report_version
|
|
34
|
+
board = Firmata::Board.new(FakeSerialPort.new)
|
|
35
|
+
board.report_version
|
|
36
|
+
board.process
|
|
37
|
+
|
|
38
|
+
assert_equal '2.3', board.version
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_writing_capability_query
|
|
42
|
+
mock_sp = mock_serial_port(Firmata::Board::START_SYSEX, Firmata::Board::CAPABILITY_QUERY, Firmata::Board::END_SYSEX)
|
|
43
|
+
|
|
44
|
+
board = Firmata::Board.new(mock_sp)
|
|
45
|
+
board.query_capabilities
|
|
46
|
+
|
|
47
|
+
mock_sp.verify
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_processing_capabilities_query
|
|
51
|
+
board = Firmata::Board.new(FakeSerialPort.new)
|
|
52
|
+
board.query_capabilities
|
|
53
|
+
board.process
|
|
54
|
+
|
|
55
|
+
assert_equal 20, board.pins.size
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def test_writing_analog_mapping_query
|
|
59
|
+
mock_sp = mock_serial_port(Firmata::Board::START_SYSEX, Firmata::Board::ANALOG_MAPPING_QUERY, Firmata::Board::END_SYSEX)
|
|
60
|
+
|
|
61
|
+
board = Firmata::Board.new(mock_sp)
|
|
62
|
+
board.query_analog_mapping
|
|
63
|
+
|
|
64
|
+
mock_sp.verify
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def test_processing_analog_mapping_query
|
|
68
|
+
board = Firmata::Board.new(FakeSerialPort.new)
|
|
69
|
+
board.query_capabilities
|
|
70
|
+
board.process
|
|
71
|
+
|
|
72
|
+
board.query_analog_mapping
|
|
73
|
+
board.process
|
|
74
|
+
|
|
75
|
+
assert_equal 6, board.analog_pins.size
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_write_pin_mode
|
|
79
|
+
mock_sp = mock_serial_port(Firmata::Board::PIN_MODE, 13, Firmata::Board::OUTPUT)
|
|
80
|
+
|
|
81
|
+
board = Firmata::Board.new(mock_sp)
|
|
82
|
+
board.pins[13] = Firmata::Board::Pin.new([0, 1, 4], 0, 0, nil)
|
|
83
|
+
|
|
84
|
+
board.pin_mode(13, Firmata::Board::OUTPUT)
|
|
85
|
+
|
|
86
|
+
assert_equal Firmata::Board::OUTPUT, board.pins[13].mode
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def test_write_pin_state_query
|
|
90
|
+
mock_sp = mock_serial_port(Firmata::Board::START_SYSEX, Firmata::Board::PIN_STATE_QUERY, 13, Firmata::Board::END_SYSEX)
|
|
91
|
+
|
|
92
|
+
board = Firmata::Board.new(mock_sp)
|
|
93
|
+
board.query_pin_state(13)
|
|
94
|
+
|
|
95
|
+
mock_sp.verify
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def test_processing_pin_state_query
|
|
99
|
+
board = Firmata::Board.new(FakeSerialPort.new)
|
|
100
|
+
board.query_capabilities
|
|
101
|
+
board.process
|
|
102
|
+
|
|
103
|
+
board.pins[13].mode = Firmata::Board::INPUT
|
|
104
|
+
|
|
105
|
+
board.query_pin_state(13)
|
|
106
|
+
board.process
|
|
107
|
+
|
|
108
|
+
assert_equal Firmata::Board::OUTPUT, board.pins[13].mode
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def test_write_turn_pin_reporting_on
|
|
112
|
+
mock_sp = mock_serial_port do |mock|
|
|
113
|
+
16.times do |i|
|
|
114
|
+
mock.expect(:write, 2, [[Firmata::Board::REPORT_DIGITAL | i, 1].map(&:chr).join])
|
|
115
|
+
mock.expect(:write, 2, [[(Firmata::Board::REPORT_ANALOG | i), 1].map(&:chr).join])
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
board = Firmata::Board.new(mock_sp)
|
|
120
|
+
board.turn_pin_reporting_on
|
|
121
|
+
|
|
122
|
+
mock_sp.verify
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def test_turn_pin_reporting_off
|
|
126
|
+
mock_sp = mock_serial_port do |mock|
|
|
127
|
+
16.times do |i|
|
|
128
|
+
mock.expect(:write, 2, [[Firmata::Board::REPORT_DIGITAL | i, 0].map(&:chr).join])
|
|
129
|
+
mock.expect(:write, 2, [[(Firmata::Board::REPORT_ANALOG | i), 0].map(&:chr).join])
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
board = Firmata::Board.new(mock_sp)
|
|
134
|
+
board.turn_pin_reporting_off
|
|
135
|
+
|
|
136
|
+
mock_sp.verify
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def test_processing_analog_message
|
|
140
|
+
fake_port = FakeSerialPort.new
|
|
141
|
+
board = Firmata::Board.new(fake_port)
|
|
142
|
+
|
|
143
|
+
board.query_capabilities
|
|
144
|
+
board.process
|
|
145
|
+
|
|
146
|
+
board.query_analog_mapping
|
|
147
|
+
board.process
|
|
148
|
+
|
|
149
|
+
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"
|
|
150
|
+
board.process
|
|
151
|
+
|
|
152
|
+
board.analog_pins.each do |pin|
|
|
153
|
+
refute_nil board.pins[pin].analog_channel, "Analog channel not set for pin #{pin}"
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def test_reset
|
|
158
|
+
mock_sp = mock_serial_port(Firmata::Board::SYSTEM_RESET)
|
|
159
|
+
|
|
160
|
+
board = Firmata::Board.new(mock_sp)
|
|
161
|
+
board.reset
|
|
162
|
+
|
|
163
|
+
mock_sp.verify
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def test_write_firmware_query
|
|
167
|
+
mock_sp = mock_serial_port(Firmata::Board::FIRMWARE_QUERY)
|
|
168
|
+
|
|
169
|
+
board = Firmata::Board.new(mock_sp)
|
|
170
|
+
board.query_firmware
|
|
171
|
+
|
|
172
|
+
mock_sp.verify
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def test_process_firmware_query
|
|
176
|
+
fake_port = FakeSerialPort.new
|
|
177
|
+
fake_port.buffer = "\xF0y\u0002\u0003S\u0000t\u0000a\u0000n\u0000d\u0000a\u0000r\u0000d\u0000F\u0000i\u0000r\u0000m\u0000a\u0000t\u0000a\u0000\xF7"
|
|
178
|
+
board = Firmata::Board.new(fake_port)
|
|
179
|
+
|
|
180
|
+
board.process
|
|
181
|
+
|
|
182
|
+
assert_equal 'StandardFirmata', board.firmware_name, 'Firmware Name is incorrect'
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def test_digital_write
|
|
186
|
+
mock_sp = mock_serial_port(145, 127, 1)
|
|
187
|
+
board = Firmata::Board.new(mock_sp)
|
|
188
|
+
|
|
189
|
+
8.times do |x|
|
|
190
|
+
board.pins[x + 8] = Firmata::Board::Pin.new([], 0, 250 + x, nil)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
board.digital_write(13, 1)
|
|
194
|
+
|
|
195
|
+
mock_sp.verify
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
|
|
44
|
+
def bytes
|
|
45
|
+
bytes = StringIO.new(@buffer).bytes
|
|
46
|
+
@buffer = ""
|
|
47
|
+
bytes
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def read
|
|
51
|
+
@buffer.read
|
|
52
|
+
end
|
|
53
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: firmata
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.2
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- ! '''Mike Breen'''
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-08-17 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: serialport
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ~>
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: 1.1.0
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ~>
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: 1.1.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
|
+
- hardbap@gmail.com
|
|
49
|
+
executables: []
|
|
50
|
+
extensions: []
|
|
51
|
+
extra_rdoc_files: []
|
|
52
|
+
files:
|
|
53
|
+
- .gitignore
|
|
54
|
+
- Gemfile
|
|
55
|
+
- LICENSE
|
|
56
|
+
- README.md
|
|
57
|
+
- Rakefile
|
|
58
|
+
- firmata.gemspec
|
|
59
|
+
- lib/firmata.rb
|
|
60
|
+
- lib/firmata/board.rb
|
|
61
|
+
- lib/firmata/version.rb
|
|
62
|
+
- sample.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.24
|
|
86
|
+
signing_key:
|
|
87
|
+
specification_version: 3
|
|
88
|
+
summary: ''
|
|
89
|
+
test_files:
|
|
90
|
+
- test/board_test.rb
|
|
91
|
+
- test/fake_serial_port.rb
|