Ruby Class for Bus Pirate binmode
From wiki.countercaster.com
This is my attempt at a simple Ruby library for accessing the Bus Pirate's binmodes.
At the moment it only (partially) supports binmode SPI mode. Error traps are conspicuously absent!
For an example of how to use it, see Scripting the Bus Pirate to talk to a Nokia 3310 LCD.
# # A start at a Ruby library for accessing the Bus Pirate's binmode SPI feature. # by blue.zener # October 2009 # # Use and adapt as you wish, and at your own risk. # module BusPirate require 'rubygems' require 'serialport' class BinModeSpi SpiSpeedMask = { 30000 => 0b000, 125000 => 0b001, 250000 => 0b010, 1000000 => 0b011, 2000000 => 0b100, 2600000 => 0b101, 4000000 => 0b110, 8000000 => 0b111 } def open(port, baud, options = {}) @serial_port = SerialPort.new(port, baud, 8, 1, SerialPort::NONE) @serial_port.flow_control = SerialPort::NONE @serial_port.sync = true init_binary_mode init_spi_mode configure_spi(options) configure_spi_speed(options) end def set_cs_high @serial_port.putc(0b00000011) puts "spi_cs_high: 0x%02x" % @serial_port.readchar end def set_cs_low @serial_port.putc(0b00000010) puts "spi_cs_low: 0x%02x" % @serial_port.readchar end # High level write # Write a single byte or array of bytes in "data". # to device attached to SPI port. # # Abstracts away BP bulk transfer limit of 16 bytes. # So "data" can be any length. def write(data) set_cs_low data = arrayify(data) # slice into bulk transfer size portions transfer_count = 0 data.to_enum.each_slice(16) do |chunk| write_bulk_transfer(chunk, :read => false) transfer_count += 1 end sleep(0.05) @serial_port.readpartial(transfer_count + data.length) set_cs_high end def set_peripherals(options = {}) params = {:power => 0, :pull_ups => 0, :aux => 0, :chip_select => 0}.merge(options) mask = 0 mask |= params[:power] << 3 mask |= params[:pull_ups] << 2 mask |= params[:aux] << 1 mask |= params[:chip_select] @serial_port.putc(0b01000000 | mask) puts "set_peripherals: 0x%02x" % @serial_port.readchar end def close return_to_binary_mode return_to_user_terminal_mode @serial_port.close end private def init_binary_mode 20.times do @serial_port.putc(0x00) end response = "" 5.times do response << @serial_port.readchar end puts "init_binary_mode: #{response}" end def init_spi_mode @serial_port.putc(0b00000001) response = "" 4.times do response << @serial_port.readchar end puts "init_spi_mode: #{response}" end def configure_spi(options = {}) params = {:output_type=>0, :idle=>0, :clock_edge=>0, :sample=>0}.merge(options) mask = 0 mask |= params[:output_type] << 3 mask |= params[:idle] << 2 mask |= params[:clock_edge] << 1 mask |= params[:sample] @serial_port.putc(0b10000000 | mask) puts "configure_spi: 0x%02x" % @serial_port.readchar end def configure_spi_speed(options={}) params = {:speed => 30000}.merge(options) puts "configure_spi_speed: Speed: %iHz" % params[:speed] puts "configure_spi_speed: Speed mask: %08b" % SpiSpeedMask[params[:speed]] @serial_port.putc(0b01100000 | SpiSpeedMask[params[:speed]]) puts "configure_spi_speed: 0x%02x" % @serial_port.readchar end def start_bulk_transfer(length, options={}) params = {:read => true}.merge(options) @serial_port.putc(0b00010000 | (length-1)) if (params[:read]) puts "start_bulk_transfer: 0x%02x" % @serial_port.readchar end end def write_bulk_transfer(data, options={}) params = {:read => true}.merge(options) if data.length > 16 puts "write_bulk_transfer: data exceeds maximum length (16)" return end start_bulk_transfer(data.length, params) data.each do |byte| @serial_port.putc(byte) @serial_port.readchar if params[:read] #puts "write_bulk_transfer: 0b%08b" % byte end end def return_to_binary_mode @serial_port.putc(0b00000000) puts "return_to_binary_mode" end def return_to_user_terminal_mode @serial_port.putc(0b00001111) puts "return_to_user_terminal_mode" end def arrayify(data) return data if data.kind_of?(Array) [] << data end end end
