BBB 0.0.10 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/lib/BBB.rb +13 -17
  2. data/lib/BBB/application.rb +4 -21
  3. data/lib/BBB/circuit.rb +18 -33
  4. data/lib/BBB/components/analog_component.rb +29 -6
  5. data/lib/BBB/components/led.rb +39 -9
  6. data/lib/BBB/components/pinnable.rb +90 -4
  7. data/lib/BBB/components/servo.rb +43 -0
  8. data/lib/BBB/pins/analog_pin.rb +39 -0
  9. data/lib/BBB/pins/digital_pin.rb +106 -0
  10. data/lib/BBB/pins/io/ain.rb +58 -0
  11. data/lib/BBB/pins/io/gpio.rb +77 -0
  12. data/lib/BBB/pins/io/mapped.rb +39 -0
  13. data/lib/BBB/pins/io/pin_mapper.rb +224 -0
  14. data/lib/BBB/pins/io/pwm.rb +61 -0
  15. data/lib/BBB/pins/pinnable.rb +78 -0
  16. data/lib/BBB/pins/pwm_pin.rb +43 -0
  17. data/lib/BBB/version.rb +1 -1
  18. data/spec/application_spec.rb +1 -26
  19. data/spec/circuit_spec.rb +0 -1
  20. data/spec/components/analog_component_spec.rb +36 -0
  21. data/spec/components/led_spec.rb +14 -19
  22. data/spec/components/pinnable_spec.rb +73 -8
  23. data/spec/components/servo_spec.rb +6 -0
  24. data/spec/pins/analog_pin_spec.rb +33 -0
  25. data/spec/pins/digital_input_pin_spec.rb +13 -0
  26. data/spec/pins/digital_output_pin_spec.rb +14 -0
  27. data/spec/pins/digital_pin_spec.rb +66 -0
  28. data/spec/pins/io/mapped_spec.rb +41 -0
  29. data/spec/{board → pins/io}/pin_mapper_spec.rb +2 -2
  30. data/spec/pins/pinnable_spec.rb +68 -0
  31. data/spec/pins/pwm_pin_spec.rb +29 -0
  32. metadata +34 -37
  33. data/lib/BBB/adc/analog_pin.rb +0 -42
  34. data/lib/BBB/adc/setup.rb +0 -20
  35. data/lib/BBB/board/base.rb +0 -45
  36. data/lib/BBB/board/json_pin_mapper.rb +0 -203
  37. data/lib/BBB/board/pin_mapper.rb +0 -20
  38. data/lib/BBB/board/test_board.rb +0 -12
  39. data/lib/BBB/gpio/base.rb +0 -56
  40. data/lib/BBB/gpio/digital_pin.rb +0 -69
  41. data/lib/BBB/gpio/pin_converter.rb +0 -28
  42. data/lib/BBB/io/analog_pin.rb +0 -24
  43. data/lib/BBB/io/digital_pin.rb +0 -67
  44. data/lib/BBB/io/mock_pin.rb +0 -8
  45. data/lib/BBB/io/pinnable.rb +0 -12
  46. data/spec/adc/analog_pin_spec.rb +0 -100
  47. data/spec/adc/setup_spec.rb +0 -9
  48. data/spec/board/board_spec.rb +0 -49
  49. data/spec/gpio/base_spec.rb +0 -48
  50. data/spec/gpio/digital_pin_spec.rb +0 -100
  51. data/spec/gpio/pin_converter_spec.rb +0 -19
  52. data/spec/io/digital_pin_spec.rb +0 -14
  53. data/spec/io/mock_pin_spec.rb +0 -13
  54. data/spec/io/pinnable_spec.rb +0 -13
data/lib/BBB.rb CHANGED
@@ -1,30 +1,26 @@
1
- require "BBB/version"
2
-
3
1
  require "json"
2
+ require "stringio"
4
3
 
5
- require "BBB/board/base"
6
- require "BBB/board/test_board"
7
- require "BBB/board/json_pin_mapper"
8
- require "BBB/board/pin_mapper"
4
+ require "BBB/version"
9
5
 
10
6
  require "BBB/circuit"
11
7
  require "BBB/exceptions"
12
8
 
13
- require "BBB/gpio/base"
14
- require "BBB/gpio/digital_pin"
15
- require "BBB/gpio/pin_converter"
9
+ require "BBB/pins/io/pin_mapper"
10
+ require "BBB/pins/io/mapped"
11
+ require "BBB/pins/io/ain"
12
+ require "BBB/pins/io/gpio"
13
+ require "BBB/pins/io/pwm"
16
14
 
