Commit 49386c92 authored by juhasch's avatar juhasch

Inital commit

parent dcffdb30
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Rope
.ropeproject
# Django stuff:
*.log
*.pot
# Sphinx documentation
docs/_build/
.idea
Created by Sean Nelson on 2009-10-14.
Copyright 2009 Sean Nelson <audiohacked@gmail.com>
Overhauled and edited by Garrett Berg on 2011- 1 - 22
Copyright 2011 Garrett Berg <cloudform511@gmail.com>
This file is part of pyBusPirate.
pyBusPirate is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pyBusPirate 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.
You should have received a copy of the GNU General Public License
along with pyBusPirate. If not, see <http://www.gnu.org/licenses/>.
# pyBusPirateLite
Python library for BusPirate
Based on code from Garrett Berg <cloudform511@gmail.com>
http://dangerousprototypes.com/2011/03/14/new-version-of-pybuspiratelite-python-library/
-------------------------
This is a rewrite for the pyBusPirateLite library. Really more than a rewrite,
it is a complete overhaul. I first started it with the intention of making a
library that allowed you to interface the bus pirate as if it were a microcontroller.
Well, that is still what the library is for, but as time has gone on (and I have used
the library more and more in creating my extend-able oscilloscope program) I went at
it and put recursion in all of the main functions. The reason for this is because
sometimes the bus pirate gets stuck, or a communication is failed, etc, and you have
to try and re-send something. I got really sick of continuouly resending things
explicitly in my code, so I made this library keep trying until it succeeded.
What this means is that if you call a function and it fails the first time,
the function will try again, as many as 15 times, to get it to work. If it doesn't
work, it probably means you don't have the bus pirate connected :D If it doesn't
work it will simply raise an error, as there is probably an error in your code,
not mine (and if it is in mine, then tell me so that I can say this with more
confidence! )
So take a look at the library and try it out with your old code. Let me know what
you think!
Use the library as follows:
1) instantiate a UC object:
my_buspirate = UC()
2) connect:
my_buspirate.connect() #will normally work in linux.
# OR
my_buspirate.connect(port) #define your own port
3) do stuff:
my_buspirate.enter_bb() #always do first after connected. gets into bit bang
my_buspirate.enter_i2c() # get into i2c mode
... do stuff in i2c...
my_buspirate.enter_bb() #get back into bb mode
my_buspirate.configure_peripherals(
power = 'on', pullups = 'on') # turn on power and
# pullups, can be used in any
# mode
my_buspirate.set_dir(0x00) # set the direction of all the pins to output
my_buspirate.set_port(0b10101) # set the pins to output 10101
# (AUX is the high pin, MISO the low pin.
# Specify reverse order (AUX still high, but
# CS low) by setting translate = False)
...etc...
almost everything in the file BitBang.py implements recursion--so you can be sure that
if you tell the bus pirate to do something, it will do it!
#! /usr/bin/env python
# -*- coding: utf-8 -*-
'''
* Summary :
*
* Created on Jan 26, 2011
* @author: garrett
'''
import select
import serial
import sys
from time import sleep
class PinCfg:
POWER = 0x8
PULLUPS = 0x4
AUX = 0x2
CS = 0x1
class BBIOPins:
# Bits are assigned as such:
MOSI = 0x01;
CLK = 0x02;
MISO = 0x04;
CS = 0x08;
AUX = 0x10;
PULLUP = 0x20;
POWER = 0x40;
class BBIOModes:
# modes are assigned as such. Use either the strings or this class in your
# code
I2C = 'i2c'
UART = 'uart'
SPI = 'spi'
_1WIRE = '1wire'
RAW = 'raw'
BB = 'bb'
ADC = 'adc'
all_modes = ['i2c' , 'uart' , 'spi' , '1wire' , 'raw', 'bb']
all_modes_and_special = ['i2c' , 'uart' , 'spi' , '1wire' , 'raw', 'bb', 'adc']
not_bb = ['i2c' , 'uart' , 'spi' , '1wire' , 'raw']
class BBIO_base():
'''functions used in every mode, the base of class. Most of these you can
probably ignore, as they are just used in the other member classes
Note: Also contains some of the older functions that are now probably outdated
'''
def resetBP(self):
self.reset()
self.port.write("\x0F")
self.timeout(.1)
#self.port.read(2000)
self.port.flushInput()
self.mode = None
return 1
def check_mode(self, chkmode):
if self.mode not in chkmode:
raise ValueError('attempt to run {0} protocol when the bus pirate is not in {0} mode'.format(chkmode))
return 1
def timeout(self, timeout = 0.1):
sleep(timeout)
#select.select([], [], [], timeout)
def response(self, byte_count = 1, return_data = False):
'''request a number of bytes and whether you want the data itself. If it receives a
'1' then it returns a 1 ('1' is the std bus pirate response for most functions)'''
data = self.port.read(byte_count)
if byte_count == 1 and return_data == False:
if data == chr(0x01): return 1
else: return None
else:
return data
def cfg_pins(self, pins = 0):
'''used in every mode to configure pins. In bb it configures as either input or output,
in the other modes it normally configures peripherals such as power supply and the aux pin'''
self.check_mode(all_modes)
self.port.write(chr(0x40 | pins))
self.timeout(self.minDelay * 10)
return self.response(1, True)
def set_pins_bb(self, pins):
'''same as raw_set_pins, except it returns the value it obtains.
Necessary to read values in bb mode. Can be used instead of
the raw one if you want to know the output'''
self.check_mode(all_modes_and_special)
self.port.write(chr(0x80 | pins))
self.timeout(self.minDelay)
return self.response(1, True)
_attempts_ = 0
def recurse_end(self):
self._attempts_ = 0
def recurse(self, function, *args):
if self._attempts_ < 15:
self._attempts_ += 1
return function(*args)
raise IOError('bus pirate malfunctioning')
def recurse_flush(self, function, *args):
if self._attempts_ < 15:
self._attempts_ += 1
for n in range(5):
self.port.write('\x00')
self.port.flushInput()
return function(*args)
raise IOError('bus pirate malfunctioning')
# Self Tests
def short_selftest(self):
self.check_mode('bb')
self.port.write("\x10")
self.timeout(self.minDelay * 10)
return self.response(1, True)
def long_selftest(self):
self.check_mode('bb')
self.port.write("\x11")
self.timeout(self.minDelay * 10)
return self.response(1, True)
# PWM control
def setup_PWM(self, prescaler, dutycycle, period):
self.check_mode('bb')
self.port.write("\x12")
self.port.write(chr(prescaler))
self.port.write(chr((dutycycle >> 8) & 0xFF))
self.port.write(chr(dutycycle & 0xFF))
self.port.write(chr((period >> 8) & 0xFF))
self.port.write(chr(period & 0xFF))
self.timeout(self.minDelay * 10)
return self.response()
# ADC control
def ADC_measure(self):
self.check_mode('bb')
self.port.write("\x14")
self.timeout(self.minDelay)
return self.response(2, True)
def mode_string(self):
self.port.write("\x01")
self.timeout(self.minDelay * 10)
return self.response()
'''unused legacy code or code I'm not so sure of...'''
def raw_set_pins(self, pins):
'''kept in for legacy purposes, but not used or recomended'''
self.check_mode('raw')
self.port.write(chr(0x80 | pins))
self.timeout(self.minDelay)
return self.response(1)
def raw_cfg_pins(self, config):
'''practically identical to cfg_pins except it returns a different value'''
self.port.write(chr(0x40 | config))
self.timeout(self.minDelay * 10)
return self.response(1)
def read_pins(self):
'''I'm not sure what this is used for. I can't find reference to the command 0x50'''
self.port.write("\x50")
self.timeout(self.minDelay)
return self.response(1, True)
def read_speed(self):
'''I don't see reference to this in the documentation, but it was in the old pyBusPirateLite
so I'm leaving it in.'''
self.port.write("\x70")
select.select(None, None, None, 0.1)
return self.response(1, True)
def reset(self):
'''I would recommend not using this. Use enter_bb instead. Kept and NOT UPDTADED
if people are using old code they should probably change their code :D'''
self.port.write("\x00")
self.timeout(self.minDelay * 10)
self.mode = 'bb'
# These commands are very strange, because you can also influence the cs
# pin through the configuration register. Additional testing needed.
# These commands MAY OR MAY NOT BE SUPPORTED.
# They should keep track of everything though, so please
# test these and report if they work! (also test set_pin('cs') :D
def cs_low(self):
self.check_mode(['raw', 'spi'])
self.bp_port &= ~0b01
self.port.write("\x04")
self.timeout(0.1)
return self.response(1)
def cs_high(self):
self.check_mode(['raw', 'spi'])
self.bp_port |= 0b01
self.port.write("\x05")
self.timeout(0.1)
return self.response(1)
def BBmode(self):
return self.enter_bb()
def enter_SPI(self):
return self.enter_spi()
def enter_I2C(self):
return self.enter_i2c()
def enter_UART(self):
return self.enter_uart()
def clear_PWM(self):
return self.clear_pwm()
'''Testing Functions. Use these to do some simple pin testing or port testing'''
def pin_test(bp_device, *pins):
#pin dir testing
print 'config', bp_device.configure_peripherals(power = 'ON', pullups = 'on')
bp_device.set_port(0)
bp_device.set_dir(0)
raw_input('pin testing. All pins (except the tested pin) set to inputs and values changed\nto zero, press enter when ready')
for pin in pins:
bp_device.set_pin_dir(pin, 'out')
for n in range(5): #do full loop 5 times
raw_input('changing %s to 1, press enter' % pin)
print 'error checking:', bp_device.set_pin(pin)
print 'adc currently reads', bp_device.get_adc_voltage(), 'volts'
raw_input('now setting output to 0, press enter')
print 'error checking:', bp_device.clear_pin(pin)
print 'adc currently reads', bp_device.get_adc_voltage(), 'volts'
raw_input('changing dir to input. press enter for next pin')
bp_device.set_pin_dir(pin, 'in')
raw_input('press enter for next')
def pin_dir_test(bp_device, *pins):
'''This shows the strange occurence that the port is apparently reseting
whenever you change the directions (and reseting to output no less). Put
a 5V pullup resistor on the pin and run this to see the effect'''
#pin dir testing
print 'config', bp_device.configure_peripherals(power = 'ON', pullups = 'on')
bp_device.set_port(0)
bp_device.set_dir(0x1F)
raw_input('pin direction testing. All pins set to inputs and values changed\nto zero, press enter when ready')
for pin in pins:
for n in range(5): #do full loop 5 times
raw_input('changing %s direction to output, press enter' % pin)
print 'error checking:', bp_device.set_pin_dir(pin, 'out')
print 'adc currently reads', bp_device.get_adc_voltage(), 'volts'
raw_input('now setting output to 0, press enter')
print 'error checking:', bp_device.clear_pin(pin)
print 'adc currently reads', bp_device.get_adc_voltage(), 'volts'
raw_input('changing %s direction to input, press enter' % pin)
print 'error checking:', bp_device.set_pin_dir(pin, 'in')
print 'adc currently reads', bp_device.get_adc_voltage(), 'volts'
raw_input('now setting output to 0, press enter')
print 'error checking:', bp_device.clear_pin(pin)
print 'adc currently reads', bp_device.get_adc_voltage(), 'volts'
raw_input('press enter for next')
def port_test(bp_device, port, std_port = 0b00000):
'''change the port to 0 or 1. Works similiar to a microcontroller'''
print 'config', bp_device.configure_peripherals(power = 'ON', pullups = 'on')
bp_device.set_port(std_port)
bp_device.set_dir(0)
raw_input('port testing. All pins outputs and at %s. press enter when ready' % bin(std_port))
for n in range(5): #do full loop 5 times
raw_input('changing port to %s, press enter' % bin(~port & std_port))
print 'error checking:', bp_device.set_port(~port & std_port)
print 'adc currently reads', bp_device.get_adc_voltage(), 'volts'
raw_input('changing port to %s, press enter' % bin(port | std_port))
print 'error checking:', bp_device.set_port(port | std_port)
print 'adc currently reads', bp_device.get_adc_voltage(), 'volts'
raw_input('press enter for next')
def pwm_test(bp_device):
bp_device.set_pin_dir('aux', 'out')
bp_device.set_pwm_frequency(1000)
raw_input('press enter to continue')
def integrity_error():
raise ValueError('failed the integrity test here')
def integrity_test(bp_device, test_repeat = 10):
'''to do a code integrity test connect CS to MISO and CLK to MOSI.
Also connect the ADC to either 3 or 5V . AUX pin not currently tested
(but it works... trust me :D )'''
print 'starting integrity tests'
print 'testing mode switching'
for n in range(test_repeat):
if not bp_device.enter_bb(): integrity_error()
if not bp_device.enter_i2c(): integrity_error()
if not bp_device.enter_bb(): integrity_error()
if not bp_device.enter_spi(): integrity_error()
if not bp_device.enter_bb(): integrity_error()
if not bp_device.enter_1wire(): integrity_error()
if not bp_device.enter_bb(): integrity_error()
if not bp_device.enter_uart(): integrity_error()
if not bp_device.enter_bb(): integrity_error()
if not bp_device.enter_rawwire(): integrity_error()
if not bp_device.enter_bb(): integrity_error()
print 'mode switching: OK'
print 'checking adc'
for n in range(test_repeat):
if not bp_device.configure_peripherals(power = 'on', pullups = 'on'): integrity_error()
if not bp_device.start_getting_adc_voltages(): integrity_error()
for n in range(1000):
if bp_device.get_next_adc_voltage() < 2: integrity_error()
if not bp_device.stop_getting_adc_voltages(): integrity_error()
if not bp_device.enter_bb(): integrity_error()
if not bp_device.configure_peripherals(power = 'off'): integrity_error()
voltage_drop = []
for n in range(10):
voltage_drop.append(bp_device.get_adc_voltage())
if bp_device.get_adc_voltage() > 0.3: integrity_error()
print "notice that the voltage drops steadily. This is the power source turning off"
print voltage_drop
print 'adc: ok'
print 'pin and port testing'
for n in range(test_repeat):
#first test x1x1
if not bp_device.set_dir(0b11010): integrity_error()
if not bp_device.set_port(0b00101): integrity_error()
if bp_device.read_port() & 0b00101 != 0b00101: integrity_error()
#now test x0x0
if not bp_device.set_dir(0b11010): integrity_error()
if not bp_device.set_port(0b00000): integrity_error()
if bp_device.read_port() & 0b00000 != 0b00000: integrity_error()
# now test 1x1x
if not bp_device.set_dir(0b10101): integrity_error()
if not bp_device.set_port(0b01010): integrity_error()
if bp_device.read_port() & 0b01010 != 0b01010: integrity_error()
# now test 0x0x
if not bp_device.set_dir(0b10101): integrity_error()
if not bp_device.set_port(0b0000): integrity_error()
if bp_device.read_port() & 0b00000 != 0b00000: integrity_error()
if not bp_device.set_dir(0x1F): integrity_error()
# now do pin testing
for pins in (('miso', 'cs') , ('mosi', 'clk')):
if not bp_device.set_pin_dir(pins[0], 'in'): integrity_error()
if not bp_device.set_pin_dir(pins[1], 'out'): integrity_error()
if not bp_device.set_pin(pins[1]): integrity_error()
if bp_device.read_pin(pins[0]) != 1: integrity_error()
if not bp_device.clear_pin(pins[1]): integrity_error()
if bp_device.read_pin(pins[0]) != 0: integrity_error()
if not bp_device.set_pin_dir(pins[1], 'in'): integrity_error()
if not bp_device.set_pin_dir(pins[0], 'out'): integrity_error()
if not bp_device.set_pin(pins[0]): integrity_error()
if bp_device.read_pin(pins[1]) != 1: integrity_error()
if not bp_device.clear_pin(pins[0]): integrity_error()
if bp_device.read_pin(pins[1]) != 0: integrity_error()
print 'pins and port testing: OK'
print 'still to do: pin and port testing in other modes.'
# may use these instead of all the longer recursion statements eventually
#_atempts_ = 0
count = 0
if __name__ == '__main__':
print 'nothing here'
#!/usr/bin/env python
# encoding: utf-8
"""
Created by Sean Nelson on 2009-10-14.
Copyright 2009 Sean Nelson <audiohacked@gmail.com>
Overhauled and edited by Garrett Berg on 2011- 1 - 22
Copyright 2011 Garrett Berg <cloudform511@gmail.com>
pyBusPirate is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pyBusPirate 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.
You should have received a copy of the GNU General Public License
along with pyBusPirate. If not, see <http://www.gnu.org/licenses/>.
"""
import select
import serial
import sys
try:
from .BBIO_base import *
except ValueError:
from BBIO_base import *
"""
PICSPEED = 24MHZ / 16MIPS
"""
'''pinout_uc prior to translating be careful, you have to translate this
when you use it!!! (only wory about this if you are developing code for the editing
this class)'''
pinout_bb = {'AUX': 0b10000,
'MOSI': 0b01000,
'CLK': 0b00100,
'MISO': 0b00010,
'CS': 0b00001}
def translator(byte, translate):
'''translates a byte so that the pinout is more user friendly (for the standard connector
orientation)'''
if translate == True:
'''maps AUX|MOSI|CLK|MISO|CS to AUX|CLK|MOSI|CS|MISO'''
if byte > 255: raise ValueError('Value Too Large')
return (byte & 0b11110000) | ((byte & 0b0101) << 1) | ((byte & 0b1010) >> 1)
else:
return byte
'''if transltor (self.t) is True then pinout is AUX|CLK|MOSI|CS|MISO
if translator is False then: AUX|MOSI|CLK|MISO|CS
The first is much more user friendly, the second is the order the
bus pirate uses (and expects)
the values in self.uc_port and self.uc_dir are the values you **want**,
i.e. if you have translate on then they will read AUX|CLK|MOSI|CS|MISO
'''
class BBIO(BBIO_base):
def __init__(self):
# MAJOR CHANGE: If you are re-using old code,
# you must nowconnect to device by calling
# the connect() function below. There is no automatic connection
self.connected = False
self.mode = None
self.t = True
def connect(self, p = "/dev/bus_pirate", s = 115200, t_out = 1):
''' will try to automatically find a port regarless of os (to be added)'''
try:
self.port = serial.Serial(p, s, timeout = t_out)
except serial.serialutil.SerialException:
return 0
self.connected = True
self.minDelay = 1 / s
return 1
_attempts_ = 0 # global stored for use in enter_bb
def enter_bb(self):
'''this is the be-all-end-all restart function. It will keep trying
to get the bus pirate into bit bang mode even if it is stuck. Call this
to get the bus pirate into a known state (bb mode)'''
if self.connected is not True:
return 0 # still need to connect to port
self.port.flushInput()
for i in range(20):
self.port.write("\x00")
#r, w, e = select.select([self.port], [], [], 0.01)
r = self.response(1, True)
if (r): break
self.port.flushInput()
self.port.write('\x00')
if self.response(5, True) == "BBIO1":
self.mode = 'bb'
self.bp_config = 0x00 # configuration bits determine action of power sources and pullups
self.bp_port = 0x00 # out_port similar to ports in microcontrollers
self.bp_dir = 0x1F # direction port similar to microchip microcontrollers. (1) is input, (0) is output
self.recurse_end()
return 1
return self.recurse_flush(self.enter_bb)
'''calls to be used only in bit bang mode'''
def enter_spi(self):
self.check_mode('bb')
self.port.write("\x01")
self.timeout(self.minDelay * 10)
if self.response(4) == "SPI1":
self.mode = 'spi'
self.bp_port = 0b00 # two bit port
self.bp_config = 0b0000
self.recurse_end()
return 1
return self.recurse_flush(self.enter_spi)
def enter_i2c(self):
self.check_mode('bb')
self.port.write("\x02")
self.timeout(self.minDelay * 10)
if self.response(4) == "I2C1":
self.mode = 'i2c'
self.bp_port = 0b00 # two bit port
self.bp_config = 0b0000
self.recurse_end()
return 1
return self.recurse_flush(self.enter_i2c)
def enter_uart(self):
self.check_mode('bb')
self.port.write("\x03")
self.timeout(self.minDelay * 10)
if self.response(4) == "ART1":
self.mode = 'uart'
self.bp_port = 0b00 # two bit port
self.bp_config = 0b0000
self.recurse_end()
return 1
return self.recurse_flush(self.enter_uart)
def enter_1wire(self):
self.check_mode('bb')
self.port.write("\x04")
self.timeout(self.minDelay * 10)
if self.response(4) == "1W01":
self.mode = '1wire'
self.bp_port = 0b00 # two bit port
self.bp_config = 0b0000
self._attempts_ = 1
return 1
return self.recurse_flush(self.enter_1wire)
def enter_rawwire(self):
self.check_mode('bb')
self.port.write("\x05")
self.timeout(self.minDelay * 10)
if self.response(4) == "RAW1":
self.mode = 'raw'
self.bp_port = 0b00 # two bit port
self.bp_config = 0b0000
self.recurse_end()
return 1
return self.recurse_flush(self.enter_rawwire)
def set_pwm_frequency(self, frequency, DutyCycle = .5):
'''set pwm frequency and duty cycle. Stolen from http://codepad.org/qtYpZmIF'''