object_oriented_beaglebone_black 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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +8 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +113 -0
  8. data/Rakefile +7 -0
  9. data/config/environments/development.yml +3 -0
  10. data/config/environments/production.yml +3 -0
  11. data/config/environments/test.yml +3 -0
  12. data/config/i2c.json +26 -0
  13. data/config/pin_index.json +1519 -0
  14. data/config/uarts.json +31 -0
  15. data/examples/current_measurement.rb +7 -0
  16. data/examples/current_measurement/current_input.rb +16 -0
  17. data/examples/voltage_measurement.rb +7 -0
  18. data/examples/voltage_measurement/voltage_input.rb +16 -0
  19. data/lib/object_oriented_beaglebone_black.rb +26 -0
  20. data/lib/object_oriented_beaglebone_black/analog_input.rb +43 -0
  21. data/lib/object_oriented_beaglebone_black/gpio.rb +40 -0
  22. data/lib/object_oriented_beaglebone_black/io.rb +34 -0
  23. data/lib/object_oriented_beaglebone_black/io/direction.rb +10 -0
  24. data/lib/object_oriented_beaglebone_black/io/value.rb +10 -0
  25. data/lib/object_oriented_beaglebone_black/led.rb +43 -0
  26. data/lib/object_oriented_beaglebone_black/pin_mappings.rb +25 -0
  27. data/lib/object_oriented_beaglebone_black/pwm.rb +58 -0
  28. data/lib/object_oriented_beaglebone_black/version.rb +3 -0
  29. data/object_orieted_beaglebone_black.gemspec +27 -0
  30. data/spec/examples/current_measurement/current_input_spec.rb +46 -0
  31. data/spec/examples/voltage_measurement/voltage_input_spec.rb +46 -0
  32. data/spec/object_oriented_beaglebone_black/analog_input_spec.rb +49 -0
  33. data/spec/object_oriented_beaglebone_black/gpio_spec.rb +66 -0
  34. data/spec/object_oriented_beaglebone_black/led_spec.rb +29 -0
  35. data/spec/object_oriented_beaglebone_black/pin_mappings_spec.rb +35 -0
  36. data/spec/object_oriented_beaglebone_black/pwm_spec.rb +57 -0
  37. data/spec/spec_helper.rb +13 -0
  38. data/spec/support/analog_input_file_behavoir_helper.rb +34 -0
  39. data/spec/support/gpio_file_behavior_helper.rb +36 -0
  40. data/spec/support/pwm_file_behavior_helper.rb +23 -0
  41. metadata +138 -0