17
- require "BBB/adc/setup"
18
- require "BBB/adc/analog_pin"
19
-
20
- require "BBB/io/pinnable"
21
- require "BBB/io/digital_pin"
22
- require "BBB/io/analog_pin"
23
- require "BBB/io/mock_pin"
15
+ require "BBB/pins/pinnable"
16
+ require "BBB/pins/digital_pin"
17
+ require "BBB/pins/analog_pin"
18
+ require "BBB/pins/pwm_pin"
24
19
 
25
20
  require "BBB/components/pinnable"
26
- require "BBB/components/led"
27
21
  require "BBB/components/analog_component"
22
+ require "BBB/components/led"
23
+ require "BBB/components/servo"
28
24
 
29
25
  require "BBB/application"
30
26
 
@@ -1,42 +1,25 @@
1
1
  module BBB
2
2
  class Application
3
3
 
4
- def self.board(board)
5
- @_board = board
6
- connect unless @_circuit.nil?
7
- end
8
-
9
4
  def self.circuit(circuit)
10
5
  @_circuit = circuit
11
- connect unless @_board.nil?
12
- end
13
-
14
- def self._board
15
- @_board
6
+ define_convenience_methods(circuit)
16
7
  end
17
8
 
18
9
  def self._circuit
19
10
  @_circuit
20
11
  end
21
12
 
22
- def self.connect
23
- @_circuit.components.each_pair do |name, component|
24
- component.pins.each do |pin|
25
- @_board.connect_io_pin(pin)
26
- end
27
-
13
+ def self.define_convenience_methods(c)
14
+ c.components.keys.each do |name|
28
15
  define_method(name) do
29
16
  circuit.send(name)
30
17
  end
31
18
  end
32
19
  end
33
20
 
34
- def board
35
- @board ||= self.class._board
36
- end
37
-
38
21
  def circuit
39
- @circuit ||= self.class._circuit
22
+ self.class._circuit
40
23
  end
41
24
 
42
25
  def start
data/lib/BBB/circuit.rb CHANGED
@@ -1,56 +1,49 @@
1
1
  module BBB
2
2
  ##
3
- # The idea here is to attach a piece of equipment to a circuit. The circuit
4
- # will later be connected to a board.
3
+ # The idea here is to attach a piece of equipment to a circuit.
5
4
  #
6
5
  # A component (e.g. Led or Servo) will define generic pins, like
7
- # DigitalInput or AnalogOutput. And then, when the circuit gets attached to
8
- # the board those pins will be "connected" to their "physical" counterparts
9
- # on the board.
10
- #
11
- # This allows you to develop generic circuits that can be attached to any
12
- # board. At least, in theory :-)
6
+ # DigitalInput or AnalogOutput. And then, when the component gets attached to
7
+ # the circuit those pins will be initialized using the file system.
13
8
  #
14
9
  # For now the attachment will be made onto specific pin numbers. For the BBB
15
10
  # this might for example be :P8_3, however, the plan is to, in a future
16
11
  # release, make sure that there are converters between the different kind of
17
12
  # boards. For example by mapping P8_3 on BBB to P1 on an Arduino.
18
13
  #
19
- # As of now, the act of "attaching" something onto the circuit equals
20
- # setting up a component with generic pins.
21
- #
22
14
  class Circuit
23
- attr_reader :components
15
+ attr_reader :components, :mock
24
16
 
25
17
  def components
26
18
  @components ||= {}
27
19
  end
28
20
 
21
+ def mock?
22
+ @mock == true
23
+ end
24
+
29
25
  ##
30
26
  # Attach a component of a certain type to the circuit
31
27
  #
32
28
  # @param component [Class] The class of the object you # want to attach.
33
29
  # @param opts [Hash] Hash of options that setup the component
34
30
  #
31
+ # @option opts [Symbol] :pin The pin position for the component
35
32
  # @option opts [Array<Symbol>] :pins The list of pin numbers used on the
36
- # circuit.
33
+ # circuit.
34
+ # @options opts [Symbol] :as The name of the component
37
35
  #
38
36
  def attach(component, opts={})
39
- if component.kind_of?(Class)
40
- component = component.new
41
- end
37
+ name = opts.delete(:as)
38
+ component = component.new if component.kind_of?(Class)
39
+ pin_positions = opts.delete(:pins) || [opts.delete(:pin)]
40
+ pin_options = {:mock=>self.mock?}.merge!(opts)
42
41
 
