Class: LittleWire

Inherits:
Object
  • Object
show all
Includes:
Analog, Digital, HardwarePWM, Servo, SoftwarePWM
Defined in:
lib/littlewire.rb,
lib/littlewire.rb,
lib/littlewire/version.rb,
lib/littlewire/gadgets/nunchuck.rb

Overview

A little library for a little wire, by Bluebie Provides an arduino or wiring style interface to the LittleWire device’s IO features and provides a nicer invented ruby-style interface also.

LittleWire class represents LittleWire’s connected to your computer via USB

Most of the time you’ll only have one LittleWire - in this case, use LittleWire.connect to get ahold of your wire. If you have more than one, you can use LittleWire.all to fetch an array of them

Defined Under Namespace

Modules: Analog, Digital, HardwarePWM, OneWire, Servo, SoftwarePWM Classes: I2C, Nunchuck, SPI, WS2811

Constant Summary collapse

DigitalPinMap =

pin name to numeric internal code maps

{ # maps common names to bit positions in PORTB
pin1: 1, d1: 1, miso:  1, pwm_b: 1, pwm_2: 1, ds1: 1,
pin2: 2, d2: 2, sck:   2, ds2: 2,
pin3: 5, d3: 5, reset: 5, ds5: 5,
pin4: 0, d4: 0, mosi:  0, pwm_a: 0, pwm_1: 0, ds0: 0 }
AnalogPinMap =

maps common names to switch index in littlewire firmware

{ # maps common names to switch index in littlewire firmware
a1: 0, adc_1: 0, reset: 0, pin3: 0, d3: 0, ds5: 0,
a2: 1, adc_2: 1, sck:   1, pin2: 1, d2: 1, ds2: 1,
temperature: 2, temp: 2 }
HardwarePWMPinMap =

maps common pin names to @hardware_pwm array index

{ # maps common pin names to @hardware_pwm array index
pwm_b: 1, pwm_1: 1, d1: 1, pin1: 1, miso: 1,
pwm_a: 0, pwm_2: 0, d4: 0, pin4: 0, mosi: 0 }
SoftwarePWMPinMap =

TODO: figure out which pins these are

{ # TODO: figure out which pins these are
softpwm_1: 0, softpwm_a: 0, pin4: 0, d4: 0, mosi: 0, pwm_a: 0, pwm_1: 0,
softpwm_2: 1, softpwm_b: 1, pin1: 1, d1: 1, miso: 1, pwm_b: 1, pwm_2: 1,
softpwm_3: 2, softpwm_c: 2, pin2: 2, d2: 2, sck: 2 }
GenericPinMap =

generic pinmap used by [] and []= methods to refer to anything

{ # generic pinmap used by [] and []= methods to refer to anything
  d1: [:digital, :pin1],
  d2: [:digital, :pin2],
  d3: [:digital, :pin3],
  d4: [:digital, :pin4],
  pin1: [:digital, :pin1],
  pin2: [:digital, :pin2],
  pin3: [:digital, :pin3],
  pin4: [:digital, :pin4],
  a1: [:analog, :a1],
  a2: [:analog, :a2],
  adc_1: [:analog, :adc_1],
  adc_1: [:analog, :adc_2],
  pwm_1: [:hardware_pwm, :pwm_1],
  pwm_2: [:hardware_pwm, :pwm_2],
  pwm_a: [:hardware_pwm, :pwm_a],
  pwm_b: [:hardware_pwm, :pwm_b],
  softpwm_1: [:software_pwm, :softpwm_1],
  softpwm_2: [:software_pwm, :softpwm_2],
  softpwm_3: [:software_pwm, :softpwm_3],
  softpwm_a: [:software_pwm, :softpwm_a],
  softpwm_b: [:software_pwm, :softpwm_b],
  softpwm_c: [:software_pwm, :softpwm_c],
}
SupportedVersions =

in order of newness.

['1.3','1.2', '1.1', '1.0']
Functions =

functions offered by the LittleWire

