smalrubot 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+
@@ -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,8 @@
1
+ require 'spec_helper'
2
+
3
+ module Smalrubot
4
+ describe BoardNotFound do
5
+ it { should be }
6
+ it { should be_a Exception }
7
+ end
8
+ 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
@@ -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