smalrubot 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LEGAL +82 -0
- data/LICENSE +22 -0
- data/README.md +48 -0
- data/Rakefile +35 -0
- data/bin/smalrubot +82 -0
- data/examples/test.rb +13 -0
- data/lib/smalrubot.rb +32 -0
- data/lib/smalrubot/board.rb +104 -0
- data/lib/smalrubot/board_not_found.rb +3 -0
- data/lib/smalrubot/components.rb +9 -0
- data/lib/smalrubot/components/base_component.rb +44 -0
- data/lib/smalrubot/components/led.rb +18 -0
- data/lib/smalrubot/components/servo.rb +21 -0
- data/lib/smalrubot/tx_rx.rb +10 -0
- data/lib/smalrubot/tx_rx/base.rb +54 -0
- data/lib/smalrubot/tx_rx/serial.rb +70 -0
- data/lib/smalrubot/version.rb +3 -0
- data/sketch/lib/Smalrubot.cpp +158 -0
- data/sketch/lib/Smalrubot.h +60 -0
- data/sketch/sr/sr.ino +18 -0
- data/smalrubot.gemspec +26 -0
- data/spec/lib/board_not_found_spec.rb +8 -0
- data/spec/lib/board_spec.rb +120 -0
- data/spec/lib/components/base_component_spec.rb +66 -0
- data/spec/lib/components/led_spec.rb +49 -0
- data/spec/lib/components/servo_spec.rb +58 -0
- data/spec/lib/tx_rx/serial_spec.rb +81 -0
- data/spec/spec_helper.rb +12 -0
- metadata +140 -0
data/sketch/sr/sr.ino
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#include "Smalrubot.h"
|
2
|
+
#include <Servo.h>
|
3
|
+
Smalrubot smalrubot;
|
4
|
+
|
5
|
+
// Smalrubot.h doesn't handle TXRX. Setup a function to tell it to write to Serial.
|
6
|
+
void writeResponse(char *response) { Serial.println(response); }
|
7
|
+
void (*writeCallback)(char *str) = writeResponse;
|
8
|
+
|
9
|
+
void setup() {
|
10
|
+
Serial.begin(115200);
|
11
|
+
smalrubot.setupWrite(writeCallback);
|
12
|
+
}
|
13
|
+
|
14
|
+
void loop() {
|
15
|
+
while(Serial.available() > 0) smalrubot.parse(Serial.read());
|
16
|
+
Serial.flush();
|
17
|
+
}
|
18
|
+
|
data/smalrubot.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'smalrubot/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "smalrubot"
|
8
|
+
spec.version = Smalrubot::VERSION
|
9
|
+
spec.authors = ["Kouji Takao"]
|
10
|
+
spec.email = ["kouji.takao@gmail.com"]
|
11
|
+
spec.summary = %q{A library and an Arduino sketch for Smalruby.}
|
12
|
+
spec.description = %q{The smalrubot is a library and an Arduino sketch for Smalruby.}
|
13
|
+
spec.homepage = "https://github.com/smalruby/smalrubot"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'rubyserial'
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "rspec"
|
26
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Smalrubot
|
4
|
+
describe Smalrubot::Board do
|
5
|
+
def io_mock(methods = {})
|
6
|
+
@io ||= double(:io, {write: nil, flush_read: nil, handshake: "14"}.merge(methods))
|
7
|
+
end
|
8
|
+
|
9
|
+
subject { Board.new(io_mock) }
|
10
|
+
|
11
|
+
describe '#initialize' do
|
12
|
+
it 'should take an io class' do
|
13
|
+
expect {
|
14
|
+
Board.new(io_mock)
|
15
|
+
}.to_not raise_exception
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should initiate the handshake' do
|
19
|
+
io_mock.should_receive(:handshake)
|
20
|
+
subject
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#write' do
|
25
|
+
it 'should return true if the write succeeds' do
|
26
|
+
@io = nil
|
27
|
+
board = Board.new(io_mock(write: true))
|
28
|
+
board.write('message').should == true
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should wrap the message in a ! and a . by default' do
|
32
|
+
io_mock.should_receive(:write).with('!hello.')
|
33
|
+
subject.write('hello')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should not wrap the message if no_wrap is set to true' do
|
37
|
+
board = Board.new(io_mock)
|
38
|
+
io_mock.should_receive(:write).with('hello')
|
39
|
+
board.write('hello', no_wrap: true)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#digital_write' do
|
44
|
+
it 'should append a append a write to the pin and value' do
|
45
|
+
io_mock.should_receive(:write).with('!0101003.')
|
46
|
+
subject.digital_write(01, 003)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#digital_read' do
|
51
|
+
it 'should tell the board to read once from the given pin' do
|
52
|
+
io_mock.should_receive(:write).with('!0213000.')
|
53
|
+
io_mock.should_receive(:read).with(1).and_return(['13', Smalrubot::Board::HIGH.to_s])
|
54
|
+
expect(subject.digital_read(13)).to eq(Smalrubot::Board::HIGH)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#analog_write' do
|
59
|
+
it 'should append a append a write to the pin and value' do
|
60
|
+
io_mock.should_receive(:write).with('!0301003.')
|
61
|
+
subject.analog_write(01, 003)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#analog_read' do
|
66
|
+
it 'should tell the board to read once from the given pin' do
|
67
|
+
io_mock.should_receive(:write).with('!0413000.')
|
68
|
+
io_mock.should_receive(:read).with(1).once.and_return(['13', '256'])
|
69
|
+
expect(subject.analog_read(13)).to eq(256)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#set_pin_mode' do
|
74
|
+
it 'should send a value of 0 if the pin mode is set to out' do
|
75
|
+
io_mock.should_receive(:write).with('!0013000.')
|
76
|
+
subject.set_pin_mode(13, :out)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should send a value of 1 if the pin mode is set to in' do
|
80
|
+
io_mock.should_receive(:write).with('!0013001.')
|
81
|
+
subject.set_pin_mode(13, :in)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#handshake' do
|
86
|
+
it 'should tell the board to reset to defaults' do
|
87
|
+
io_mock.should_receive(:handshake)
|
88
|
+
subject.handshake
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#normalize_pin' do
|
93
|
+
it 'should normalize numbers so they are two digits' do
|
94
|
+
subject.normalize_pin(1).should == '01'
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should not normalize numbers that are already two digits' do
|
98
|
+
subject.normalize_pin(10).should == '10'
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should raise if a number larger than two digits are given' do
|
102
|
+
expect { subject.normalize_pin(1000) }.to raise_exception 'pin number must be in 0-99'
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#normalize_value' do
|
107
|
+
it 'should normalize numbers so they are three digits' do
|
108
|
+
subject.normalize_value(1).should == '001'
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should not normalize numbers that are already three digits' do
|
112
|
+
subject.normalize_value(10).should == '010'
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should raise if a number larger than three digits are given' do
|
116
|
+
expect { subject.normalize_value(1000) }.to raise_exception 'values are limited to three digits'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Smalrubot
|
4
|
+
module Components
|
5
|
+
|
6
|
+
describe BaseComponent do
|
7
|
+
|
8
|
+
it 'should initialize with board and pin' do
|
9
|
+
pin = "a pin"
|
10
|
+
board = "a board"
|
11
|
+
component = BaseComponent.new(pin: pin, board: board)
|
12
|
+
|
13
|
+
component.pin.should == pin
|
14
|
+
component.board.should == board
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should assign pins' do
|
18
|
+
pins = {red: 'red', green: 'green', blue: 'blue'}
|
19
|
+
board = "a board"
|
20
|
+
component = BaseComponent.new(pins: pins, board: board)
|
21
|
+
|
22
|
+
component.pins.should == pins
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should require a pin or pins' do
|
26
|
+
expect {
|
27
|
+
BaseComponent.new(board: 'some board')
|
28
|
+
}.to raise_exception
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should require a board' do
|
32
|
+
expect {
|
33
|
+
BaseComponent.new(pin: 'some pin')
|
34
|
+
}.to raise_exception
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when subclassed #after_initialize should be executed" do
|
38
|
+
|
39
|
+
class SpecComponent < BaseComponent
|
40
|
+
|
41
|
+
def sucessfully_initialized? ; @success ; end
|
42
|
+
|
43
|
+
def options ; @options ; end
|
44
|
+
|
45
|
+
def after_initialize(options={})
|
46
|
+
@success = true
|
47
|
+
@options = options
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
let(:options) { { pin: pin, board: board } }
|
52
|
+
let(:pin) { "a pin" }
|
53
|
+
let(:board) { "a board" }
|
54
|
+
|
55
|
+
it "should call #after_initialize with options" do
|
56
|
+
component = SpecComponent.new(options)
|
57
|
+
component.should be_sucessfully_initialized
|
58
|
+
component.options.should eq options
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Smalrubot
|
4
|
+
module Components
|
5
|
+
describe Led do
|
6
|
+
let(:board) { double(:board, digital_write: true, set_pin_mode: true) }
|
7
|
+
|
8
|
+
describe '#initialize' do
|
9
|
+
it 'should raise if it does not receive a pin' do
|
10
|
+
expect {
|
11
|
+
Led.new(board: board)
|
12
|
+
}.to raise_exception
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should raise if it does not receive a board' do
|
16
|
+
expect {
|
17
|
+
Led.new(pins: {})
|
18
|
+
}.to raise_exception
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should set the pin to out' do
|
22
|
+
board.should_receive(:set_pin_mode).with(13, :out, nil)
|
23
|
+
Led.new(pin: 13, board: board)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should set the pin to low' do
|
27
|
+
board.should_receive(:digital_write).with(13, Board::LOW)
|
28
|
+
Led.new(pin: 13, board: board)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#on' do
|
33
|
+
it 'should send a high to the board with the pin' do
|
34
|
+
@led = Led.new(pin: 13, board: board)
|
35
|
+
board.should_receive(:digital_write).with(13, Board::HIGH)
|
36
|
+
@led.on
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#off' do
|
41
|
+
it 'should send a high to the board with the pin' do
|
42
|
+
@led = Led.new(pin: 13, board: board)
|
43
|
+
board.should_receive(:digital_write).with(13, Board::LOW)
|
44
|
+
@led.off
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Smalrubot
|
4
|
+
module Components
|
5
|
+
describe Servo do
|
6
|
+
let(:board) { double(:board, analog_write: true, set_pin_mode: true, servo_toggle: true, servo_write: true) }
|
7
|
+
|
8
|
+
describe '#initialize' do
|
9
|
+
it 'should raise if it does not receive a pin' do
|
10
|
+
expect {
|
11
|
+
Servo.new(board: board)
|
12
|
+
}.to raise_exception
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should raise if it does not receive a board' do
|
16
|
+
expect {
|
17
|
+
Servo.new(pin: 13)
|
18
|
+
}.to raise_exception
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should set the pins to out' do
|
22
|
+
board.should_receive(:set_pin_mode).with(13, :out, nil)
|
23
|
+
Servo.new(pin: 13, board: board)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should set the inital position to 0' do
|
27
|
+
servo = Servo.new(pin: 13, board: board)
|
28
|
+
servo.instance_variable_get(:@position).should == 0
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#position' do
|
33
|
+
let(:servo) {servo = Servo.new(pin: 13, board: board)}
|
34
|
+
|
35
|
+
it 'should set the position of the Servo' do
|
36
|
+
servo.position = 90
|
37
|
+
servo.instance_variable_get(:@position).should == 90
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should let you write up to 180' do
|
41
|
+
servo.position = 180
|
42
|
+
servo.instance_variable_get(:@position).should == 180
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should modulate when position > 180' do
|
46
|
+
servo.position = 190
|
47
|
+
servo.instance_variable_get(:@position).should == 10
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should write the new position to the board' do
|
51
|
+
board.should_receive(:servo_write).with(13, 10)
|
52
|
+
servo.position = 190
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Smalrubot
|
4
|
+
describe TxRx::Serial do
|
5
|
+
it { should be }
|
6
|
+
|
7
|
+
describe '#initialize' do
|
8
|
+
it 'should set first_write to true' do
|
9
|
+
TxRx::Serial.new.instance_variable_get(:@first_write).should == true
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should set the device and buad if specified' do
|
13
|
+
txrx = TxRx::Serial.new({device: "/dev/ttyACM0", baud: 9600})
|
14
|
+
txrx.instance_variable_get(:@baud).should == 9600
|
15
|
+
txrx.instance_variable_get(:@device).should == "/dev/ttyACM0"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#io' do
|
20
|
+
context "on windows" do
|
21
|
+
it 'should instantiate a new ::Serial for the first available tty device' do
|
22
|
+
original_platform = RUBY_PLATFORM
|
23
|
+
Constants.redefine(:RUBY_PLATFORM, "mswin", :on => Object)
|
24
|
+
subject.instance_variable_set('@tty_devices', ["COM1", "COM2", "COM3"])
|
25
|
+
|
26
|
+
# COM2 is chosen as available for this test.
|
27
|
+
::Serial.should_receive(:new).with("COM1", TxRx::Serial::BAUD).and_raise
|
28
|
+
::Serial.should_receive(:new).with("COM2", TxRx::Serial::BAUD).and_return(mock_serial = double)
|
29
|
+
::Serial.should_not_receive(:new).with("COM3", TxRx::Serial::BAUD)
|
30
|
+
|
31
|
+
subject.io.should == mock_serial
|
32
|
+
Constants.redefine(:RUBY_PLATFORM, original_platform, :on => Object)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "on unix" do
|
37
|
+
it 'should instantiate a new ::Serial for the first available tty device' do
|
38
|
+
subject.should_receive(:tty_devices).and_return(['/dev/ttyACM0', '/dev/tty.usbmodem1'])
|
39
|
+
|
40
|
+
# /dev/ttyACM0 is chosen as available for this test.
|
41
|
+
::Serial.should_receive(:new).with('/dev/ttyACM0', TxRx::Serial::BAUD).and_return(mock_serial = double)
|
42
|
+
::Serial.should_not_receive(:new).with('/dev/tty.usbmodem1', TxRx::Serial::BAUD)
|
43
|
+
|
44
|
+
subject.io.should == mock_serial
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should connect to the specified device at the specified baud rate' do
|
49
|
+
subject.should_receive(:tty_devices).and_return(["/dev/ttyACM0"])
|
50
|
+
::Serial.should_receive(:new).with('/dev/ttyACM0', 9600).and_return(mock_serial = double)
|
51
|
+
|
52
|
+
subject.instance_variable_set(:@device, "/dev/ttyACM0")
|
53
|
+
subject.instance_variable_set(:@baud, 9600)
|
54
|
+
|
55
|
+
subject.io.should == mock_serial
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should use the existing io instance if set' do
|
59
|
+
subject.should_receive(:tty_devices).once.and_return(['/dev/tty.ACM0', '/dev/tty.usbmodem1'])
|
60
|
+
::Serial.stub(:new).and_return(mock_serial = double)
|
61
|
+
|
62
|
+
3.times { subject.io }
|
63
|
+
subject.io.should == mock_serial
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should raise a BoardNotFound exception if there is no board connected' do
|
67
|
+
::Serial.stub(:new).and_raise
|
68
|
+
expect { subject.io }.to raise_exception BoardNotFound
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#write' do
|
73
|
+
it 'should write to the device' do
|
74
|
+
subject.stub(:io).and_return(mock_serial = double)
|
75
|
+
msg = 'a message'
|
76
|
+
mock_serial.should_receive(:write).with(msg).and_return(msg.length)
|
77
|
+
subject.write('a message')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
|
3
|
+
require File.expand_path(File.join('../..', 'lib/smalrubot'), __FILE__)
|
4
|
+
|
5
|
+
# Nice little helper module to redefine constants quietly.
|
6
|
+
module Constants
|
7
|
+
def self.redefine(const, value, opts={})
|
8
|
+
opts = {:on => self.class}.merge(opts)
|
9
|
+
opts[:on].send(:remove_const, const) if self.class.const_defined?(const)
|
10
|
+
opts[:on].const_set(const, value)
|
11
|
+
end
|
12
|
+
end
|