[
  ## Generic requests
  :echo,      # echo test  0
  :read,      # read byte (wIndex:address)  1
  :write,     # write byte (wIndex:address, wValue:value)  2
  :clear_bit, # clear bit (wIndex:address, wValue:bitno)  3
  :set_bit,   # set bit (wIndex:address, wValue:bitno)  4
  ## Programming requests
  :power_up,      # apply power (wValue:SCK-period, wIndex:RESET)  5
  :power_down,    # remove power from chip  6
  :spi,           # issue SPI command (wValue:c1c0, wIndex:c3c2)  7
  :poll_bytes,    # set poll bytes for write (wValue:p1p2)  8
  :flash_read,    # read flash (wIndex:address)  9
  :flash_write,   # write flash (wIndex:address, wValue:timeout)  10
  :eeprom_read,   # read eeprom (wIndex:address)  11
  :eeprom_write,  # write eeprom (wIndex:address, wValue:timeout)  12
  ## Additional requests - ihsanKehribar
  :pin_set_input,       # 13
  :pin_set_output,      # 14
  :read_adc,            # 15
  :start_pwm,           # 16
  :update_pwm_compare,  # 17
  :pin_set_high,        # 18
  :pin_set_low,         # 19
  :pin_read,            # 20
  :single_spi,          # 21
  :change_pwm_prescale, # 22
  :setup_spi,           # 23
  :setup_i2c,           # 24
  :i2c_begin_tx,        # 25
  :i2c_add_buffer,      # 26
  :i2c_send_buffer,     # 27
  :spi_add_buffer,      # 28
  :spi_send_buffer,     # 29
  :i2c_request_from,    # 30
  :spi_update_delay,    # 31
  :stop_pwm,            # 32
  :debug_spi,           # 33
  :version,             # 34
  :analog_init,         # 35
  :reserved, :reserved, :reserved, :reserved,
  :read_buffer,         # 40
  :onewire_reset_pulse, # 41
  :onewire_send_byte,   # 42
  :onewire_read_byte,   # 43
  :i2c_init,            # 44
  :i2c_begin,           # 45
  :i2c_read,            # 46
  :init_softpwm,        # 47
  :update_softpwm,      # 48
  :i2c_update_delay,    # 49
  :onewire_read_bit,    # 50
  :onewire_write_bit,   # 51
  :pic_24f_programming, # 52 - experimental
  :pic_24f_sendsix,     # 53 - experimental
  :ws2812,              # 54 - experimental
  # special cases
  # pic 24f send bytes - request = 0xD*
  # i2c send multiple messages - request = 0xE*     ### experimental ###
  # spi multiple message send - request = 0xF*
]
Version =
'0.9.11'

Constants included from HardwarePWM

HardwarePWM::PWMPrescaleSettings

Constants included from Analog

Analog::AnalogReferences

Constants included from Digital

Digital::BulkWriteBitmask, Digital::BulkWriteDefaultStates, Digital::EnableBulkWrite

Instance Attribute Summary

Attributes included from SoftwarePWM

#software_pwm_enabled

Attributes included from HardwarePWM

#hardware_pwm_enabled

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Servo

#servo_read, #servo_write

Methods included from SoftwarePWM

#is_software_pwm_available?, #software_pwm, #software_pwm=, #software_pwm_read, #software_pwm_write

Methods included from HardwarePWM

#hardware_pwm, #hardware_pwm=, #hardware_pwm_prescale=, #hardware_pwm_read, #hardware_pwm_write

Methods included from Analog

#analog_read, #temperature

Methods included from Digital

#digital_read, #digital_write, #pin_mode

Constructor Details

#initialize(devref) ⇒ LittleWire

initializes a LittleWire with a libusb device reference and some default values - does not talk to device



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/littlewire.rb', line 89

def initialize devref #:nodoc:
  @device = devref
  
  @hardware_pwm_enabled = :unknown
  @hardware_pwm_prescale = :unknown
  @hardware_pwm = [0, 0]
  @software_pwm_enabled = :unknown
  @software_pwm = [0, 0, 0]
  
  # shut everything down, trying to setup littlewire in consistent initial state in case previous programs
  # messed with it's state
  self.software_pwm_enabled = false if version_hex >= 0x11
  self.hardware_pwm_enabled = false
  self.pin_mode(pin1: :input, pin2: :input, pin3: :input, pin4: :input)
  self.digital_write(pin1: :gnd, pin2: :gnd, pin3: :gnd, pin4: :gnd)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &proc) ⇒ Object

translate calls with arduino-style lowerCamelCase method names in to ruby-style underscored_method_names



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/littlewire.rb', line 179

def method_missing name, *args, &proc
  underscorized = name.to_s.gsub(/([a-z])([A-Z])/) { "#{$1}_#{$2}" }.downcase  # make underscored equivilent
  return send(underscorized, *args, &proc) if respond_to? underscorized # translate casing style if we can find an equivilent
  
  read_only = name.to_s.gsub('=', '').to_sym
  if GenericPinMap.has_key? read_only
    if name.to_s.end_with? '='
      return (self[read_only] = args.first)
    else
      return self[read_only]
    end
  end
  
  super # default behaviour
end

Class Method Details

.allObject

An array of all unclaimed littlewires connected to computer via USB



75
76
77
78
79
80
81
82
# File 'lib/littlewire.rb', line 75

def self.all
  usb = LIBUSB::Context.new
  usb.devices.select { |device|
    device.idProduct == 0x0c9f && device.idVendor == 0x1781 && device.product == 'USBtinySPI'
  }.map { |device|
    self.new(device)
  }
end

.connectObject

Frst littlewire connected to this computer via USB - good when you only have one



85
# File 'lib/littlewire.rb', line 85

def self.connect; all.first; end

.create_destructor(io) ⇒ Object

creates a lambda to close usb device when LittleWire is deallocated, without LittleWire instance closured in to it recursively



107
108
109
110
111
# File 'lib/littlewire.rb', line 107

def self.create_destructor io #:nodoc:
  lambda do
    io.close
  end
end

.versionObject

correct interface, to enable dynamic stuff later if need be:



5
6
7
# File 'lib/littlewire/version.rb', line 5

def self.version
  LittleWire::Version
end

Instance Method Details

#[](name) ⇒ Object

