Skip to content

Commit

Permalink
Merge pull request #6 from julianvilas/vendor-pyBusPirateLite-564d047
Browse files Browse the repository at this point in the history
Vendor pyBusPirateLite (commit: 564d047)
  • Loading branch information
julianvilas authored Jun 1, 2024
2 parents c71a1c4 + 1515873 commit a069846
Show file tree
Hide file tree
Showing 14 changed files with 2,075 additions and 8 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# bphelpers

`bphelpers` is a Python library and command-line interface (CLI) that provides high-level functions to interact with specific integrated circuits using the [Bus Pirate](http://dangerousprototypes.com/docs/Bus_Pirate).
`bphelpers` is a Python library that provides high-level functions to interact with specific integrated circuits using the [Bus Pirate](http://dangerousprototypes.com/docs/Bus_Pirate).
This library takes into account the particularities of the integrated circuits it interacts with.

This project built on top of [pyBusPirateLite](https://github.com/juhasch/pyBusPirateLite), and we would like to give credit to the original authors and contributors of pyBusPirateLite and pyBusPirate.
This project is built on top of [pyBusPirateLite](https://github.com/juhasch/pyBusPirateLite), and we would like to give credit to the original authors and contributors of pyBusPirateLite and pyBusPirate.

_NOTE: the pyBusPirateLite dependency is vendored from https://github.com/julianvilas/pyBusPirateLite/tree/new for convenience, as the original project does not seem to be maintained and it is not available in PyPI neither._
_The `new` branch in that fork contains commits not available in the original upstream, while `master` matches exactly the upstream (as of today)._

## Installation

Expand Down
2 changes: 1 addition & 1 deletion bphelpers/AT24CXXX.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pyBusPirateLite.I2C import I2C
from vendor.pyBusPirateLite.I2C import I2C

class AT24CXXX(I2C):
""" Adapted I2C methods for AT24128/256 EEPROMs """
Expand Down
14 changes: 9 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os

from setuptools import setup
from setuptools import setup, find_packages

def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
Expand All @@ -13,11 +13,15 @@ def read(fname):
license = "GPLv3",
keywords = "BusPirate",
url = "https://github.com/julianvilas/bphelpers",
packages=['bphelpers'],
# NOTE: the pyBusPirateLite dependency is vendored from
# https://github.com/julianvilas/pyBusPirateLite/tree/new for convenience,
# as the project does not seem to be maintained and it is not available in
# PyPI. Again many thanks to the original author!
packages=find_packages(),
install_requires=[
'pyserial',
],
long_description=read('README.md'),
# NOTE: for convenience the pyBusPirateLite dependency is installed from a
# forked repository as the original one is not updated
install_requires=['pyBusPirateLite @ https://github.com/julianvilas/pyBusPirateLite/tarball/master'],
classifiers=[
'Development Status :: 3 - Alpha',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
Expand Down
279 changes: 279 additions & 0 deletions vendor/pyBusPirateLite/BitBang.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
# 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/>.

from .base import BusPirate, ProtocolError


class BitBang(BusPirate):
""" Provide access to the Bus Pirate bitbang mode"""

def __init__(self, portname='', speed=115200, timeout=0.1, connect=True):
"""
This constructor by default conntects to the first buspirate it can
find. If you don't want that, set connect to False.
Parameters
----------
portname : str
Name of comport (/dev/bus_pirate or COM3)
speed : int
Communication speed, use default of 115200
timeout : int
Timeout in s to wait for reply
Examples
--------
>>> bb = BitBang()
"""
super().__init__(portname, speed, timeout, connect)

@property
def outputs(self):
"""
Returns
-------
byte
Current state of the pins
PIN_AUX, PIN_MOSI, PIN_CLK, PIN_MISO, PIN_CS
"""

self.write(0x40 | ~ self.pins_direction & 0x1f) # map input->1, output->0 **TODO**
self.timeout(self.minDelay * 10)
return ord(self.response(1, binary=True)) & 0x1f

@outputs.setter
def outputs(self, pinlist=0):
""" Configure pins as input our output
Notes
-----
The Bus pirate responds to each direction update with a byte showing the current state of the pins, regardless
of direction. This is useful for open collector I/O modes. 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
Parameters
----------
pinlist : byte
List of pins to be set as outputs (default: all inputs)
PIN_AUX, PIN_MOSI, PIN_CLK, PIN_MISO, PIN_CS
Returns
-------
byte
Current state of the pins
PIN_AUX, PIN_MOSI, PIN_CLK, PIN_MISO, PIN_CS
"""
self.pins_direction = pinlist & 0x1f
self.write(0x40 | ~ self.pins_direction & 0x1f) # map input->1, output->0
self.timeout(self.minDelay * 10)
self.response(1, binary=True)

@property
def pins(self):
""" Get pins status
Returns
-------
byte
Current state of the pins
PIN_POWER, PIN_PULLUP, PIN_AUX, PIN_MOSI, PIN_CLK, PIN_MISO, PIN_CS
"""
self.write(0x80 | (self.pins_state & 0x7f))
self.timeout(self.minDelay * 10)
self.pins_state = ord(self.response(1, binary=True)) & 0x7f
return self.pins_state

@pins.setter
def pins(self, pinlist=0):
""" Set pins to high or low
Notes
-----
The lower 7bits of the command byte control the Bus Pirate pins and peripherals.
Bitbang works like a player piano or bitmap. The Bus Pirate pins map to the bits in the command byte as follows:
1|POWER|PULLUP|AUX|MOSI|CLK|MISO|CS
The Bus pirate responds to each update with a byte in the same format that shows the current state of the pins.
Parameters
----------
pinlist : byte
List of pins to be set high
PIN_POWER, PIN_PULLUP, PIN_AUX, PIN_MOSI, PIN_CLK, PIN_MISO, PIN_CS
"""
self.pins_state = pinlist & 0x7f
self.write(0x80 | self.pins_state)
self.timeout(self.minDelay * 10)
self.pins_state = ord(self.response(1, binary=True)) & 0x7f

@property
def adc(self):
"""Returns the voltage from ADC pin
Returns
-------
float
Voltage measured at ADC pin
"""
self.write(0x14)
self.timeout(self.minDelay)
ret = self.response(2, binary=True)
voltage = (ret[0] << 8) + ret[1]
voltage = (voltage * 6.6) / 1024
return voltage

def start_getting_adc_voltages(self):
"""Start continuously getting adc voltages.
Notes
-----
use memberfunction enter_bb to exit,
use get_next_adc_voltage to get the next one.
"""
self.write(0x15)

def get_next_adc_voltage(self):
ret = self.response(2, binary=True)
voltage = (ret[0] << 8) + ret[1]
voltage = (voltage * 6.6) / 1024

if voltage < 10:
"""sometimes the input gets out of sync. This is the best error checking
currently available, firmware will probably be updated to expect a 101 or
something in the top byte, which will be better error checking"""
self.recurse_end()
return voltage

self.response(1, binary=True) # get an additional byte and then flush
self.port.flushInput()
return self.recurse(self.get_next_adc_voltage)

def stop_getting_adc_voltages(self):
"""I was encountering problems resetting out of adc mode, so I wrote this
little function"""
self.port.flushInput()
for i in range(5):
self.write(0x00)
#r, w, e = select.select([self.port], [], [], 0.01);
r = self.response(1, binary=True)
if r: break;
self.port.flushInput()
self.enter_bb()
return 1

def selftest(self, complete=False):
""" Self test
Parameters
----------
complete: bool
Requires jumpers between +5 and Vpu, +3.3 and ADC
Notes
-----
Self-tests are access from the binary bitbang mode. There are actually two self-tests available. T
he full test is the same as self-test in the user terminal, it requires jumpers between two sets of pins
in order to test some features. The short test eliminates the six checks that require jumpers.
After the test is complete, the Bus Pirate responds with the number of errors. It also echoes any input plus
the number of errors. The MODE LED blinks if the test was successful, or remains solid if there were errors.
Exit the self-test by sending 0xff, the Bus Pirate will respond 0x01 and return to binary bitbang mode.
Returns
-------
int
Number of errors
"""
self.port.flushInput()
if complete is True:
self.write(0x11)
else:
self.write(0x10)
self.timeout(1)
errors = self.response(1, binary=True)
self.write(0xff)
resp = self.response(1, binary=True)
if resp != b'\x01':
raise ProtocolError('Self test did not return to bitbang mode')
self.timeout(self.minDelay)
return ord(errors)

def enable_PWM(self, frequency, dutycycle=.5):
""" Enable PWM output
Parameters
----------
frequency: float
PWM frequency in Hz
dutycycle: float
Duty cycle between 0 (0%) and 1 (100%)
Notes
-----
Configure and enable pulse-width modulation output in the AUX pin. Requires a 5 byte configuration sequence.
Responds 0x01 after a complete sequence is received. The PWM remains active after leaving binary bitbang mode!
Equations to calculate the PWM frequency and period are in the PIC24F output compare manual.
Bit 0 and 1 of the first configuration byte set the prescaler value. The Next two bytes set the duty cycle
register, high 8bits first. The final two bytes set the period register, high 8bits first.
Parameter calculation stolen from http://codepad.org/qtYpZmIF
"""
if dutycycle > 1:
raise ValueError('Duty cycle should be between 0 and 1')
Fosc = 24e6
Tcy = 2.0 / Fosc
PwmPeriod = 1.0 / frequency

# find needed prescaler
PrescalerList = {0: 1, 1: 8, 2: 64, 3: 256}

for n in range(4):
Prescaler = PrescalerList[n]
PRy = PwmPeriod * 1.0 / (Tcy * Prescaler)
PRy = int(PRy - 1)
OCR = int(PRy * dutycycle)

if PRy < (2 ** 16 - 1):
break # valid value for PRy, keep values
else:
raise ValueError('frequency requested is invalid')

prescaler = Prescaler
dutycycle = OCR
period = PRy

self.write(0x12)
self.write(prescaler)
self.write((dutycycle >> 8) & 0xFF)
self.write(dutycycle & 0xFF)
self.write((period >> 8) & 0xFF)
self.write(period & 0xFF)
self.timeout(self.minDelay * 10)
if self.response(1, binary=True) != b'\x01':
raise ValueError("Could not setup PWM mode")

def disable_PWM(self):
""" Clear/disable PWM """
self.write(0x13)
self.timeout(self.minDelay * 10)
if self.response(1, binary=True) != b'\x01':
raise ValueError("Could not disable PWM mode")
Loading

0 comments on commit a069846

Please sign in to comment.