Closed thus1 closed 11 years ago
Do you have this up anywhere? I'd love to use it in lieue of a decision being made here.
Sorry for the late answer, I didnt recognize your request in my mail-folder. How can I attach the source-code here? Ok I try it inline. I think it would be nice if we could add this single file to the ruby-gem 'wiringPi' for simpification of the install procedure. But for now you can copy the file to any location where your ruby looks to. (ruby -e 'p $:') Decide yourself if you need the subdirectory wiringPi.
#!/usr/bin/ruby # # = wiringPi/spi.rb # # Object-Oriented WiringPi::Spi Class # # Author:: Thomas Husterer# # This module currently works only with ruby >= 1.9, because some minor # 1.9 features are used. e.g. Hash#merge. # # For documentation, use rdoc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. require "pp" begin require "ffi" rescue LoadError raise "\nmissing ffi-package, install with:\nsudo apt-get install ruby-ffi" end # This module Ioctl is only a helper module module Ioctl#:nodoc: IOC_NRBITS = 8 IOC_TYPEBITS = 8 IOC_SIZEBITS = 14 IOC_DIRBITS = 2 #dir: IOC_NONE = 0 IOC_WRITE = 1 IOC_READ = 2 class << self def ioc(dir,type,nr,size) dir < (1 << IOC_DIRBITS) or raise type < (1 << IOC_TYPEBITS) or raise nr < (1 << IOC_NRBITS) or raise size < (1 << IOC_SIZEBITS) or raise n = 0 n = dir | (n << IOC_DIRBITS) n = size | (n << IOC_SIZEBITS) n = type | (n << IOC_TYPEBITS) n = nr | (n << IOC_NRBITS) n-=2**32 if n >= 2**31 n end #/* used to create numbers */ def ioc_r(type,nr,realsize) #define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size))) ioc(IOC_READ,type,nr,realsize) end def ioc_w(type,nr,realsize)#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) ioc(IOC_WRITE,type,nr,realsize) end def ioc_rw(type,nr,realsize)#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) ioc(IOC_READ|IOC_WRITE,type,nr,realsize) end end end module WiringPi # This class WiringPi::Spi is used to generate Interface-Objects # for each spi-channel # # Usage: # # require "wiringPi/spi" # # spi = WiringPi::Spi.new("/dev/spidev0.0",speed: 1000000) # result = spi.dataRW([1,2,3,0,4],delay: 100,bytedelay: 10) # p result # spi.close # # class Spi OPTS ={ speed: 1000000, #from 10KHz .. 100MHz ? bpw: 8, #here only 8 is supported delay: 0, #us delay after whole message bytedelay: nil #us delay after each sent byte } #:nodoc: SPI_IOC_MAGIC = 107 #?k #"k".chr #:nodoc: #struct spi_ioc_transfer see /usr/include/linux/spi/spidev.h SPI_IOC_TRANSFER_SIZE = 32 # Spi_ioc_transfer.size #:nodoc: SPI_IOC_WR_MSG={}#:nodoc: def spi_ioc_message(n)#:nodoc: SPI_IOC_WR_MSG[n] ||= Ioctl::ioc_w(SPI_IOC_MAGIC, 0, n*SPI_IOC_TRANSFER_SIZE) end #/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */ SPI_IOC_RD_MODE = Ioctl::ioc_r(SPI_IOC_MAGIC, 1, 1)#:nodoc: SPI_IOC_WR_MODE = Ioctl::ioc_w(SPI_IOC_MAGIC, 1, 1)#:nodoc: #/* Read / Write SPI bit justification */ SPI_IOC_RD_LSB_FIRST = Ioctl::ioc_r(SPI_IOC_MAGIC, 2, 1)#:nodoc: SPI_IOC_WR_LSB_FIRST = Ioctl::ioc_w(SPI_IOC_MAGIC, 2, 1)#:nodoc: #/* Read / Write SPI device word length (1..N) */ SPI_IOC_RD_BITS_PER_WORD = Ioctl::ioc_r(SPI_IOC_MAGIC, 3, 1)#:nodoc: SPI_IOC_WR_BITS_PER_WORD = Ioctl::ioc_w(SPI_IOC_MAGIC, 3, 1)#:nodoc: #/* Read / Write SPI device default max speed hz */ SPI_IOC_RD_MAX_SPEED_HZ = Ioctl::ioc_r(SPI_IOC_MAGIC, 4, 4)#:nodoc: SPI_IOC_WR_MAX_SPEED_HZ = Ioctl::ioc_w(SPI_IOC_MAGIC, 4, 4)#:nodoc: private :spi_ioc_message # This method sends out some data-bytes and receives the same number # of bytes from the slave-device # # [data] may be given in three formats # * as String e.g. "hello" # * as Array of positive Integers (0-255) e.g. [1,2,3] # * as FFI::MemoryPointer # # [opts] arguments are the same as in the new-method # # The received Bytes are returned as an Array of positive Interger values def dataRW(data,opts={}) if data.is_a? String wbuf = FFI::MemoryPointer.from_string(data) elsif data.is_a? FFI::Pointer wbuf = data elsif data.is_a? Array wbuf = FFI::MemoryPointer.new(:uint8,data.length) wbuf.write_array_of_uint8(data) else raise end rbuf=FFI::MemoryPointer.new(:uint8,wbuf.size) FFI::Pointer.size==4 or raise "" opts = @opts.merge(opts) speed = opts[:speed] bpw = opts[:bpw] delay = opts[:delay] bytedelay = opts[:bytedelay] if bytedelay and bytedelay != 0 iter = wbuf.size len = 1 else iter = 1 len = wbuf.size end spi = "" #setup ioctl message buffer iter.times{|i| last = i==(iter-1) spi+=[ wbuf.address+i, # layout :tx_buf ,:pointer, 0, # :tx_buf64 ,:pointer, rbuf.address+i, # :rx_buf ,:pointer, 0, # :rx_buf64 ,:pointer, len, # :len ,:uint32 , speed, # :speed_hz ,:uint32 , last ? delay : bytedelay, # :delay_usecs ,:uint16 , bpw, # :bits_per_word ,:uint8 , last ? 1 : 0, # :cs_change ,:uint8 , 0, # :pad ,:uint32 ].pack("LLLLLLSCCL") } @fh.ioctl(spi_ioc_message(iter),spi) rbuf.read_array_of_uint8(rbuf.size) end # generate a new Spi-Channel object # [chan] may be a number or a device-name-path # any additional arguments are options-arguments # # [opts] may be: # * speed: a value from 10KHz .. 100MHz ? # * bpw: here only 8 is supported # * delay: a delay after the whole message in us # * bytedelay: a delay after each sent byte in us # # # Example: # WiringPi::Spi.new("/dev/spidev0.0", speed: 1000000, bytedelay: 50) def initialize(chan,opts={}) dev = chan.is_a?(Integer) ? "/dev/spidev0.#{chan}" : chan begin @fh = File.open(dev,"w+b") rescue Errno::EACCES raise "\nPermission denied, maybe its missing:\nsudo modprobe spi_bcm2708\nsudo chown #{Process.uid} #{dev}" end @opts=OPTS.merge(opts) s_Mode = [0].pack("C") #static uint8_t spiMode = 0 ; @fh.ioctl(SPI_IOC_WR_MODE,s_Mode) @fh.ioctl(SPI_IOC_RD_MODE,s_Mode) s_BPW = [OPTS[:bpw]].pack("C") #static uint8_t spiBPW = 8 ; @fh.ioctl(SPI_IOC_WR_BITS_PER_WORD,s_BPW) @fh.ioctl(SPI_IOC_RD_BITS_PER_WORD,s_BPW) s_Speed= [OPTS[:speed]].pack("V") #u32 @fh.ioctl(SPI_IOC_WR_MAX_SPEED_HZ,s_Speed) @fh.ioctl(SPI_IOC_RD_MAX_SPEED_HZ,s_Speed) end # closes this channel after usage def close @fh.close end end end if $0 == __FILE__ spi=WiringPi::Spi.new("/dev/spidev0.0",speed: 1000000) while 1 p spi.dataRW([1,2,3,0,4],delay: 100,bytedelay: 10) sleep 0.001 end spi.close end
sorry, i hit the wrong button 'Close & Comment' how can I undo this step?
Looks like the script got garbled around the Ioctl module
What is the output in the shell when the script craches
I have implemented a small pure-ruby-library(150 lines) for spi-access.
usage:
require "wiringpi/spi" spi = WiringPi::Spi.new("/dev/spidev0.0",speed: 1000000) result = spi.dataRW([1,2,3,0,4],delay: 100,bytedelay: 10) spi.close
The lib requires the package ruby-1.9x and ruby-ffi, both is available in rapbian wheezy
Do you think its worth to integrate it into this project?
con:
pro:
By the way, the same arguments also count for any other functionality of wiringPi ;-))