get the value of something



197
198
199
200
201
# File 'lib/littlewire.rb', line 197

def [] name
  pin = GenericPinMap[name.to_sym]
  raise "Unknown Pin '#{name}'" unless pin
  self.send "#{pin[0]}_read", pin[1]
end

#[]=(name, value) ⇒ Object

set the value of something



204
205
206
207
208
# File 'lib/littlewire.rb', line 204

def []= name, value
  pin = GenericPinMap[name.to_sym]
  raise "Unknown Pin '#{name}'" unless pin
  self.send "#{pin[0]}_write", pin[1], value
end

#control_transfer(opts = {}) ⇒ Object

transfer data between usb device and this program



300
301
302
303
304
305
306
307
308
# File 'lib/littlewire.rb', line 300

def control_transfer(opts = {}) #:nodoc:
  opts[:bRequest] = Functions.index(opts.delete(:function)) if opts[:function]
  io.control_transfer({
    wIndex: 0,
    wValue: 0,
    bmRequestType: usb_request_type(opts),
    timeout: 5000
  }.merge opts)
end

#finishedObject

Call finished when you’re done with the LittleWire to release it for other programs to use. You can always claim it again later by using any of the methods on this class which communicate over USB



115
116
117
118
119
120
121
# File 'lib/littlewire.rb', line 115

def finished
  if @io
    ObjectSpace.undefine_finalizer(self) # remove usb closer finalizer
    @io.close
    @io = nil
  end
end

#get_boolean(value) ⇒ Object

translate possible literal values in to a boolean true or false (meaning high or low)



219
220
221
222
223
# File 'lib/littlewire.rb', line 219

def get_boolean value #:nodoc:
  # some exceptions
  value = false if value == :low or value == 0 or value == nil or value == :off or value == :ground or value == :gnd
  !! value # double invert value in to boolean form
end

#get_pin(map, value) ⇒ Object

lookup a pin name in a map and return it’s raw identifier



212
213
214
215
216
# File 'lib/littlewire.rb', line 212

def get_pin map, value #:nodoc:
  value = value.to_sym if value.is_a? String
  value = map[value] if map.has_key? value
  value
end

#i2cObject

get the I2C interface



153
154
155
# File 'lib/littlewire.rb', line 153

def i2c
  @i2c ||= I2C.new(self)
end

#ioObject

raw opened device



226
227
228
229
230
231
232
233
234
235
# File 'lib/littlewire.rb', line 226

def io #:nodoc:
  unless @io
    @io = @device.open
    ObjectSpace.define_finalizer(self, self.class.create_destructor(@io))
    
    # check for compatible firmware on littlewire device and warn if is unknown
    warn "Unknown littlewire.cc firmware version #{version} might cause problems" unless SupportedVersions.include? version
  end
  @io
end

#nunchuckObject

get Wii Nunchuck interface



3
4
5
# File 'lib/littlewire/gadgets/nunchuck.rb', line 3

def nunchuck
  @nunchuck ||= LittleWire::Nunchuck.new self
end

#one_wireObject

get the 1wire interface (requires firmware 1.1 or newer)



158
159
160
161
# File 'lib/littlewire.rb', line 158

def one_wire
  raise "You need to update your LittleWire firmware to version 1.1 to use One Wire" unless version_hex >= 0x11
  @one_wire ||= OneWire.new(self)
end

#spiObject

get the SPI interface



148
149
150
# File 'lib/littlewire.rb', line 148

def spi
  @spi ||= SPI.new(self)
end

#usb_request_type(opts) ⇒ Object

calculate usb request type



311
312
313
314
315
316
# File 'lib/littlewire.rb', line 311

def usb_request_type opts #:nodoc:
  value = LIBUSB::REQUEST_TYPE_VENDOR | LIBUSB::RECIPIENT_DEVICE
  value |= LIBUSB::ENDPOINT_OUT if opts.has_key? :dataOut
  value |= LIBUSB::ENDPOINT_IN if opts.has_key? :dataIn
  return value
end

#versionObject

Returns version number of firmware on LittleWire hardware



143
144
145
# File 'lib/littlewire.rb', line 143

def version
  @version ||= version_hex.to_s(16).chars.entries.join('.')
end

#version_hexObject

returns version code number (treat it as a hex number)



138
139
140
# File 'lib/littlewire.rb', line 138

def version_hex
  @version_hex ||= control_transfer(function: :version, dataIn: 1).unpack('c').first
end

#ws2811(pin = false) ⇒ Object Also known as: ws2812

get the ws2811 led strip interface (requires firmware 1.2 or newer) optionally call with pin number to preset it



165
166
167
168
169
170
171
172
# File 'lib/littlewire.rb', line 165

def ws2811 pin = false
  raise "You need to update your LittleWire firmware to version 1.2 to use One Wire" unless version_hex >= 0x12
  @ws2811 ||= Array.new
  pin = get_pin(LittleWire::DigitalPinMap, pin || 0)
  raise "Unknown pin #{pin.inspect}" unless pin.is_a? Integer
  @ws2811[pin] ||= WS2811.new(self, pin)
  return @ws2811[pin]
end