class BitWizard::Board
Attributes
address[R]
bus[R]
features[R]
logger[RW]
type[R]
version[R]
Public Class Methods
detect(options)
click to toggle source
Detects the type of board on the given address and creates the correct handler class for it.
@param [Number] address The address to check. @param [optional, Hash] options A Hash of options. @option options [Symbol] :bus The type of bus the board is connected on. (:spi or :i2c) @option options [Logger] :logger A logger you want to attach to the board.
# File lib/bitwizard.rb, line 13 def Board.detect(options) options = { address: -1, bus: :spi, logger: NullLogger.new }.merge(options).merge({ type: :auto_detect, skip_check: false }) options[:logger] = NullLogger.new unless options[:logger] temp = BitWizard::Board.new options correct = temp.instance_variable_get(:@constructor).call(options.merge({skip_check: true})) if temp.valid? correct.instance_variable_set(:@type, temp.type) correct.instance_variable_set(:@version, temp.version) correct.instance_variable_set(:@features, temp.features) correct end
new(options)
click to toggle source
Creates a generic board handle for reading and writing directly.
@param [Hash] options A hash of options. @option options [Fixnum] :address The address of the board. (0x00..0xff) @option options [Symbol] :type The board type, defaults to auto detecting. (identifier) @option options [Symbol] :bus The bus it's connected to. (:spi or :i2c) @option options [Boolean] :skip_check Skip the self check that runs on creation. @option options [Number] :clock The clockrate you want to run the communication with. @option options [Logger] :logger Add a logger here to log data that's sent and received.
# File lib/bitwizard.rb, line 47 def initialize(options) options = { address: -1, type: :auto_detect, bus: :spi, skip_check: false, clock: 45000, logger: NullLogger.new }.merge(options) raise ArgumentError.new "Bus must be :spi or :i2c." unless options[:bus] == :spi or options[:bus] == :i2c @logger = options[:logger] @address = options[:address] @type = options[:type] @bus = options[:bus] self_check! unless options[:skip_check] end
Public Instance Methods
address=(new_address)
click to toggle source
Changes the boards address
The new address needs to follow these criteria; * Must be a 8-bit number between 0x00 and 0xff * Must not have it's least significant bit set @param [Number] new_address The new address of the board
# File lib/bitwizard.rb, line 104 def address=(new_address) raise ArgumentError.new "#{new_address} is not a valid address" unless new_address.is_a? Fixnum and (0..255).include? new_address and new_address|1 != new_address # Run a quick check so that there isn't a board on the other address. old_address = @address @address = new_address identifier = read(0x01, 20).pack("C*").split("\0")[0] @address = old_address Known_Boards.each do |name, data| if name =~ identifier then raise ArgumentError.new "Another board (#{identifier}) already exists on #{new_address}!" end end # Unlock the change register write 0xf1, 0x55 write 0xf2, 0xaa # Perform the change write 0xf0, new_address @address = new_address end
read(reg, count)
click to toggle source
Reads a value from the board
@param [Number] reg The registry address to read from @param [Number] count The number of bytes to read
# File lib/bitwizard.rb, line 90 def read(reg, count) raise ArgumentError.new "#{reg} is not a valid register, must be a number between 0x00..0xff" unless reg.is_a? Fixnum and (0..255).include? reg return spi_read(reg, count) if @bus == :spi return i2c_read(reg, count) if @bus == :i2c end
valid?()
click to toggle source
Returns if the board has a valid communication address
# File lib/bitwizard.rb, line 68 def valid? return false if @address == -1 or @type == :auto_detect true end
write(reg, value)
click to toggle source
Writes a value to the board, either a single byte or several in the form of a string
@param [Number] reg The registry address to write to @param [Number|String] value The data to write to the board
# File lib/bitwizard.rb, line 77 def write(reg, value) raise ArgumentError.new "#{reg} is not a valid register, must be a number between 0x00..0xff" unless reg.is_a? Fixnum and (0..255).include? reg raise ArgumentError.new "#{value} is not a valid value, must be a single byte or a string" unless (value.is_a? Fixnum and (0..255).include? value) or (value.is_a? String) value = value.unpack("C*") if value.is_a? String return spi_write(reg, value) if @bus == :spi return i2c_write(reg, value) if @bus == :i2c end
Private Instance Methods
i2c_read(reg, count)
click to toggle source
# File lib/bitwizard.rb, line 211 def i2c_read(reg, count) PiPiper::I2C.begin do |i2c| i2c.write({ to: @address | 1, data: [reg] }) end data = PiPiper::I2C.begin do |i2c| PiPiper::Platform.driver.i2c_set_address(@address | 1) i2c.read count end @logger.debug("I2C [0x#{@address.to_s(16)}] --> 0x#{reg.to_s(16)}: #{data.pack("C*").inspect}") data end
i2c_write(reg, value)
click to toggle source
# File lib/bitwizard.rb, line 199 def i2c_write(reg, value) @logger.debug("I2C [0x#{@address.to_s(16)}] <-- 0x#{reg.to_s(16)}: #{value.is_a? Array and value.pack("C*").inspect or value.inspect}") PiPiper::I2C.begin do |i2c| data = [reg] data << value unless value.is_a? Array data += value if value.is_a? Array i2c.write({ to: @address, data: data }) end end
self_check!()
click to toggle source
Performs a self check of the board
This includes contacting the board and checking that it's of the correct type.
# File lib/bitwizard.rb, line 138 def self_check! found_board = nil Known_Boards.each do |name, data| if name =~ @type then @address = data[:default_address] unless (0..255).include? @address found_board = { name: name, data: data } break end end raise ArgumentError.new "Don't know what board '#{@type}' is." if not found_board and @type != :auto_detect raise ArgumentError.new "Board type is 'auto_detect', but invalid address #{@address} given." if @type == :auto_detect and not (0..255).include? @address identifier = read(0x01, 20).pack("C*").split("\0")[0] raise ArgumentError.new "No response from board" if not identifier or identifier.empty? if @type == :auto_detect then Known_Boards.each do |name, data| if name =~ identifier then @type, @version = *identifier.split @type = @type.to_sym @constructor = data[:constructor] @features = data[:features] break end end raise ArgumentError.new "No known board of type '#{identifier}'." if @type == :auto_detect and not identifier.empty? else Known_Boards.each do |name, data| if name =~ identifier then @version = identifier.split[1] @features = data[:features] raise ArgumentError.new "Board reports type #{real_name}, which does not match #{@type}" unless found_board[:data] == data break end end end true end
spi_read(reg, count)
click to toggle source
# File lib/bitwizard.rb, line 190 def spi_read(reg, count) data = PiPiper::Spi.begin do |spi| spi.write @address | 1, reg, *Array.new(count, 0) end[2..-1] @logger.debug("SPI [0x#{@address.to_s(16)}] --> 0x#{reg.to_s(16)}: #{data.pack("C*").inspect}") data end
spi_write(reg, value)
click to toggle source
# File lib/bitwizard.rb, line 182 def spi_write(reg, value) @logger.debug("SPI [0x#{@address.to_s(16)}] <-- 0x#{reg.to_s(16)}: #{value.is_a? Array and value.pack("C*").inspect or value.inspect}") PiPiper::Spi.begin do |spi| spi.write @address, reg, *value if value.is_a? Array spi.write @address, reg, value unless value.is_a? Array end end