data/config/uarts.json ADDED
@@ -0,0 +1,31 @@
1
+ // Based on https://github.com/jadonk/bonescript/blob/master/src/bone.js
2
+ // The content is copied from there and key uarts" is added.
3
+ // The idea of adding that key to make the JSON structure in this file is coming from
4
+ // https://github.com/Sparkboxx/bbb/blob/master/resources/pin_mappings.json
5
+ { "uarts" : {
6
+ "/dev/ttyO0": {
7
+ },
8
+ "/dev/ttyO1": {
9
+ "devicetree": "BB-UART1",
10
+ "rx": "P9_26",
11
+ "tx": "P9_24"
12
+ },
13
+ "/dev/ttyO2": {
14
+ "devicetree": "BB-UART2",
15
+ "rx": "P9_22",
16
+ "tx": "P9_21"
17
+ },
18
+ "/dev/ttyO3": {
19
+ },
20
+ "/dev/ttyO4": {
21
+ "devicetree": "BB-UART4",
22
+ "rx": "P9_11",
23
+ "tx": "P9_13"
24
+ },
25
+ "/dev/ttyO5": {
26
+ "devicetree": "BB-UART5",
27
+ "rx": "P8_38",
28
+ "tx": "P8_37"
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,7 @@
1
+ require 'object_oriented_beaglebone_black'
2
+
3
+ require 'current_measurement/current_input'
4
+
5
+ module CurrentMeasurement
6
+ # Your code goes here...
7
+ end
@@ -0,0 +1,16 @@
1
+ require 'bigdecimal'
2
+
3
+ module CurrentMeasurement
4
+ class CurrentInput
5
+
6
+ def initialize(pin_key)
7
+ @analog_input = ObjectOrientedBeagleboneBlack::AnalogInput.new(pin_key)
8
+ end
9
+
10
+ def value
11
+ # Conversion for ACS712 Breakout. If a different current measurement device is used, extract this code to subclass and make this class parent class.
12
+ (@analog_input.raw_value / BigDecimal("0.185")).to_f
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ require 'object_oriented_beaglebone_black'
2
+
3
+ require 'voltage_measurement/voltage_input'
4
+
5
+ module VoltageMeasurement
6
+ # Your code goes here...
7
+ end
@@ -0,0 +1,16 @@
1
+ require 'bigdecimal'
2
+
3
+ module VoltageMeasurement
4
+ class VoltageInput
5
+
6
+ def initialize(pin_key)
7
+ @analog_input = ObjectOrientedBeagleboneBlack::AnalogInput.new(pin_key)
8
+ end
9
+
10
+ def value
11
+ # For voltage divider 11:1, e.g. 51[kΩ] and 5.1[kΩ]. If another voltage divider is added, extract this code to subclass and make this class parent class.
12
+ (@analog_input.raw_value * BigDecimal("11")).to_f
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ require "object_oriented_beaglebone_black/version"
2
+ require "erb"
3
+
4
+ OBJECT_ORIENTED_BEAGLEBONE_BLACK_ROOT = File.expand_path('..', __dir__)
5
+
6
+ require 'yaml'
7
+ # require 'active_support/core_ext/hash/keys'
8
+
9
+ ENV["OBJECT_ORIENTED_BEAGLEBONE_BLACK_ENV"] ||= 'development'
10
+ OBJECT_ORIENTED_BEAGLEBONE_BLACK_CONFIG = YAML.load(ERB.new(File.read(File.join(OBJECT_ORIENTED_BEAGLEBONE_BLACK_ROOT, "config", "environments", "#{ENV["OBJECT_ORIENTED_BEAGLEBONE_BLACK_ENV"]}.yml"))).result)
11
+ # YAML.load_file(File.join(OBJECT_ORIENTED_BEAGLEBONE_BLACK_ROOT, "config", "environments", "#{ENV["OBJECT_ORIENTED_BEAGLEBONE_BLACK_ENV"]}.yml"))
12
+ # In order not to use activesupport (since Beaglebone Black that is used currently didn't have Internet access to download it), Hash#deep_symbolize_keys! is not used.
13
+ # OBJECT_ORIENTED_BEAGLEBONE_BLACK_CONFIG.deep_symbolize_keys!
14
+
15
+ require 'object_oriented_beaglebone_black/pin_mappings'
16
+ require 'object_oriented_beaglebone_black/io'
17
+ require 'object_oriented_beaglebone_black/io/direction'
18
+ require 'object_oriented_beaglebone_black/io/value'
19
+ require 'object_oriented_beaglebone_black/gpio'
20
+ require 'object_oriented_beaglebone_black/led'
21
+ require 'object_oriented_beaglebone_black/pwm'
22
+ require 'object_oriented_beaglebone_black/analog_input'
23
+
24
+ module ObjectOrientedBeagleboneBlack
25
+ # Your code goes here...
26
+ end
@@ -0,0 +1,43 @@
1
+ require 'bigdecimal'
2
+
3
+ module ObjectOrientedBeagleboneBlack
4
+ class AnalogInput
5
+ include ObjectOrientedBeagleboneBlack::PinMappings
6
+
7
+ def initialize(pin_key)
8
+ @pin_key = pin_key
9
+ @slots_file_path = File.join(File.join(OBJECT_ORIENTED_BEAGLEBONE_BLACK_CONFIG["slots_directory"], "slots"))
10
+
11
+ activate_device_tree_overlays
12
+ end
13
+
14
+ def activate_device_tree_overlays
15
+ # Note: Since slots file acts as an interface to activate Device Tree Overlay, simply writing to it does what needs to be done.
16
+ # I'm using appending here so that testing in a local environment becomes straightfoward.
17
+ File.open(@slots_file_path, "a") { |file| file.write("cape-bone-iio") }
18
+ end
19
+
20
+ def raw_value
21
+ internal_raw_value = nil
22
+ File.open(File.join(analog_input_directory, pin_name(@pin_key)), "r") { |file| internal_raw_value = file.read.strip }
23
+ raw_value = (BigDecimal(internal_raw_value.to_s) / BigDecimal("1000")).to_f
24
+ raw_value
25
+ end
26
+
27
+ def value
28
+ # The raw_value is in the range of 0 to 1.8[V].
29
+ # The value is in the range of 0 to 1.0.
30
+ (BigDecimal(raw_value.to_s) * (BigDecimal("1.0") / BigDecimal("1.8"))).to_f
31
+ end
32
+
33
+ private
34
+ def pin_name(pin_key)
35
+ property_hash(key: pin_key)["name"]
36
+ end
37
+
38
+ def analog_input_directory
39
+ Dir["#{File.join(OBJECT_ORIENTED_BEAGLEBONE_BLACK_CONFIG["device_directory"], "helper.")}*"].first
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,40 @@
1
+ module ObjectOrientedBeagleboneBlack
2
+ class Gpio
3
+
4
+ def initialize(pin_number)
5
+ @pin_number = pin_number
6
+ @gpio_directory = File.join(OBJECT_ORIENTED_BEAGLEBONE_BLACK_CONFIG["io_root_directory"], "gpio")
7
+ end
8
+
9
+ def export
10
+ File.open(File.join(@gpio_directory, "export"), "w") { |file| file.write(@pin_number) }
11
+ end
12
+
13
+ def unexport
14
+ File.open(File.join(@gpio_directory, "unexport"), "w") { |file| file.write(@pin_number) }
15
+ end
16
+
17
+ def direction=(direction)
18
+ File.open(File.join(@gpio_directory, "gpio#{@pin_number}", "direction"), "w") { |file| file.write(direction) }
19
+ end
20
+
21
+ def direction
22
+ # Using this instead of simple "File.open(file_path).read" in order to close file after reading.
23
+ direction = nil
24
+ File.open(File.join(@gpio_directory, "gpio#{@pin_number}", "direction"), "r") { |file| direction = file.read.strip }
25
+ direction
26
+ end
27
+
28
+ def value=(value)
29
+ File.open(File.join(@gpio_directory, "gpio#{@pin_number}", "value"), "w") { |file| file.write(value) }
30
+ end
31
+
32
+ def value
33
+ # Using this instead of simple "File.open(file_path).read" in order to close file after reading.
34
+ value = nil
35
+ File.open(File.join(@gpio_directory, "gpio#{@pin_number}", "value"), "r") { |file| value = file.read.strip.to_i }
36
+ value
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,34 @@
1
+ require 'fileutils'
2
+
3
+ module ObjectOrientedBeagleboneBlack
4
+ module IO
5
+
6
+ def file_directory_path
7
+ raise "#{__method__} method must be implemented in the class including this module"
8
+ end
9
+
10
+ def write_to_io_file(filename, value)
11
+ FileUtils.mkdir_p(file_directory_path, mode: 0700) unless Dir.exists?(file_directory_path)
12
+ file_path = File.join(file_directory_path, filename)
13
+
14
+ File.open(file_path, "w") do |file|
15
+ file.write(value)
16
+ end
17
+ end
18
+
19
+ def read_from_io_file(filename)
20
+ file_path = File.join(file_directory_path, filename)
21
+
22
+ if File.exists?(file_path)
23
+ file_content = nil
24
+ # Using this instead of simple "File.open(file_path).read" in order to close file after reading.
25
+ File.open(file_path) do |file|
26
+ file_content = file.read.strip
27
+ end
28
+ file_content
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ module ObjectOrientedBeagleboneBlack
2
+ module IO
3
+ module Direction
4
+
5
+ IN = "in"
6
+ OUT = "out"
7
+
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module ObjectOrientedBeagleboneBlack
2
+ module IO
3
+ module Value
4
+
5
+ HIGH = 1
6
+ LOW = 0
7
+
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,43 @@
1
+ module ObjectOrientedBeagleboneBlack
2
+ class Led
3
+ include ObjectOrientedBeagleboneBlack::PinMappings
4
+ include ObjectOrientedBeagleboneBlack::IO
5
+
6
+ LED_RELATIVE_DIRECTORY_PATTERN = "leds/beaglebone:green:%s"
7
+ TRIGGER_FILENAME = "trigger"
8
+ GPIO_FILENAME = "brightness"
9
+
10
+ def initialize(led_name)
11
+ @led_name = led_name
12
+ end
13
+
14
+ def pin_mode=(pin_mode)
15
+ case pin_mode
16
+ when "out"
17
+ write_to_io_file(TRIGGER_FILENAME, "gpio")
18
+ else
19
+ raise "Invalid pin_mode for Led: #{pin_mode}. Must be 'out'"
20
+ end
21
+ end
22
+
23
+ def digital_write(state)
24
+ write_to_io_file(GPIO_FILENAME, state)
25
+ end
26
+
27
+ def state
28
+ state = read_from_io_file(GPIO_FILENAME)
29
+ begin
30
+ state.to_i
31
+ rescue
32
+ state
33
+ end
34
+ end
35
+
36
+ private
37
+ def file_directory_path
38
+ internal_led_name = property_hash(name: @led_name)["led"]
39
+ File.expand_path(File.join(OBJECT_ORIENTED_BEAGLEBONE_BLACK_CONFIG["io_root_directory"], sprintf(LED_RELATIVE_DIRECTORY_PATTERN, internal_led_name)))
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,25 @@
1
+ require 'json'
2
+ # require 'active_support/core_ext/hash/keys'
3
+
4
+ module ObjectOrientedBeagleboneBlack
5
+ module PinMappings
6
+
7
+ def load_pin_index_array
8
+ # In order not to use activesupport (since Beaglebone Black that is used currently doesn't have Internet access to download it), Hash#deep_symbolize_keys! is not used.
9
+ # ::OBJECT_ORIENTED_BEAGLEBONE_BLACK_PIN_INDEX_ARRAY ||= JSON.load(File.read(File.join(OBJECT_ORIENTED_BEAGLEBONE_BLACK_ROOT, "config", "pin_index.json")))["pinIndex"].each { |property_hash| property_hash.deep_symbolize_keys! }
10
+ ::OBJECT_ORIENTED_BEAGLEBONE_BLACK_PIN_INDEX_ARRAY ||= JSON.load(File.read(File.join(OBJECT_ORIENTED_BEAGLEBONE_BLACK_ROOT, "config", "pin_index.json")))["pinIndex"]
11
+ end
12
+
13
+ def property_hash(name: nil, key: nil)
14
+ load_pin_index_array
15
+
16
+ if !name.nil?
17
+ ::OBJECT_ORIENTED_BEAGLEBONE_BLACK_PIN_INDEX_ARRAY.select { |property_hash| property_hash["name"] == name }.first
18
+ elsif !key.nil?
19
+ ::OBJECT_ORIENTED_BEAGLEBONE_BLACK_PIN_INDEX_ARRAY.select { |property_hash| property_hash["key"] == key }.first
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,58 @@
1
+ require 'bigdecimal'
2
+
3
+ module ObjectOrientedBeagleboneBlack
4
+ class Pwm
5
+
6
+ module Polarity
7
+ DIRECT = 0
8
+ INVERSE = 1
9
+ end
10
+
11
+ DUTY_VALUE_PER_ONE_HUNDREDTH = BigDecimal("5000")
12
+
13
+ def initialize(pin_key)
14
+ @pin_key = pin_key
15
+ @slots_file_path = File.join(File.join(OBJECT_ORIENTED_BEAGLEBONE_BLACK_CONFIG["slots_directory"], "slots"))
16
+
17
+ activate_device_tree_overlays
18
+ end
19
+
20
+ def activate_device_tree_overlays
21
+ # Note: Since slots file acts as an interface to activate Device Tree Overlay, simply writing to it does what needs to be done.
22
+ # I'm using appending here so that testing in a local environment becomes straightfoward.
23
+ File.open(@slots_file_path, "a") { |file| file.write("am33xx_pwm") }
24
+ File.open(@slots_file_path, "a") { |file| file.write("bone_pwm_#{@pin_key}") }
25
+ end
26
+
27
+ # duty_cycle (value between 0 and 1)
28
+ def duty_cycle=(duty_cycle)
29
+ self.polarity = ObjectOrientedBeagleboneBlack::Pwm::Polarity::DIRECT
30
+ internal_duty_value = (BigDecimal(duty_cycle.to_s) * BigDecimal("100") * DUTY_VALUE_PER_ONE_HUNDREDTH).to_i
31
+ File.open(File.join(pwm_directory, "duty"), "w") { |file| file.write(internal_duty_value) }
32
+ end
33
+
34
+ def duty_cycle
35
+ # Using this instead of simple "File.open(file_path).read" in order to close file after reading.
36
+ internal_duty_value = nil
37
+ File.open(File.join(pwm_directory, "duty"), "r") { |file| internal_duty_value = file.read.strip }
38
+ duty_cycle = (BigDecimal(internal_duty_value.to_s) / DUTY_VALUE_PER_ONE_HUNDREDTH / BigDecimal("100")).to_f
39
+ duty_cycle
40
+ end
41
+
42
+ def polarity=(polarity)
43
+ File.open(File.join(pwm_directory, "polarity"), "w") { |file| file.write(polarity) }
44
+ end
45
+
46
+ def polarity
47
+ internal_polarity_value = nil
48
+ File.open(File.join(pwm_directory, "polarity"), "r") { |file| internal_polarity_value = file.read.strip.to_i }
49
+ internal_polarity_value
50
+ end
51
+
52
+ private
53
+ def pwm_directory
54
+ Dir["#{File.join(OBJECT_ORIENTED_BEAGLEBONE_BLACK_CONFIG["device_directory"], "pwm_test_#{@pin_key}.")}*"].first
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module ObjectOrientedBeagleboneBlack
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'object_oriented_beaglebone_black/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "object_oriented_beaglebone_black"
8
+ spec.version = ObjectOrientedBeagleboneBlack::VERSION
9
+ spec.authors = ["Tadatoshi Takahashi"]
10
+ spec.email = ["tadatoshi@gmail.com"]
11
+ spec.summary = %q{For using BeagleBone Black in Object-Oriented way through Ruby.}
12
+ spec.description = %q{Performs accessing GPIO, etc. in Object-Oriented way on BeagleBone Black through Ruby.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = '>= 2.1.2'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib", "examples"]
21
+
22
+ # spec.add_dependency "activesupport"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.6"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec"
27
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+ require 'current_measurement'
3
+ require 'bigdecimal'
4
+
5
+ describe "Current measurement by ACS712 Breakout", analog_input: true do
6
+
7
+ before(:each) do
8
+
9
+ @slots_directory = OBJECT_ORIENTED_BEAGLEBONE_BLACK_CONFIG["slots_directory"]
10
+ @device_directory = OBJECT_ORIENTED_BEAGLEBONE_BLACK_CONFIG["device_directory"]
11
+
12
+ # In order to run this spec example in the real environment, the directories and files that already exist there are not created in that case.
13
+ if ENV["OBJECT_ORIENTED_BEAGLEBONE_BLACK_ENV"] == 'test'
14
+ FileUtils.mkdir_p(@slots_directory, mode: 0700) unless Dir.exists?(@slots_directory)
15
+ FileUtils.touch(File.join(@slots_directory, "slots"))
16
+ File.chmod(0700, File.join(@slots_directory, "slots"))
17
+
18
+ FileUtils.mkdir_p(@device_directory, mode: 0700) unless Dir.exists?(@device_directory)
19
+ end
20
+ end
21
+
22
+ after(:each) do
23
+ if ENV["OBJECT_ORIENTED_BEAGLEBONE_BLACK_ENV"] == 'test'
24
+ File.open(File.join(@slots_directory, "slots"), 'w') {|file| file.truncate(0) }
25
+ end
26
+ end
27
+
28
+ it "should calculated the measured current" do
29
+
30
+ pin_key = "P9_40"
31
+ expected_current = BigDecimal("10").to_f
32
+ expected_raw_value = (BigDecimal(expected_current.to_s) * BigDecimal("0.185")).to_f
33
+
34
+ current_input = CurrentMeasurement::CurrentInput.new(pin_key)
35
+
36
+ # Since the real "slots" file creates a directory structure when a device tree overlay is written to it,
37
+ # in the "test" environment with a regular file, it is mimiced here.
38
+ mimic_internal_analog_input_directory_creation(pin_key, expected_raw_value) if ENV["OBJECT_ORIENTED_BEAGLEBONE_BLACK_ENV"] == 'test'
39
+
40
+ expect(Dir.exists?(Dir["#{File.join(OBJECT_ORIENTED_BEAGLEBONE_BLACK_CONFIG["device_directory"], "helper.")}*"].first)).to be true
41
+
42
+ expect(current_input.value).to eq(expected_current)
43
+
44
+ end
45
+
46
+ end