hybridgroup-firmata 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .rvmrc
19
+ harness.rb
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in firmata.gemspec
4
+ gemspec
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,11 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs.push "lib"
7
+ t.test_files = FileList['test/*_test.rb']
8
+ t.verbose = true
9
+ end
10
+
11
+ task :default => [:test]
@@ -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,2 @@
1
+ require 'firmata/version'
2
+ require 'firmata/board'
@@ -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
@@ -0,0 +1,3 @@
1
+ module Firmata
2
+ VERSION = "0.2.0"
3
+ end
@@ -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