43
- if pin_positions = opts[:pins] || [opts[:pin]]
44
- component_pins = component.pins
45
- verify_pin_argument_count(component_pins.count, pin_positions.count)
46
- component.register_pin_positions(pin_positions)
47
- end
48
-
49
- name = opts.fetch(:as)
50
- register_component(component, name)
42
+ component.initialize_pins(pin_positions, pin_options)
43
+ define_method_for_component(component, name)
51
44
  end
52
45
 
53
- def register_component(component, name)
46
+ def define_method_for_component(component, name)
54
47
  components[name] = component
55
48
  eigenclass = class << self; self; end
56
49
  eigenclass.class_eval do
@@ -60,13 +53,5 @@ module BBB
60
53
  end
61
54
  end
62
55
 
63
- def verify_pin_argument_count(type_count, position_count)
64
- if type_count != position_count
65
- raise PinsDoNotMatchException,
66
- "#{object.to_s} requires #{types_count} but received #{position_count} pin arguments."
67
- end
68
- end
69
-
70
-
71
56
  end
72
57
  end
@@ -1,22 +1,45 @@
1
1
  module BBB
2
2
  module Components
3
+ ##
4
+ # An AnalogComponent is a component that reads from an analog input (AIN) on
5
+ # the board. You can use a generic analog component for, for example,
6
+ # temperature or light sensors.
7
+ #
8
+ # The BeagleBoneBlack has 12 bit (4096) AIN pins. So the expected value of
9
+ # an analog pin is between 0 and 4096.
10
+ #
3
11
  class AnalogComponent
4
12
  include Pinnable
5
13
 
6
- attr_reader :pin, :pins
7
-
8
- def initialize
9
- @pin = BBB::IO::AnalogPin.new
10
- @pins = [@pin]
11
- end
14
+ uses BBB::Pins::AnalogPin
12
15
 
16
+ ##
17
+ # Read from an initialized pin, if the pins have not been initialized yet,
18
+ # this method might actually raise an exception.
19
+ #
20
+ # @raise MethodNotFoundException
21
+ #
22
+ # @return Integer
23
+ #
13
24
  def read
14
25
  pin.read
15
26
  end
16
27
 
28
+ ##
29
+ # @see #read
30
+ #
17
31
  def value
18
32
  read
19
33
  end
34
+
35
+ ##
36
+ # Convenience method to grab the first pin in the pins array
37
+ #
38
+ # @return BBB::Pins::AnalogPin
39
+ #
40
+ def pin
41
+ pins.first
42
+ end
20
43
  end
21
44
  end
22
45
  end
@@ -1,31 +1,61 @@
1
1
  module BBB
2
2
  module Components
3
+ ##
4
+ # The LED class is the component interface into a digital pin. In a way it's
5
+ # nothing more than a straight forward port of a digital pin. You can use a
6
+ # led component when you want to use digital pins, or simply define your own
7
+ # class and extend it from the LED.
8
+ #
9
+ # The Led class does not perform any sort of caching or smart calls, it
10
+ # forwards everything to the pin. In your own applications you might want to
11
+ # tune this behavior by adding some kind of caching.
12
+ #
3
13
  class Led
4
14
  include Pinnable
5
- attr_reader :state, :pin
6
15
 
7
- def initialize
8
- @state = :low
9
- @pin = BBB::IO::DigitalPin.new(:output)
10
- @pins = [@pin]
16
+ uses BBB::Pins::DigitalOutputPin
17
+
18
+ ##
19
+ # Convenience method to grab the first pin in the pins array
20
+ #
21
+ # @return BBB::Pins::DigitalOutputPin
22
+ #
23
+ def pin
24
+ pins.first
11
25
  end
12
26
 
27
+ ##
28
+ # Turns on the LED
29
+ # @return void
30
+ #
13
31
  def on!
14
32
  pin.on!
15
- @state = :high
16
33
  end
17
34
 
35
+ ##
36
+ # Turns off the LED
37
+ # @return void
38
+ #
18
39
  def off!
19
40
  pin.off!
20
- @state = :low
21
41
  end
22
42
 
43
+ ##
44
+ # Checks if the LED is turned on.
45
+ #
46
+ # @return Boolean
47
+ #
23
48
  def on?
24
- state == :high
49
+ pin.on?
25
50
  end
26
51
 
52
+ ##
53
+ # Checks if the LED is turned off.
54
+ #
55
+ # @return Boolean
56
+ #
27
57
  def off?
28
- state == :low
58
+ pin.off?
29
59
  end
30
60
 
31
61
  end
@@ -3,13 +3,99 @@ module BBB
3
3
  module Pinnable
4
4
  attr_reader :pins
5
5
 
