dino 0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,53 @@
1
+ module Dino
2
+ module Components
3
+ class Button < BaseComponent
4
+ UP = "01"
5
+ DOWN = "00"
6
+
7
+ def initialize(options={})
8
+ super(options)
9
+
10
+ @down_callbacks, @up_callbacks, @state = [], [], UP
11
+
12
+ self.board.add_digital_hardware(self)
13
+ self.board.start_read
14
+ end
15
+
16
+ def down(callback)
17
+ @down_callbacks << callback
18
+ end
19
+
20
+ def up(callback)
21
+ @up_callbacks << callback
22
+ end
23
+
24
+ def update(data)
25
+ return if data == @state
26
+ @state = data
27
+
28
+ case data
29
+ when UP
30
+ button_up
31
+ when DOWN
32
+ button_down
33
+ else
34
+ return
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def button_up
41
+ @up_callbacks.each do |callback|
42
+ callback.call
43
+ end
44
+ end
45
+
46
+ def button_down
47
+ @down_callbacks.each do |callback|
48
+ callback.call
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,33 @@
1
+ module Dino
2
+ module Components
3
+ class IrReceiver < BaseComponent
4
+ STABLE = "01"
5
+
6
+ def initialize(options={})
7
+ super(options)
8
+
9
+ @flash_callbacks = []
10
+
11
+ self.board.add_digital_hardware(self)
12
+ self.board.start_read
13
+ end
14
+
15
+ def flash(callback)
16
+ @flash_callbacks << callback
17
+ end
18
+
19
+ def update(data)
20
+ return if data == STABLE
21
+ light_flashed
22
+ end
23
+
24
+ private
25
+
26
+ def light_flashed
27
+ @flash_callbacks.each do |callback|
28
+ callback.call
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ module Dino
2
+ module Components
3
+ class Led < BaseComponent
4
+ def initialize(options={})
5
+ super(options)
6
+
7
+ set_pin_mode(:out)
8
+ digital_write(Board::LOW)
9
+ end
10
+
11
+ def on
12
+ digital_write(Board::HIGH)
13
+ end
14
+
15
+ def off
16
+ digital_write(Board::LOW)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,44 @@
1
+ module Dino
2
+ module Components
3
+ class RgbLed < BaseComponent
4
+ # options = {board: my_board, pins: {red: red_pin, green: green_pin, blue: blue_pin}
5
+ def initialize(options={})
6
+ super(options)
7
+
8
+ raise 'missing pins[:red] pin' unless self.pins[:red]
9
+ raise 'missing pins[:green] pin' unless self.pins[:green]
10
+ raise 'missing pins[:blue] pin' unless self.pins[:blue]
11
+
12
+ pins.each do |color, pin|
13
+ set_pin_mode(:out, pin)
14
+ analog_write(Board::LOW, pin)
15
+ end
16
+ end
17
+
18
+ def blue
19
+ analog_write(Board::LOW, pins[:red])
20
+ analog_write(Board::LOW, pins[:green])
21
+ analog_write(Board::HIGH, pins[:blue])
22
+ end
23
+
24
+ def red
25
+ analog_write(Board::HIGH, pins[:red])
26
+ analog_write(Board::LOW, pins[:green])
27
+ analog_write(Board::LOW, pins[:blue])
28
+ end
29
+
30
+ def green
31
+ analog_write(Board::LOW, pins[:red])
32
+ analog_write(Board::HIGH, pins[:green])
33
+ analog_write(Board::LOW, pins[:blue])
34
+ end
35
+
36
+ def blinky
37
+ [:red, :green, :blue].cycle do |color|
38
+ self.send(color)
39
+ sleep(0.01)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,23 @@
1
+ module Dino
2
+ module Components
3
+ class Sensor < BaseComponent
4
+ def initialize(options={})
5
+ super(options)
6
+
7
+ @data_callbacks = []
8
+ @board.add_analog_hardware(self)
9
+ @board.start_read
10
+ end
11
+
12
+ def when_data_received(callback)
13
+ @data_callbacks << callback
14
+ end
15
+
16
+ def update(data)
17
+ @data_callbacks.each do |callback|
18
+ callback.call(data)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ module Dino
2
+ module Components
3
+ class Servo < BaseComponent
4
+ attr_reader :position
5
+
6
+ def initialize(options)
7
+ super(options)
8
+
9
+ set_pin_mode(:out)
10
+ self.position = 0
11
+ end
12
+
13
+ def position=(new_position)
14
+ @position = new_position % 180
15
+ analog_write(@position)
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,29 @@
1
+ module Dino
2
+ module Components
3
+ class Stepper < BaseComponent
4
+
5
+ def initialize(options={})
6
+ super(options)
7
+
8
+ raise 'missing pins[:step] pin' unless self.pins[:step]
9
+ raise 'missing pins[:direction] pin' unless self.pins[:direction]
10
+
11
+ set_pin_mode(:out, pins[:step])
12
+ set_pin_mode(:out, pins[:direction])
13
+ digital_write(Board::LOW, pins[:step])
14
+ end
15
+
16
+ def step_cc
17
+ digital_write(Board::HIGH, self.pins[:direction])
18
+ digital_write(Board::HIGH, self.pins[:step])
19
+ digital_write(Board::LOW, self.pins[:step])
20
+ end
21
+
22
+ def step_cw
23
+ digital_write(Board::LOW, self.pins[:direction])
24
+ digital_write(Board::HIGH, self.pins[:step])
25
+ digital_write(Board::LOW, self.pins[:step])
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,58 @@
1
+ require 'serialport'
2
+ require 'observer'
3
+
4
+ module Dino
5
+ class TxRx
6
+ include Observable
7
+
8
+ BAUD = 115200
9
+
10
+ def initialize
11
+ @first_write = true
12
+ end
13
+
14
+ def io
15
+ @io ||= tty_devices.map do |device|
16
+ next if device.match /^cu/
17
+ begin
18
+ SerialPort.new("/dev/#{device}", BAUD)
19
+ rescue
20
+ nil
21
+ end
22
+ end.compact.first
23
+ end
24
+
25
+ def io=(device)
26
+ @io = SerialPort.new(device, BAUD)
27
+ end
28
+
29
+ def read
30
+ @thread ||= Thread.new do
31
+ loop do
32
+ if IO.select([io], nil, nil, 0.005)
33
+ pin, message = *io.gets.chop.split(/::/)
34
+ pin && message && changed && notify_observers(pin, message)
35
+ end
36
+ sleep 0.004
37
+ end
38
+ end
39
+ end
40
+
41
+ def close_read
42
+ return nil if @thread.nil?
43
+ Thread.kill(@thread)
44
+ @thread = nil
45
+ end
46
+
47
+ def write(message)
48
+ IO.select(nil, [io], nil)
49
+ io.puts(message)
50
+ end
51
+
52
+ private
53
+
54
+ def tty_devices
55
+ `ls /dev | grep usb`.split(/\n/)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module Dino
2
+ VERSION = "0.8"
3
+ end
@@ -0,0 +1,242 @@
1
+ require 'spec_helper'
2
+
3
+ module Dino
4
+ describe Dino::Board do
5
+ def io_mock(methods = {})
6
+ @io ||= mock(:io, {write: nil, add_observer: nil}.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 observe the io' do
19
+ io_mock.should_receive(:add_observer).with(subject)
20
+ subject.send(:initialize, io_mock)
21
+ end
22
+
23
+ it 'should start the heart beat' do
24
+ io_mock.should_receive(:write).with('!0212000.')
25
+ subject.add_digital_hardware(mock(:part, pin: 12))
26
+ sleep 0.01
27
+ end
28
+
29
+ it 'should send clearing bytes to the io' do
30
+ io_mock.should_receive(:write).with("00000000")
31
+ subject
32
+ end
33
+ end
34
+
35
+ describe '#update' do
36
+ context 'when the given pin connects to an analog hardware part' do
37
+ it 'should call update with the message on the part' do
38
+ part = mock(:part, pin: 7)
39
+ subject.add_analog_hardware(part)
40
+ other_part = mock(:part, pin: 9)
41
+ subject.add_analog_hardware(other_part)
42
+
43
+ part.should_receive(:update).with('wake up!')
44
+ subject.update(7, 'wake up!')
45
+ end
46
+ end
47
+
48
+ context 'when the given pin connects to an digital hardware part' do
49
+ it 'should call update with the message on the part' do
50
+ part = mock(:part, pin: 5)
51
+ subject.add_digital_hardware(part)
52
+ other_part = mock(:part, pin: 11)
53
+ subject.add_digital_hardware(other_part)
54
+
55
+ part.should_receive(:update).with('wake up!')
56
+ other_part.should_not_receive(:update).with('wake up!')
57
+
58
+ subject.update(5, 'wake up!')
59
+ end
60
+ end
61
+
62
+ context 'when the given pin is not connected' do
63
+ it 'should not do anything' do
64
+ expect {
65
+ subject.update(5, 'wake up!')
66
+ }.to_not raise_exception
67
+ end
68
+ end
69
+ end
70
+
71
+ describe '#digital_hardware' do
72
+ it 'should initialize as empty' do
73
+ subject.digital_hardware.should == []
74
+ end
75
+ end
76
+
77
+ describe '#analog_hardware' do
78
+ it 'should initialize as empty' do
79
+ subject.analog_hardware.should == []
80
+ end
81
+ end
82
+
83
+ describe '#add_digital_hardware' do
84
+ it 'should add digital hardware to the board' do
85
+ subject.add_digital_hardware(mock1 = mock(:part1, pin: 12))
86
+ subject.add_digital_hardware(mock2 = mock(:part2, pin: 14))
87
+ subject.digital_hardware.should =~ [mock1, mock2]
88
+ end
89
+
90
+ it 'should set the mode for the given pin to "in"' do
91
+ subject
92
+ subject.should_receive(:write).with("0012000")
93
+ subject.add_digital_hardware(mock1 = mock(:part1, pin: 12))
94
+ end
95
+ end
96
+
97
+ describe '#remove_digital_hardware' do
98
+ it 'should remove the given part from the hardware of the board' do
99
+ mock = mock(:part1, pin: 12)
100
+ subject.add_digital_hardware(mock)
101
+ subject.remove_digital_hardware(mock)
102
+ subject.digital_hardware.should == []
103
+ end
104
+ end
105
+
106
+ describe '#add_analog_hardware' do
107
+ it 'should add analog hardware to the board' do
108
+ subject.add_analog_hardware(mock1 = mock(:part1, pin: 12))
109
+ subject.add_analog_hardware(mock2 = mock(:part2, pin: 14))
110
+ subject.analog_hardware.should =~ [mock1, mock2]
111
+ end
112
+
113
+ it 'should set the mode for the given pin to "in"' do
114
+ subject
115
+ subject.should_receive(:write).with("0012000")
116
+ subject.add_analog_hardware(mock1 = mock(:part1, pin: 12))
117
+ end
118
+ end
119
+
120
+ describe '#remove_analog_hardware' do
121
+ it 'should remove the given part from the hardware of the board' do
122
+ mock = mock(:part1, pin: 12)
123
+ subject.add_analog_hardware(mock)
124
+ subject.remove_analog_hardware(mock)
125
+ subject.analog_hardware.should == []
126
+ end
127
+ end
128
+
129
+ describe '#start_read' do
130
+ it 'should tell the io to read' do
131
+ io_mock.should_receive(:read)
132
+ Board.new(io_mock).start_read
133
+ end
134
+ end
135
+
136
+ describe '#stop_read' do
137
+ it 'should tell the io to read' do
138
+ io_mock.should_receive(:close_read)
139
+ Board.new(io_mock).stop_read
140
+ end
141
+ end
142
+
143
+ describe '#write' do
144
+ it 'should return true if the write succeeds' do
145
+ @io = nil
146
+ board = Board.new(io_mock(write: true))
147
+ board.write('message').should == true
148
+ end
149
+
150
+ it 'should wrap the message in a ! and a . by default' do
151
+ io_mock.should_receive(:write).with('!hello.')
152
+ subject.write('hello')
153
+ end
154
+
155
+ it 'should not wrap the message if no_wrap is set to true' do
156
+ board = Board.new(io_mock)
157
+ io_mock.should_receive(:write).with('hello')
158
+ board.write('hello', no_wrap: true)
159
+ end
160
+ end
161
+
162
+ describe '#digital_write' do
163
+ it 'should append a append a write to the pin and value' do
164
+ io_mock.should_receive(:write).with('!0101003.')
165
+ subject.digital_write(01, 003)
166
+ end
167
+ end
168
+
169
+ describe '#digital_read' do
170
+ it 'should tell the board to start reading from the given pin' do
171
+ io_mock.should_receive(:write).with('!0213000.')
172
+ subject.digital_read(13)
173
+ end
174
+ end
175
+
176
+ describe '#analog_write' do
177
+ it 'should append a append a write to the pin and value' do
178
+ io_mock.should_receive(:write).with('!0301003.')
179
+ subject.analog_write(01, 003)
180
+ end
181
+ end
182
+
183
+ describe '#analog_read' do
184
+ it 'should tell the board to start reading from the given pin' do
185
+ io_mock.should_receive(:write).with('!0413000.')
186
+ subject.analog_read(13)
187
+ end
188
+ end
189
+
190
+ describe '#set_pin_mode' do
191
+ it 'should send a value of 1 if the pin mode is set to out' do
192
+ io_mock.should_receive(:write).with('!0013001.')
193
+ subject.set_pin_mode(13, :out)
194
+ end
195
+
196
+ it 'should send a value of 0 if the pin mode is set to in' do
197
+ io_mock.should_receive(:write).with('!0013000.')
198
+ subject.set_pin_mode(13, :in)
199
+ end
200
+ end
201
+
202
+ describe '#set_debug' do
203
+ it 'should set the boards debug on when passed on' do
204
+ io_mock.should_receive(:write).with('!9900001.')
205
+ subject.set_debug(:on)
206
+ end
207
+
208
+ it 'should set the boards debug off when passed off' do
209
+ io_mock.should_receive(:write).with('!9900000.')
210
+ subject.set_debug(:off)
211
+ end
212
+ end
213
+
214
+ describe '#normalize_pin' do
215
+ it 'should normalize numbers so they are two digits' do
216
+ subject.normalize_pin(1).should == '01'
217
+ end
218
+
219
+ it 'should not normalize numbers that are already two digits' do
220
+ subject.normalize_pin(10).should == '10'
221
+ end
222
+
223
+ it 'should raise if a number larger than two digits are given' do
224
+ expect { subject.normalize_pin(1000) }.to raise_exception 'pins can only be two digits'
225
+ end
226
+ end
227
+
228
+ describe '#normalize_value' do
229
+ it 'should normalize numbers so they are three digits' do
230
+ subject.normalize_value(1).should == '001'
231
+ end
232
+
233
+ it 'should not normalize numbers that are already three digits' do
234
+ subject.normalize_value(10).should == '010'
235
+ end
236
+
237
+ it 'should raise if a number larger than three digits are given' do
238
+ expect { subject.normalize_value(1000) }.to raise_exception 'values are limited to three digits'
239
+ end
240
+ end
241
+ end
242
+ end