-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Change gem structure #3
base: dev
Are you sure you want to change the base?
Changes from all commits
6fb566d
1cce4f8
a752369
f87b293
79a768d
9f510dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
language: ruby | ||
cache: bundler | ||
rvm: | ||
- 1.9.3 | ||
- 2.1.0 | ||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,15 @@ | ||
require "pi_piper/bcm2835/version" | ||
require 'pi_piper/bcm2835/version' | ||
require 'pi_piper/bcm2835/pin' | ||
require 'pi_piper/bcm2835/spi' | ||
require 'pi_piper/bcm2835/i2c' | ||
require 'pi_piper/bcm2835/driver' | ||
|
||
module PiPiper | ||
autoload PiPiper::Bcm2835, "pi_piper/bcm2835/bcm2835" | ||
module Bcm2835 | ||
class << self | ||
def driver | ||
@driver ||= PiPiper::Bcm2835::Driver.new | ||
end | ||
end | ||
end | ||
end |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
require 'ffi' | ||
require 'pry' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not useful in production, could be added for dev There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. absolutely, it was just a placeholder since this PR was a work in progress. |
||
|
||
module PiPiper | ||
module Bcm2835 | ||
# The Bcm2835 module is not intended to be directly called. | ||
# It serves as an FFI library for PiPiper::SPI and PiPiper::I2C | ||
class Driver | ||
include PiPiper::Bcm2835::Pin | ||
include PiPiper::Bcm2835::SPI | ||
include PiPiper::Bcm2835::I2C | ||
include FFI::Library | ||
|
||
def initialize | ||
ffi_lib File.expand_path('../../../../bin/libbcm2835.so', __FILE__) | ||
setup_gpio | ||
setup_pwm | ||
setup_spi | ||
setup_i2c | ||
end | ||
|
||
def setup_gpio | ||
attach_function :init, :bcm2835_init, [], :uint8 | ||
attach_function :close, :bcm2835_close, [], :uint8 | ||
|
||
# Sets the Function Select register for the given pin, which configures the | ||
# pin as Input, Output or one of the 6 alternate functions. | ||
attach_function :gpio_select_function, :bcm2835_gpio_fsel, [:uint8, :uint8], :void | ||
# attach_function :gpio_set, :bcm2835_gpio_set, [:uint8], :void | ||
# attach_function :gpio_clear, :bcm2835_gpio_clr, [:uint8], :void | ||
# attach_function :gpio_level, :bcm2835_gpio_lev, [:uint8], :uint8 | ||
|
||
# pin support... | ||
attach_function :pin_set_pud, :bcm2835_gpio_set_pud, [:uint8, :uint8], :void | ||
end | ||
|
||
def setup_pwm | ||
# PWM support... | ||
attach_function :pwm_clock, :bcm2835_pwm_set_clock, [:uint32], :void | ||
attach_function :pwm_mode, :bcm2835_pwm_set_mode, [:uint8, :uint8, :uint8], :void | ||
attach_function :pwm_range, :bcm2835_pwm_set_range, [:uint8, :uint32], :void | ||
attach_function :pwm_data, :bcm2835_pwm_set_data, [:uint8, :uint32], :void | ||
end | ||
|
||
|
||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
require 'ffi' | ||
require 'pi_piper/frequency' | ||
|
||
module PiPiper | ||
module Bcm2835 | ||
module I2C | ||
I2C_REASON_OK = 0 # Success | ||
I2C_REASON_ERROR_NACK = 1 # Received a NACK | ||
I2C_REASON_ERROR_CLKT = 2 # Received Clock Stretch Timeout | ||
I2C_REASON_ERROR_DATA = 3 # Not all data is sent / received | ||
|
||
def setup_i2c | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll prefer the BTW even without your workaround with attach_function I can have very good coverage (for now 270 / 289 LOC (93.43%)) |
||
attach_function :i2c_begin, :bcm2835_i2c_begin, [], :void | ||
attach_function :i2c_end, :bcm2835_i2c_end, [], :void | ||
attach_function :i2c_write, :bcm2835_i2c_write, [:pointer, :uint], :uint8 | ||
attach_function :i2c_set_address,:bcm2835_i2c_setSlaveAddress, [:uint8], :void | ||
attach_function :i2c_set_clock_divider, :bcm2835_i2c_setClockDivider, [:uint16], :void | ||
attach_function :i2c_read, :bcm2835_i2c_read, [:pointer, :uint], :uint8 | ||
end | ||
|
||
def i2c_allowed_clocks | ||
[100.kilohertz, | ||
399.3610.kilohertz, | ||
1.666.megahertz, | ||
1.689.megahertz] | ||
end | ||
|
||
def i2c_transfer_bytes(data) | ||
data_out = FFI::MemoryPointer.new(data.count) | ||
(0..data.count - 1).each{ |i| data_out.put_uint8(i, data[i]) } | ||
i2c_write(data_out, data.count) | ||
end | ||
|
||
def i2c_read_bytes(bytes) | ||
data_in = FFI::MemoryPointer.new(bytes) | ||
i2c_read(data_in, bytes) #TODO reason codes | ||
|
||
(0..bytes - 1).map { |i| data_in.get_uint8(i) } | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
require 'set' | ||
|
||
module PiPiper | ||
module Bcm2835 | ||
module Pin | ||
def pins | ||
@pins ||= Set.new | ||
end | ||
|
||
def pin_input(pin) | ||
export(pin) | ||
pin_direction(pin, 'in') | ||
end | ||
|
||
def pin_set(pin, value) | ||
File.write("/sys/class/gpio/gpio#{pin}/value", value) | ||
end | ||
|
||
def pin_output(pin) | ||
export(pin) | ||
pin_direction(pin, 'out') | ||
end | ||
|
||
def pin_read(pin) | ||
raise ArgumentError, "Pin #{pin} is not exported" if unexported?(pin) | ||
File.read("/sys/class/gpio/gpio#{pin}/value").to_i | ||
end | ||
|
||
def unexport(pin) | ||
raise ArgumentError, "Pin #{pin} not exported" if unexported?(pin) | ||
File.write('/sys/class/gpio/unexport', pin) | ||
pins.delete(pin) | ||
end | ||
|
||
def unexport_all | ||
pins.dup.each { |pin| unexport(pin) } | ||
end | ||
|
||
def exported?(pin) | ||
pins.include?(pin) | ||
end | ||
|
||
def unexported?(pin) | ||
!exported?(pin) | ||
end | ||
|
||
private | ||
|
||
def export(pin) | ||
raise ArgumentError, "Pin #{pin} already exported" if exported?(pin) | ||
File.write('/sys/class/gpio/export', pin) | ||
pins << pin | ||
end | ||
|
||
def pin_direction(pin, direction) | ||
File.write("/sys/class/gpio/gpio#{pin}/direction", direction) | ||
end | ||
|
||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is a missunderstanding.
PiPiper.driver in my implementation is the only instance of any driver kind loaded at any moment.
I even though a moment to use the singleto module : http://ruby-doc.org/stdlib-1.9.3/libdoc/singleton/rdoc/Singleton.html
If we want to be able to have several drivers for several Object, we have to rethink the implementation. I don't think it is very useful, but we can discuss it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I thought we would do something like this in the user code:
And yes, only 1 driver would be loaded for
PiPiper
at any given moment.Is that what you meant, or something different?
And then later on if you do
Or we could allow driver changes but that would complicate things.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in PiPiper I wrote :
It ensure the driver is properly closed before loading a new one. I thought it was enough, it free a bit of memory, and it lightened the
at_exit
hook.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And as you only need one driver to be loaded my implementation allow to only write :
it load the code and load the driver with
PiPiper.driver = PiPiper::Bcm2835
in the Bcm2835 module/classThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see, I can certainly change my code so that it works like the above. It will load the driver when running
require
.