6
- def register_pin_positions(*positions)
7
- positions.flatten!
8
- pins.each_with_index do |pin, index|
9
- pin.position=positions[index]
6
+ module ClassMethods
7
+ ##
8
+ # Register the use of classes of pins to a class. These classes will be
9
+ # initialized upon #initialize_pins
10
+ #
11
+ # @param pin_classes [Array<Class>] the classes to register on class
12
+ # level.
13
+ #
14
+ def uses(*pin_classes)
15
+ pins.concat(pin_classes)
10
16
  end
17
+
18
+ ##
19
+ # Attribute reader to the class level @pins
20
+ #
21
+ # @return Array<Class>
22
+ #
23
+ def pins
24
+ @pins ||= []
25
+ end
26
+ end
27
+
28
+ def self.included(base)
29
+ base.extend(ClassMethods)
11
30
  end
12
31
 
32
+ ##
33
+ # Initialize the pin classes with their positions and options. Turning
34
+ # them from their Classes into working pin instances.
35
+ #
36
+ # The argument list of the methods is a bit odd. Since it's not
37
+ # possible to have both a splat and an option array as arguments, the
38
+ # method signature only shows a splat of positions. The options are then
39
+ # taken out of the positions, if the last position is actually a Hash as
40
+ # opposed to a Symbol. If the last element of the positions list is not
41
+ # a Hash, the options are set to an empty hash.
42
+ #
43
+ # @param positions [Array<Symbol>] positions the pins should be
44
+ # initialized with.
45
+ # @param opts [Hash] Options to pass along to the pins during
46
+ # initialization.
47
+ #
48
+ # @return Array[Pins]
49
+ #
50
+ def initialize_pins(*positions)
51
+ opts = positions.last.kind_of?(Hash) ? positions.pop : {}
52
+
53
+ verify_pin_position_count(positions)
54
+
55
+ @pins = []
56
+ self.class.pins.each_with_index do |pin, index|
57
+ @pins << pin.new(positions[index], opts)
58
+ end
59
+ after_pin_initialization
60
+ end
61
+
62
+ ##
63
+ # Verifies if the number of pins registered in the @pins array match with
64
+ # the number of pins provided as an argument to the method. This function
65
+ # normally gets called as part of the initialize pins method to verify if
66
+ # the positions given to the initialize_pins method matches the number of
67
+ # registered pins.
68
+ #
69
+ # @param positions [Array<Symbol>] The array of positions
70
+ #
71
+ # @raise [PinsDoNotMatchException] If the pin counts between the positions
72
+ # provided as an argument and the pins in the pins array do not match,
73
+ # this exception gets raised, to prevent hard to debug situations later
74
+ # on in the lifecycle of an application.
75
+ #
76
+ # @return Void
77
+ def verify_pin_position_count(positions)
78
+ if self.class.pins.count != positions.count
79
+ raise PinsDoNotMatchException,
80
+ "#{self.class.to_s} requires #{self.class.pins.count} but received #{positions.count} pin position."
81
+ end
82
+ end
83
+
84
+ ##
85
+ # Method which classes can overwrite to hook into the after pin
86
+ # initialization
87
+ #
88
+ def after_pin_initialization
89
+ end
90
+
91
+ ##
92
+ # Method that is used in the test suite to test if the pinnable module is
93
+ # included in an object
94
+ #
95
+ # @return true
96
+ def pinnable?
97
+ true
98
+ end
13
99
  end
14
100
  end
15
101
  end
@@ -0,0 +1,43 @@
1
+ module BBB
2
+ module Components
3
+ class Servo
4
+ include Pinnable
5
+ #uses Pins::PWMPin
6
+ attr_reader :min_duty, :max_duty, :period
7
+
8
+ def initialize(period=17e6, min_duty=14.6e6, max_duty=16.6e6)
9
+ @period = period
10
+ @min_duty = min_duty
11
+ @max_duty = max_duty
12
+ end
13
+
14
+ def after_pin_initialization
15
+ pin.period = 17e6
16
+ pin.duty = (min_duty + duty_range / 2)
17
+ pin.run = 0
18
+ end
19
+
20
+ def angle(degrees)
21
+ value = degrees / 180.to_f * duty_range + min_duty
22
+ pin.duty = value
23
+ end
24
+
25
+ def activate!
26
+ pin.run = 1
27
+ end
28
+
29
+ def deactivate!
30
+ pin.run = 0
31
+ end
32
+
33
+ def pin
34
+ pins.first
35
+ end
36
+
37
+ def duty_range
38
+ max_duty - min_duty
39
+ end
40
+
41
+ end
42
+ end
43
+ end