dino 0.8

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.
@@ -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