Class: Micronucleus

Inherits:
Object
  • Object
show all
Defined in:
lib/littlewire/gadgets/micronucleus.rb

Overview

Abstracts access to micronucleus avr tiny85 bootloader - can be used only to erase and upload bytes

Constant Summary collapse

Functions =
[
  :get_info,
  :write_page,
  :erase_application,
  :run_program
]

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(devref) ⇒ Micronucleus

Returns a new instance of Micronucleus.



22
23
24
# File 'lib/littlewire/gadgets/micronucleus.rb', line 22

def initialize devref
  @device = devref
end

Class Method Details

.allObject

return all micronucleus devices connected to computer



13
14
15
16
17
18
19
20
# File 'lib/littlewire/gadgets/micronucleus.rb', line 13

def self.all
  usb = LIBUSB::Context.new
  usb.devices.select { |device|
    device.idVendor == 0x16d0 && device.idProduct == 0x0753
  }.map { |device|
    self.new(device)
  }
end

Instance Method Details

#erase!Object



44
45
46
47
48
49
50
51
52
# File 'lib/littlewire/gadgets/micronucleus.rb', line 44

def erase!
  puts "erasing"
  info = self.info
  control_transfer(function: :erase_application)
  info[:pages].times do
    sleep(info[:write_sleep]) # sleep for as many pages as the chip has to erase
  end
  puts "erased chip"
end

#finishedObject



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/littlewire/gadgets/micronucleus.rb', line 74

def finished
  info = self.info

  puts "asking device to finish writing"
  control_transfer(function: :run_program)
  puts "waiting for device to finish"

  # sleep for as many pages as the chip could potentially need to write - this could be smarter
  info[:pages].times do
    sleep(info[:write_sleep]) 
  end

  @io.close
  @io = nil
end

#infoObject



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/littlewire/gadgets/micronucleus.rb', line 26

def info
  unless @info
    result = control_transfer(function: :get_info, dataIn: 4)
    flash_length, page_size, write_sleep = result.unpack('S>CC')

    @info = {
      flash_length: flash_length,
      page_size: page_size,
      pages: (flash_length.to_f / page_size).ceil,
      write_sleep: write_sleep.to_f / 1000.0,
      version: "#{@device.bcdDevice >> 8}.#{(@device.bcdDevice & 0xFF).to_s.rjust(2, '0')}",
      version_numeric: @device.bcdDevice
    }
  end

  @info
end

#inspectObject



90
91
92
# File 'lib/littlewire/gadgets/micronucleus.rb', line 90

def inspect
  "<Micronucleus #{info[:version]}: #{(info[:flash_length] / 1024.0).round(1)} kb programmable>"
end

#program=(bytestring) ⇒ Object

upload a new program



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/littlewire/gadgets/micronucleus.rb', line 55

def program= bytestring
  info = self.info
  raise "Program too long!" if bytestring.bytesize > info[:flash_length]
  bytes = bytestring.bytes.to_a
  bytes.push(0xFF) while bytes.length < info[:flash_length]
  
  erase!
  
  address = 0
  bytes.each_slice(info[:page_size]) do |slice|
    slice.push(0xFF) while slice.length < info[:page_size] # ensure every slice is one page_size long - pad out if needed
    
    puts "uploading @ #{address} of #{bytes.length}"
    control_transfer(function: :write_page, wIndex: address, wValue: slice.length, dataOut: slice.pack('C*'))
    sleep(info[:write_sleep])
    address += slice.length
  end
end