mirror of
https://github.com/xtacocorex/CHIP_IO
synced 2025-07-20 04:43:21 +00:00
Initial commit, working GPIO for all available CHIP GPIO pins, have not tested edge detection and callbacks
This commit is contained in:
7
CHANGELOG.rst
Normal file
7
CHANGELOG.rst
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
0.0.4
|
||||||
|
____
|
||||||
|
* Initial Commit
|
||||||
|
* GPIO working - untested callback and edge detection
|
||||||
|
* Initial GPIO unit tests
|
||||||
|
|
||||||
|
|
0
CHIP_IO/__init__.py
Normal file
0
CHIP_IO/__init__.py
Normal file
19
Makefile
Normal file
19
Makefile
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
time:
|
||||||
|
/usr/bin/ntpdate -b -s -u pool.ntp.org
|
||||||
|
|
||||||
|
publish: clean
|
||||||
|
python setup.py sdist upload
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf CHIP_IO.* build dist
|
||||||
|
rm -f *.pyo
|
||||||
|
rm -f *.egg
|
||||||
|
rm -f overlays/*.pyo overlays/*.pyc
|
||||||
|
tests:
|
||||||
|
py.test
|
||||||
|
|
||||||
|
build:
|
||||||
|
python setup.py build --force
|
||||||
|
|
||||||
|
install: build
|
||||||
|
python setup.py install --force
|
94
README.rst
Normal file
94
README.rst
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
# CHIP_IO
|
||||||
|
A CHIP GPIO library
|
||||||
|
|
||||||
|
Manual::
|
||||||
|
|
||||||
|
sudo ntpdate pool.ntp.org
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install build-essential python-dev python-pip -y
|
||||||
|
git clone git://github.com/xtacocorex/CHIP_IO.git
|
||||||
|
cd CHIP_IO
|
||||||
|
sudo python setup.py install
|
||||||
|
cd ..
|
||||||
|
sudo rm -rf CHIP_IO
|
||||||
|
|
||||||
|
**Usage**
|
||||||
|
|
||||||
|
Using the library is very similar to the excellent RPi.GPIO library used on the Raspberry Pi. Below are some examples.
|
||||||
|
|
||||||
|
**GPIO Setup**
|
||||||
|
|
||||||
|
Import the library, and setup as GPIO.OUT or GPIO.IN::
|
||||||
|
|
||||||
|
import CHIP_IO.GPIO as GPIO
|
||||||
|
GPIO.setup("CSID0", GPIO.OUT)
|
||||||
|
|
||||||
|
You can also refer to the pin number::
|
||||||
|
|
||||||
|
GPIO.setup("U14_31", GPIO.OUT)
|
||||||
|
|
||||||
|
**GPIO Output**
|
||||||
|
|
||||||
|
Setup the pin for output, and write GPIO.HIGH or GPIO.LOW. Or you can use 1 or 0.::
|
||||||
|
|
||||||
|
import CHIP_IO.GPIO as GPIO
|
||||||
|
GPIO.setup("CSID0", GPIO.OUT)
|
||||||
|
GPIO.output("CSID0", GPIO.HIGH)
|
||||||
|
|
||||||
|
**GPIO Input**
|
||||||
|
|
||||||
|
Inputs work similarly to outputs.::
|
||||||
|
|
||||||
|
import CHIP_IO.GPIO as GPIO
|
||||||
|
GPIO.setup("CSID0", GPIO.IN)
|
||||||
|
|
||||||
|
Polling inputs::
|
||||||
|
|
||||||
|
if GPIO.input("CSID0"):
|
||||||
|
print("HIGH")
|
||||||
|
else:
|
||||||
|
print("LOW")
|
||||||
|
|
||||||
|
Waiting for an edge (GPIO.RISING, GPIO.FALLING, or GPIO.BOTH::
|
||||||
|
|
||||||
|
GPIO.wait_for_edge(channel, GPIO.RISING)
|
||||||
|
|
||||||
|
Detecting events::
|
||||||
|
|
||||||
|
GPIO.add_event_detect("CSID0", GPIO.FALLING)
|
||||||
|
#your amazing code here
|
||||||
|
#detect wherever:
|
||||||
|
if GPIO.event_detected("CSID0"):
|
||||||
|
print "event detected!"
|
||||||
|
|
||||||
|
**PWM**::
|
||||||
|
|
||||||
|
Not implemented yet
|
||||||
|
|
||||||
|
**ADC**::
|
||||||
|
|
||||||
|
Not Implemented yet
|
||||||
|
|
||||||
|
**Running tests**
|
||||||
|
|
||||||
|
Install py.test to run the tests. You'll also need the python compiler package for py.test.::
|
||||||
|
|
||||||
|
opkg update && opkg install python-compiler
|
||||||
|
#Either pip or easy_install
|
||||||
|
pip install -U pytest
|
||||||
|
easy_install -U pytest
|
||||||
|
|
||||||
|
Execute the following in the root of the project::
|
||||||
|
|
||||||
|
py.test
|
||||||
|
|
||||||
|
**Credits**
|
||||||
|
|
||||||
|
The CHIP IO Python library was originally forked from the Adafruit Beaglebone IO Python Library.
|
||||||
|
The BeagleBone IO Python library was originally forked from the excellent MIT Licensed [RPi.GPIO](https://code.google.com/p/raspberry-gpio-python) library written by Ben Croston.
|
||||||
|
|
||||||
|
**License**
|
||||||
|
|
||||||
|
CHIP IO port by Robert Wolterman, released under the MIT License.
|
||||||
|
Beaglebone IO Library Written by Justin Cooper, Adafruit Industries. BeagleBone IO Python library is released under the MIT License.
|
||||||
|
|
556
distribute_setup.py
Normal file
556
distribute_setup.py
Normal file
@ -0,0 +1,556 @@
|
|||||||
|
#!python
|
||||||
|
"""Bootstrap distribute installation
|
||||||
|
|
||||||
|
If you want to use setuptools in your package's setup.py, just include this
|
||||||
|
file in the same directory with it, and add this to the top of your setup.py::
|
||||||
|
|
||||||
|
from distribute_setup import use_setuptools
|
||||||
|
use_setuptools()
|
||||||
|
|
||||||
|
If you want to require a specific version of setuptools, set a download
|
||||||
|
mirror, or use an alternate download directory, you can do so by supplying
|
||||||
|
the appropriate options to ``use_setuptools()``.
|
||||||
|
|
||||||
|
This file can also be run as a script to install or upgrade setuptools.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import fnmatch
|
||||||
|
import tempfile
|
||||||
|
import tarfile
|
||||||
|
import optparse
|
||||||
|
|
||||||
|
from distutils import log
|
||||||
|
|
||||||
|
try:
|
||||||
|
from site import USER_SITE
|
||||||
|
except ImportError:
|
||||||
|
USER_SITE = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
def _python_cmd(*args):
|
||||||
|
args = (sys.executable,) + args
|
||||||
|
return subprocess.call(args) == 0
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
# will be used for python 2.3
|
||||||
|
def _python_cmd(*args):
|
||||||
|
args = (sys.executable,) + args
|
||||||
|
# quoting arguments if windows
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
def quote(arg):
|
||||||
|
if ' ' in arg:
|
||||||
|
return '"%s"' % arg
|
||||||
|
return arg
|
||||||
|
args = [quote(arg) for arg in args]
|
||||||
|
return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
|
||||||
|
|
||||||
|
DEFAULT_VERSION = "0.0.1"
|
||||||
|
DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
|
||||||
|
SETUPTOOLS_FAKED_VERSION = "0.6c11"
|
||||||
|
|
||||||
|
SETUPTOOLS_PKG_INFO = """\
|
||||||
|
Metadata-Version: 1.0
|
||||||
|
Name: setuptools
|
||||||
|
Version: %s
|
||||||
|
Summary: xxxx
|
||||||
|
Home-page: xxx
|
||||||
|
Author: xxx
|
||||||
|
Author-email: xxx
|
||||||
|
License: xxx
|
||||||
|
Description: xxx
|
||||||
|
""" % SETUPTOOLS_FAKED_VERSION
|
||||||
|
|
||||||
|
|
||||||
|
def _install(tarball, install_args=()):
|
||||||
|
# extracting the tarball
|
||||||
|
tmpdir = tempfile.mkdtemp()
|
||||||
|
log.warn('Extracting in %s', tmpdir)
|
||||||
|
old_wd = os.getcwd()
|
||||||
|
try:
|
||||||
|
os.chdir(tmpdir)
|
||||||
|
tar = tarfile.open(tarball)
|
||||||
|
_extractall(tar)
|
||||||
|
tar.close()
|
||||||
|
|
||||||
|
# going in the directory
|
||||||
|
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
|
||||||
|
os.chdir(subdir)
|
||||||
|
log.warn('Now working in %s', subdir)
|
||||||
|
|
||||||
|
# installing
|
||||||
|
log.warn('Installing Distribute')
|
||||||
|
if not _python_cmd('setup.py', 'install', *install_args):
|
||||||
|
log.warn('Something went wrong during the installation.')
|
||||||
|
log.warn('See the error message above.')
|
||||||
|
# exitcode will be 2
|
||||||
|
return 2
|
||||||
|
finally:
|
||||||
|
os.chdir(old_wd)
|
||||||
|
shutil.rmtree(tmpdir)
|
||||||
|
|
||||||
|
|
||||||
|
def _build_egg(egg, tarball, to_dir):
|
||||||
|
# extracting the tarball
|
||||||
|
tmpdir = tempfile.mkdtemp()
|
||||||
|
log.warn('Extracting in %s', tmpdir)
|
||||||
|
old_wd = os.getcwd()
|
||||||
|
try:
|
||||||
|
os.chdir(tmpdir)
|
||||||
|
tar = tarfile.open(tarball)
|
||||||
|
_extractall(tar)
|
||||||
|
tar.close()
|
||||||
|
|
||||||
|
# going in the directory
|
||||||
|
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
|
||||||
|
os.chdir(subdir)
|
||||||
|
log.warn('Now working in %s', subdir)
|
||||||
|
|
||||||
|
# building an egg
|
||||||
|
log.warn('Building a Distribute egg in %s', to_dir)
|
||||||
|
_python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
os.chdir(old_wd)
|
||||||
|
shutil.rmtree(tmpdir)
|
||||||
|
# returning the result
|
||||||
|
log.warn(egg)
|
||||||
|
if not os.path.exists(egg):
|
||||||
|
raise IOError('Could not build the egg.')
|
||||||
|
|
||||||
|
|
||||||
|
def _do_download(version, download_base, to_dir, download_delay):
|
||||||
|
egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
|
||||||
|
% (version, sys.version_info[0], sys.version_info[1]))
|
||||||
|
if not os.path.exists(egg):
|
||||||
|
tarball = download_setuptools(version, download_base,
|
||||||
|
to_dir, download_delay)
|
||||||
|
_build_egg(egg, tarball, to_dir)
|
||||||
|
sys.path.insert(0, egg)
|
||||||
|
import setuptools
|
||||||
|
setuptools.bootstrap_install_from = egg
|
||||||
|
|
||||||
|
|
||||||
|
def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
|
||||||
|
to_dir=os.curdir, download_delay=15, no_fake=True):
|
||||||
|
# making sure we use the absolute path
|
||||||
|
to_dir = os.path.abspath(to_dir)
|
||||||
|
was_imported = 'pkg_resources' in sys.modules or \
|
||||||
|
'setuptools' in sys.modules
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
import pkg_resources
|
||||||
|
|
||||||
|
# Setuptools 0.7b and later is a suitable (and preferable)
|
||||||
|
# substitute for any Distribute version.
|
||||||
|
try:
|
||||||
|
pkg_resources.require("setuptools>=0.7b")
|
||||||
|
return
|
||||||
|
except (pkg_resources.DistributionNotFound,
|
||||||
|
pkg_resources.VersionConflict):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not hasattr(pkg_resources, '_distribute'):
|
||||||
|
if not no_fake:
|
||||||
|
_fake_setuptools()
|
||||||
|
raise ImportError
|
||||||
|
except ImportError:
|
||||||
|
return _do_download(version, download_base, to_dir, download_delay)
|
||||||
|
try:
|
||||||
|
pkg_resources.require("distribute>=" + version)
|
||||||
|
return
|
||||||
|
except pkg_resources.VersionConflict:
|
||||||
|
e = sys.exc_info()[1]
|
||||||
|
if was_imported:
|
||||||
|
sys.stderr.write(
|
||||||
|
"The required version of distribute (>=%s) is not available,\n"
|
||||||
|
"and can't be installed while this script is running. Please\n"
|
||||||
|
"install a more recent version first, using\n"
|
||||||
|
"'easy_install -U distribute'."
|
||||||
|
"\n\n(Currently using %r)\n" % (version, e.args[0]))
|
||||||
|
sys.exit(2)
|
||||||
|
else:
|
||||||
|
del pkg_resources, sys.modules['pkg_resources'] # reload ok
|
||||||
|
return _do_download(version, download_base, to_dir,
|
||||||
|
download_delay)
|
||||||
|
except pkg_resources.DistributionNotFound:
|
||||||
|
return _do_download(version, download_base, to_dir,
|
||||||
|
download_delay)
|
||||||
|
finally:
|
||||||
|
if not no_fake:
|
||||||
|
_create_fake_setuptools_pkg_info(to_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
|
||||||
|
to_dir=os.curdir, delay=15):
|
||||||
|
"""Download distribute from a specified location and return its filename
|
||||||
|
|
||||||
|
`version` should be a valid distribute version number that is available
|
||||||
|
as an egg for download under the `download_base` URL (which should end
|
||||||
|
with a '/'). `to_dir` is the directory where the egg will be downloaded.
|
||||||
|
`delay` is the number of seconds to pause before an actual download
|
||||||
|
attempt.
|
||||||
|
"""
|
||||||
|
# making sure we use the absolute path
|
||||||
|
to_dir = os.path.abspath(to_dir)
|
||||||
|
try:
|
||||||
|
from urllib.request import urlopen
|
||||||
|
except ImportError:
|
||||||
|
from urllib2 import urlopen
|
||||||
|
tgz_name = "distribute-%s.tar.gz" % version
|
||||||
|
url = download_base + tgz_name
|
||||||
|
saveto = os.path.join(to_dir, tgz_name)
|
||||||
|
src = dst = None
|
||||||
|
if not os.path.exists(saveto): # Avoid repeated downloads
|
||||||
|
try:
|
||||||
|
log.warn("Downloading %s", url)
|
||||||
|
src = urlopen(url)
|
||||||
|
# Read/write all in one block, so we don't create a corrupt file
|
||||||
|
# if the download is interrupted.
|
||||||
|
data = src.read()
|
||||||
|
dst = open(saveto, "wb")
|
||||||
|
dst.write(data)
|
||||||
|
finally:
|
||||||
|
if src:
|
||||||
|
src.close()
|
||||||
|
if dst:
|
||||||
|
dst.close()
|
||||||
|
return os.path.realpath(saveto)
|
||||||
|
|
||||||
|
|
||||||
|
def _no_sandbox(function):
|
||||||
|
def __no_sandbox(*args, **kw):
|
||||||
|
try:
|
||||||
|
from setuptools.sandbox import DirectorySandbox
|
||||||
|
if not hasattr(DirectorySandbox, '_old'):
|
||||||
|
def violation(*args):
|
||||||
|
pass
|
||||||
|
DirectorySandbox._old = DirectorySandbox._violation
|
||||||
|
DirectorySandbox._violation = violation
|
||||||
|
patched = True
|
||||||
|
else:
|
||||||
|
patched = False
|
||||||
|
except ImportError:
|
||||||
|
patched = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
return function(*args, **kw)
|
||||||
|
finally:
|
||||||
|
if patched:
|
||||||
|
DirectorySandbox._violation = DirectorySandbox._old
|
||||||
|
del DirectorySandbox._old
|
||||||
|
|
||||||
|
return __no_sandbox
|
||||||
|
|
||||||
|
|
||||||
|
def _patch_file(path, content):
|
||||||
|
"""Will backup the file then patch it"""
|
||||||
|
f = open(path)
|
||||||
|
existing_content = f.read()
|
||||||
|
f.close()
|
||||||
|
if existing_content == content:
|
||||||
|
# already patched
|
||||||
|
log.warn('Already patched.')
|
||||||
|
return False
|
||||||
|
log.warn('Patching...')
|
||||||
|
_rename_path(path)
|
||||||
|
f = open(path, 'w')
|
||||||
|
try:
|
||||||
|
f.write(content)
|
||||||
|
finally:
|
||||||
|
f.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
_patch_file = _no_sandbox(_patch_file)
|
||||||
|
|
||||||
|
|
||||||
|
def _same_content(path, content):
|
||||||
|
f = open(path)
|
||||||
|
existing_content = f.read()
|
||||||
|
f.close()
|
||||||
|
return existing_content == content
|
||||||
|
|
||||||
|
|
||||||
|
def _rename_path(path):
|
||||||
|
new_name = path + '.OLD.%s' % time.time()
|
||||||
|
log.warn('Renaming %s to %s', path, new_name)
|
||||||
|
os.rename(path, new_name)
|
||||||
|
return new_name
|
||||||
|
|
||||||
|
|
||||||
|
def _remove_flat_installation(placeholder):
|
||||||
|
if not os.path.isdir(placeholder):
|
||||||
|
log.warn('Unkown installation at %s', placeholder)
|
||||||
|
return False
|
||||||
|
found = False
|
||||||
|
for file in os.listdir(placeholder):
|
||||||
|
if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
if not found:
|
||||||
|
log.warn('Could not locate setuptools*.egg-info')
|
||||||
|
return
|
||||||
|
|
||||||
|
log.warn('Moving elements out of the way...')
|
||||||
|
pkg_info = os.path.join(placeholder, file)
|
||||||
|
if os.path.isdir(pkg_info):
|
||||||
|
patched = _patch_egg_dir(pkg_info)
|
||||||
|
else:
|
||||||
|
patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
|
||||||
|
|
||||||
|
if not patched:
|
||||||
|
log.warn('%s already patched.', pkg_info)
|
||||||
|
return False
|
||||||
|
# now let's move the files out of the way
|
||||||
|
for element in ('setuptools', 'pkg_resources.py', 'site.py'):
|
||||||
|
element = os.path.join(placeholder, element)
|
||||||
|
if os.path.exists(element):
|
||||||
|
_rename_path(element)
|
||||||
|
else:
|
||||||
|
log.warn('Could not find the %s element of the '
|
||||||
|
'Setuptools distribution', element)
|
||||||
|
return True
|
||||||
|
|
||||||
|
_remove_flat_installation = _no_sandbox(_remove_flat_installation)
|
||||||
|
|
||||||
|
|
||||||
|
def _after_install(dist):
|
||||||
|
log.warn('After install bootstrap.')
|
||||||
|
placeholder = dist.get_command_obj('install').install_purelib
|
||||||
|
_create_fake_setuptools_pkg_info(placeholder)
|
||||||
|
|
||||||
|
|
||||||
|
def _create_fake_setuptools_pkg_info(placeholder):
|
||||||
|
if not placeholder or not os.path.exists(placeholder):
|
||||||
|
log.warn('Could not find the install location')
|
||||||
|
return
|
||||||
|
pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
|
||||||
|
setuptools_file = 'setuptools-%s-py%s.egg-info' % \
|
||||||
|
(SETUPTOOLS_FAKED_VERSION, pyver)
|
||||||
|
pkg_info = os.path.join(placeholder, setuptools_file)
|
||||||
|
if os.path.exists(pkg_info):
|
||||||
|
log.warn('%s already exists', pkg_info)
|
||||||
|
return
|
||||||
|
|
||||||
|
log.warn('Creating %s', pkg_info)
|
||||||
|
try:
|
||||||
|
f = open(pkg_info, 'w')
|
||||||
|
except EnvironmentError:
|
||||||
|
log.warn("Don't have permissions to write %s, skipping", pkg_info)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
f.write(SETUPTOOLS_PKG_INFO)
|
||||||
|
finally:
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
pth_file = os.path.join(placeholder, 'setuptools.pth')
|
||||||
|
log.warn('Creating %s', pth_file)
|
||||||
|
f = open(pth_file, 'w')
|
||||||
|
try:
|
||||||
|
f.write(os.path.join(os.curdir, setuptools_file))
|
||||||
|
finally:
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
_create_fake_setuptools_pkg_info = _no_sandbox(
|
||||||
|
_create_fake_setuptools_pkg_info
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _patch_egg_dir(path):
|
||||||
|
# let's check if it's already patched
|
||||||
|
pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
|
||||||
|
if os.path.exists(pkg_info):
|
||||||
|
if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
|
||||||
|
log.warn('%s already patched.', pkg_info)
|
||||||
|
return False
|
||||||
|
_rename_path(path)
|
||||||
|
os.mkdir(path)
|
||||||
|
os.mkdir(os.path.join(path, 'EGG-INFO'))
|
||||||
|
pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
|
||||||
|
f = open(pkg_info, 'w')
|
||||||
|
try:
|
||||||
|
f.write(SETUPTOOLS_PKG_INFO)
|
||||||
|
finally:
|
||||||
|
f.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
_patch_egg_dir = _no_sandbox(_patch_egg_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def _before_install():
|
||||||
|
log.warn('Before install bootstrap.')
|
||||||
|
_fake_setuptools()
|
||||||
|
|
||||||
|
|
||||||
|
def _under_prefix(location):
|
||||||
|
if 'install' not in sys.argv:
|
||||||
|
return True
|
||||||
|
args = sys.argv[sys.argv.index('install') + 1:]
|
||||||
|
for index, arg in enumerate(args):
|
||||||
|
for option in ('--root', '--prefix'):
|
||||||
|
if arg.startswith('%s=' % option):
|
||||||
|
top_dir = arg.split('root=')[-1]
|
||||||
|
return location.startswith(top_dir)
|
||||||
|
elif arg == option:
|
||||||
|
if len(args) > index:
|
||||||
|
top_dir = args[index + 1]
|
||||||
|
return location.startswith(top_dir)
|
||||||
|
if arg == '--user' and USER_SITE is not None:
|
||||||
|
return location.startswith(USER_SITE)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _fake_setuptools():
|
||||||
|
log.warn('Scanning installed packages')
|
||||||
|
try:
|
||||||
|
import pkg_resources
|
||||||
|
except ImportError:
|
||||||
|
# we're cool
|
||||||
|
log.warn('Setuptools or Distribute does not seem to be installed.')
|
||||||
|
return
|
||||||
|
ws = pkg_resources.working_set
|
||||||
|
try:
|
||||||
|
setuptools_dist = ws.find(
|
||||||
|
pkg_resources.Requirement.parse('setuptools', replacement=False)
|
||||||
|
)
|
||||||
|
except TypeError:
|
||||||
|
# old distribute API
|
||||||
|
setuptools_dist = ws.find(
|
||||||
|
pkg_resources.Requirement.parse('setuptools')
|
||||||
|
)
|
||||||
|
|
||||||
|
if setuptools_dist is None:
|
||||||
|
log.warn('No setuptools distribution found')
|
||||||
|
return
|
||||||
|
# detecting if it was already faked
|
||||||
|
setuptools_location = setuptools_dist.location
|
||||||
|
log.warn('Setuptools installation detected at %s', setuptools_location)
|
||||||
|
|
||||||
|
# if --root or --preix was provided, and if
|
||||||
|
# setuptools is not located in them, we don't patch it
|
||||||
|
if not _under_prefix(setuptools_location):
|
||||||
|
log.warn('Not patching, --root or --prefix is installing Distribute'
|
||||||
|
' in another location')
|
||||||
|
return
|
||||||
|
|
||||||
|
# let's see if its an egg
|
||||||
|
if not setuptools_location.endswith('.egg'):
|
||||||
|
log.warn('Non-egg installation')
|
||||||
|
res = _remove_flat_installation(setuptools_location)
|
||||||
|
if not res:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
log.warn('Egg installation')
|
||||||
|
pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
|
||||||
|
if (os.path.exists(pkg_info) and
|
||||||
|
_same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
|
||||||
|
log.warn('Already patched.')
|
||||||
|
return
|
||||||
|
log.warn('Patching...')
|
||||||
|
# let's create a fake egg replacing setuptools one
|
||||||
|
res = _patch_egg_dir(setuptools_location)
|
||||||
|
if not res:
|
||||||
|
return
|
||||||
|
log.warn('Patching complete.')
|
||||||
|
_relaunch()
|
||||||
|
|
||||||
|
|
||||||
|
def _relaunch():
|
||||||
|
log.warn('Relaunching...')
|
||||||
|
# we have to relaunch the process
|
||||||
|
# pip marker to avoid a relaunch bug
|
||||||
|
_cmd1 = ['-c', 'install', '--single-version-externally-managed']
|
||||||
|
_cmd2 = ['-c', 'install', '--record']
|
||||||
|
if sys.argv[:3] == _cmd1 or sys.argv[:3] == _cmd2:
|
||||||
|
sys.argv[0] = 'setup.py'
|
||||||
|
args = [sys.executable] + sys.argv
|
||||||
|
sys.exit(subprocess.call(args))
|
||||||
|
|
||||||
|
|
||||||
|
def _extractall(self, path=".", members=None):
|
||||||
|
"""Extract all members from the archive to the current working
|
||||||
|
directory and set owner, modification time and permissions on
|
||||||
|
directories afterwards. `path' specifies a different directory
|
||||||
|
to extract to. `members' is optional and must be a subset of the
|
||||||
|
list returned by getmembers().
|
||||||
|
"""
|
||||||
|
import copy
|
||||||
|
import operator
|
||||||
|
from tarfile import ExtractError
|
||||||
|
directories = []
|
||||||
|
|
||||||
|
if members is None:
|
||||||
|
members = self
|
||||||
|
|
||||||
|
for tarinfo in members:
|
||||||
|
if tarinfo.isdir():
|
||||||
|
# Extract directories with a safe mode.
|
||||||
|
directories.append(tarinfo)
|
||||||
|
tarinfo = copy.copy(tarinfo)
|
||||||
|
tarinfo.mode = 448 # decimal for oct 0700
|
||||||
|
self.extract(tarinfo, path)
|
||||||
|
|
||||||
|
# Reverse sort directories.
|
||||||
|
if sys.version_info < (2, 4):
|
||||||
|
def sorter(dir1, dir2):
|
||||||
|
return cmp(dir1.name, dir2.name)
|
||||||
|
directories.sort(sorter)
|
||||||
|
directories.reverse()
|
||||||
|
else:
|
||||||
|
directories.sort(key=operator.attrgetter('name'), reverse=True)
|
||||||
|
|
||||||
|
# Set correct owner, mtime and filemode on directories.
|
||||||
|
for tarinfo in directories:
|
||||||
|
dirpath = os.path.join(path, tarinfo.name)
|
||||||
|
try:
|
||||||
|
self.chown(tarinfo, dirpath)
|
||||||
|
self.utime(tarinfo, dirpath)
|
||||||
|
self.chmod(tarinfo, dirpath)
|
||||||
|
except ExtractError:
|
||||||
|
e = sys.exc_info()[1]
|
||||||
|
if self.errorlevel > 1:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
self._dbg(1, "tarfile: %s" % e)
|
||||||
|
|
||||||
|
|
||||||
|
def _build_install_args(options):
|
||||||
|
"""
|
||||||
|
Build the arguments to 'python setup.py install' on the distribute package
|
||||||
|
"""
|
||||||
|
install_args = []
|
||||||
|
if options.user_install:
|
||||||
|
if sys.version_info < (2, 6):
|
||||||
|
log.warn("--user requires Python 2.6 or later")
|
||||||
|
raise SystemExit(1)
|
||||||
|
install_args.append('--user')
|
||||||
|
return install_args
|
||||||
|
|
||||||
|
def _parse_args():
|
||||||
|
"""
|
||||||
|
Parse the command line for options
|
||||||
|
"""
|
||||||
|
parser = optparse.OptionParser()
|
||||||
|
parser.add_option(
|
||||||
|
'--user', dest='user_install', action='store_true', default=False,
|
||||||
|
help='install in user site package (requires Python 2.6 or later)')
|
||||||
|
parser.add_option(
|
||||||
|
'--download-base', dest='download_base', metavar="URL",
|
||||||
|
default=DEFAULT_URL,
|
||||||
|
help='alternative URL from where to download the distribute package')
|
||||||
|
options, args = parser.parse_args()
|
||||||
|
# positional arguments are ignored
|
||||||
|
return options
|
||||||
|
|
||||||
|
def main(version=DEFAULT_VERSION):
|
||||||
|
"""Install or upgrade setuptools and EasyInstall"""
|
||||||
|
options = _parse_args()
|
||||||
|
tarball = download_setuptools(download_base=options.download_base)
|
||||||
|
return _install(tarball, _build_install_args(options))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
22
fix_py_compile.py
Normal file
22
fix_py_compile.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
# Some Angstrom images are missing the py_compile module; get it if not
|
||||||
|
# present:
|
||||||
|
# Fix credit:https://github.com/alexanderhiam/PyBBIO/blob/master/setup.py
|
||||||
|
import random, os
|
||||||
|
python_lib_path = random.__file__.split('random')[0]
|
||||||
|
if not os.path.exists(python_lib_path + 'py_compile.py'):
|
||||||
|
print "py_compile module missing; installing to %spy_compile.py" %\
|
||||||
|
python_lib_path
|
||||||
|
import urllib2
|
||||||
|
url = "http://hg.python.org/cpython/raw-file/4ebe1ede981e/Lib/py_compile.py"
|
||||||
|
py_compile = urllib2.urlopen(url)
|
||||||
|
with open(python_lib_path+'py_compile.py', 'w') as f:
|
||||||
|
f.write(py_compile.read())
|
||||||
|
print "testing py_compile..."
|
||||||
|
try:
|
||||||
|
import py_compile
|
||||||
|
print "py_compile installed successfully"
|
||||||
|
except Exception, e:
|
||||||
|
print "*py_compile install failed, could not import"
|
||||||
|
print "*Exception raised:"
|
||||||
|
raise e
|
36
setup.py
Normal file
36
setup.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
try:
|
||||||
|
from overlays import builder
|
||||||
|
builder.compile()
|
||||||
|
builder.copy()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
import distribute_setup
|
||||||
|
distribute_setup.use_setuptools()
|
||||||
|
from setuptools import setup, Extension, find_packages
|
||||||
|
|
||||||
|
classifiers = ['Development Status :: 3 - Alpha',
|
||||||
|
'Operating System :: POSIX :: Linux',
|
||||||
|
'License :: OSI Approved :: MIT License',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'Programming Language :: Python :: 2.7',
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
'Topic :: Software Development',
|
||||||
|
'Topic :: Home Automation',
|
||||||
|
'Topic :: System :: Hardware']
|
||||||
|
|
||||||
|
setup(name = 'CHIP_IO',
|
||||||
|
version = '0.0.2',
|
||||||
|
author = 'Robert Wolterman',
|
||||||
|
author_email = 'robert.wolterman@gmail.com',
|
||||||
|
description = 'A module to control CHIP IO channels',
|
||||||
|
long_description = open('README.rst').read() + open('CHANGELOG.rst').read(),
|
||||||
|
license = 'MIT',
|
||||||
|
keywords = 'CHIP NextThingCo IO GPIO PWM ADC',
|
||||||
|
url = 'https://github.com/xtacocorex/CHIP_IO/',
|
||||||
|
classifiers = classifiers,
|
||||||
|
packages = find_packages(),
|
||||||
|
ext_modules = [Extension('CHIP_IO.GPIO', ['source/py_gpio.c', 'source/event_gpio.c', 'source/constants.c', 'source/common.c'], extra_compile_args=['-Wno-format-security'])]) #,
|
||||||
|
# Extension('CHIP_IO.PWM', ['source/py_pwm.c', 'source/c_pwm.c', 'source/constants.c', 'source/common.c'], extra_compile_args=['-Wno-format-security']),
|
||||||
|
# Extension('CHIP_IO.ADC', ['source/py_adc.c', 'source/c_adc.c', 'source/constants.c', 'source/common.c'], extra_compile_args=['-Wno-format-security']),
|
||||||
|
# Extension('CHIP_IO.SPI', ['source/spimodule.c', 'source/constants.c', 'source/common.c'], extra_compile_args=['-Wno-format-security'])])
|
309
source/common.c
Normal file
309
source/common.c
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2016 Robert Wolterman
|
||||||
|
|
||||||
|
Original BBIO Author Justin Cooper
|
||||||
|
Modified for CHIP_IO Author Robert Wolterman
|
||||||
|
|
||||||
|
This file incorporates work covered by the following copyright and
|
||||||
|
permission notice, all modified code adopts the original license:
|
||||||
|
|
||||||
|
Copyright (c) 2013 Adafruit
|
||||||
|
|
||||||
|
Original RPi.GPIO Author Ben Croston
|
||||||
|
Modified for BBIO Author Justin Cooper
|
||||||
|
|
||||||
|
This file incorporates work covered by the following copyright and
|
||||||
|
permission notice, all modified code adopts the original license:
|
||||||
|
|
||||||
|
Copyright (c) 2013 Ben Croston
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Python.h"
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
int setup_error = 0;
|
||||||
|
int module_setup = 0;
|
||||||
|
|
||||||
|
typedef struct pins_t {
|
||||||
|
const char *name;
|
||||||
|
const char *key;
|
||||||
|
int gpio;
|
||||||
|
int pwm_mux_mode;
|
||||||
|
int ain;
|
||||||
|
} pins_t;
|
||||||
|
|
||||||
|
// I have no idea if this table is correct, we shall see - Robert Wolterman
|
||||||
|
pins_t table[] = {
|
||||||
|
{ "GND", "U13_1", 0, -1, -1},
|
||||||
|
{ "CHG-IN", "U13_2", 0, -1, -1},
|
||||||
|
{ "VCC-5V", "U13_3", 0, -1, -1},
|
||||||
|
{ "GND", "U13_4", 0, -1, -1},
|
||||||
|
{ "VCC-3V3", "U13_5", 0, -1, -1},
|
||||||
|
{ "TS", "U13_6", 0, -1, -1},
|
||||||
|
{ "VCC-1V8", "U13_7", 0, -1, -1},
|
||||||
|
{ "BAT", "U13_8", 0, -1, -1},
|
||||||
|
{ "TWI1-SDA", "U13_9", 48, -1, -1},
|
||||||
|
{ "PWRON", "U13_10", 0, -1, -1},
|
||||||
|
{ "TWI1-SCK", "U13_11", 47, -1, -1},
|
||||||
|
{ "GND", "U13_12", 0, -1, -1},
|
||||||
|
{ "X1", "U13_13", 0, -1, -1},
|
||||||
|
{ "X2", "U13_14", 0, -1, -1},
|
||||||
|
{ "Y1", "U13_15", 0, -1, -1},
|
||||||
|
{ "Y2", "U13_16", 0, -1, -1},
|
||||||
|
{ "LCD-D2", "U13_17", 98, -1, -1},
|
||||||
|
{ "PWM0", "U13_18", 34, -1, -1},
|
||||||
|
{ "LCD-D4", "U13_19", 100, -1, -1},
|
||||||
|
{ "LCD-D3", "U13_20", 99, -1, -1},
|
||||||
|
{ "LCD-D6", "U13_21", 102, -1, -1},
|
||||||
|
{ "LCD-D5", "U13_22", 101, -1, -1},
|
||||||
|
{ "LCD-D10", "U13_23", 106, -1, -1},
|
||||||
|
{ "LCD-D7", "U13_24", 103, -1, -1},
|
||||||
|
{ "LCD-D12", "U13_25", 108, -1, -1},
|
||||||
|
{ "LCD-D11", "U13_26", 107, -1, -1},
|
||||||
|
{ "LCD-D14", "U13_27", 110, -1, -1},
|
||||||
|
{ "LCD-D13", "U13_28", 109, -1, -1},
|
||||||
|
{ "LCD-D18", "U13_29", 114, -1, -1},
|
||||||
|
{ "LCD-D15", "U13_30", 111, -1, -1},
|
||||||
|
{ "LCD-D20", "U13_31", 116, -1, -1},
|
||||||
|
{ "LCD-D19", "U13_32", 115, -1, -1},
|
||||||
|
{ "LCD-D22", "U13_33", 118, -1, -1},
|
||||||
|
{ "LCD-D21", "U13_34", 117, -1, -1},
|
||||||
|
{ "LCD-CLK", "U13_35", 120, -1, -1},
|
||||||
|
{ "LCD-D23", "U13_36", 119, -1, -1},
|
||||||
|
{ "LCD-VSYNC", "U13_37", 123, -1, -1},
|
||||||
|
{ "LCD-HSYNC", "U13_38", 122, -1, -1},
|
||||||
|
{ "GND", "U13_39", 0, -1, -1},
|
||||||
|
{ "LCD-DE", "U13_40", 121, -1, -1},
|
||||||
|
{ "GND", "U14_1", 0, -1, -1},
|
||||||
|
{ "VCC-5V", "U14_2", 0, -1, -1},
|
||||||
|
{ "UART1-TX", "U14_3", 195, -1, -1},
|
||||||
|
{ "HPL", "U14_4", 0, -1, -1},
|
||||||
|
{ "UART1-RX", "U14_5", 196, -1, -1},
|
||||||
|
{ "HPCOM", "U14_6", 0, -1, -1},
|
||||||
|
{ "FEL", "U14_7", 0, -1, -1},
|
||||||
|
{ "HPR", "U14_8", 0, -1, -1},
|
||||||
|
{ "VCC-3V3", "U14_9", 0, -1, -1},
|
||||||
|
{ "MICM", "U14_10", 0, -1, -1},
|
||||||
|
{ "LRADC", "U14_11", 0, -1, -1},
|
||||||
|
{ "MICIN1", "U14_12", 0, -1, -1},
|
||||||
|
{ "XIO-P0", "U14_13", 408, -1, -1},
|
||||||
|
{ "XIO-P1", "U14_14", 409, -1, -1},
|
||||||
|
{ "XIO-P2", "U14_15", 410, -1, -1},
|
||||||
|
{ "XIO-P3", "U14_16", 411, -1, -1},
|
||||||
|
{ "XIO-P4", "U14_17", 412, -1, -1},
|
||||||
|
{ "XIO-P5", "U14_18", 413, -1, -1},
|
||||||
|
{ "XIO-P6", "U14_19", 414, -1, -1},
|
||||||
|
{ "XIO-P7", "U14_20", 415, -1, -1},
|
||||||
|
{ "GND", "U14_21", 0, -1, -1},
|
||||||
|
{ "GND", "U14_22", 0, -1, -1},
|
||||||
|
{ "AP-EINT1", "U14_23", 193, -1, -1},
|
||||||
|
{ "AP-EINT3", "U14_24", 35, -1, -1},
|
||||||
|
{ "TWI2-SDA", "U14_25", 50, -1, -1},
|
||||||
|
{ "TWI2-SCK", "U14_26", 49, -1, -1},
|
||||||
|
{ "CSIPCK", "U14_27", 128, -1, -1},
|
||||||
|
{ "CSICK", "U14_28", 129, 4, -1},
|
||||||
|
{ "CSIHSYNC", "U14_29", 130, 1, -1},
|
||||||
|
{ "CSIVSYNC", "U14_30", 131, -1, -1},
|
||||||
|
{ "CSID0", "U14_31", 132, 1, -1},
|
||||||
|
{ "CSID1", "U14_32", 133, -1, -1},
|
||||||
|
{ "CSID2", "U14_33", 134, -1, 4},
|
||||||
|
{ "CSID3", "U14_34", 135, -1, -1},
|
||||||
|
{ "CSID4", "U14_35", 136, -1, 6},
|
||||||
|
{ "CSID5", "U14_36", 137, -1, 5},
|
||||||
|
{ "CSID6", "U14_37", 138, -1, 2},
|
||||||
|
{ "CSID7", "U14_38", 139, -1, 3},
|
||||||
|
{ "GND", "U14_39", 0, -1, 0},
|
||||||
|
{ "GND", "U14_40", 0, -1, 1},
|
||||||
|
{ NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
int lookup_gpio_by_key(const char *key)
|
||||||
|
{
|
||||||
|
pins_t *p;
|
||||||
|
for (p = table; p->key != NULL; ++p) {
|
||||||
|
if (strcmp(p->key, key) == 0) {
|
||||||
|
return p->gpio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lookup_gpio_by_name(const char *name)
|
||||||
|
{
|
||||||
|
pins_t *p;
|
||||||
|
for (p = table; p->name != NULL; ++p) {
|
||||||
|
if (strcmp(p->name, name) == 0) {
|
||||||
|
return p->gpio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lookup_ain_by_key(const char *key)
|
||||||
|
{
|
||||||
|
pins_t *p;
|
||||||
|
for (p = table; p->key != NULL; ++p) {
|
||||||
|
if (strcmp(p->key, key) == 0) {
|
||||||
|
if (p->ain == -1) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return p->ain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lookup_ain_by_name(const char *name)
|
||||||
|
{
|
||||||
|
pins_t *p;
|
||||||
|
for (p = table; p->name != NULL; ++p) {
|
||||||
|
if (strcmp(p->name, name) == 0) {
|
||||||
|
if (p->ain == -1) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return p->ain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int copy_pwm_key_by_key(const char *input_key, char *key)
|
||||||
|
{
|
||||||
|
pins_t *p;
|
||||||
|
for (p = table; p->key != NULL; ++p) {
|
||||||
|
if (strcmp(p->key, input_key) == 0) {
|
||||||
|
//validate it's a valid pwm pin
|
||||||
|
if (p->pwm_mux_mode == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
strncpy(key, p->key, 7);
|
||||||
|
key[7] = '\0';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_pwm_key_by_name(const char *name, char *key)
|
||||||
|
{
|
||||||
|
pins_t *p;
|
||||||
|
for (p = table; p->name != NULL; ++p) {
|
||||||
|
if (strcmp(p->name, name) == 0) {
|
||||||
|
//validate it's a valid pwm pin
|
||||||
|
if (p->pwm_mux_mode == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
strncpy(key, p->key, 7);
|
||||||
|
key[7] = '\0';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_gpio_number(const char *key, unsigned int *gpio)
|
||||||
|
{
|
||||||
|
*gpio = lookup_gpio_by_key(key);
|
||||||
|
|
||||||
|
if (!*gpio) {
|
||||||
|
*gpio = lookup_gpio_by_name(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_pwm_key(const char *input, char *key)
|
||||||
|
{
|
||||||
|
if (!copy_pwm_key_by_key(input, key)) {
|
||||||
|
return get_pwm_key_by_name(input, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_adc_ain(const char *key, unsigned int *ain)
|
||||||
|
{
|
||||||
|
*ain = lookup_ain_by_key(key);
|
||||||
|
|
||||||
|
if (*ain == -1) {
|
||||||
|
*ain = lookup_ain_by_name(key);
|
||||||
|
|
||||||
|
if (*ain == -1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int build_path(const char *partial_path, const char *prefix, char *full_path, size_t full_path_len)
|
||||||
|
{
|
||||||
|
DIR *dp;
|
||||||
|
struct dirent *ep;
|
||||||
|
|
||||||
|
dp = opendir (partial_path);
|
||||||
|
if (dp != NULL) {
|
||||||
|
while ((ep = readdir (dp))) {
|
||||||
|
// Enforce that the prefix must be the first part of the file
|
||||||
|
char* found_string = strstr(ep->d_name, prefix);
|
||||||
|
|
||||||
|
if (found_string != NULL && (ep->d_name - found_string) == 0) {
|
||||||
|
snprintf(full_path, full_path_len, "%s/%s", partial_path, ep->d_name);
|
||||||
|
(void) closedir (dp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void) closedir (dp);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_spi_bus_path_number(unsigned int spi)
|
||||||
|
{
|
||||||
|
char path[50];
|
||||||
|
|
||||||
|
build_path("/sys/devices", "ocp", ocp_dir, sizeof(ocp_dir));
|
||||||
|
|
||||||
|
if (spi == 0) {
|
||||||
|
snprintf(path, sizeof(path), "%s/48030000.spi/spi_master/spi1", ocp_dir);
|
||||||
|
} else {
|
||||||
|
snprintf(path, sizeof(path), "%s/481a0000.spi/spi_master/spi1", ocp_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
DIR* dir = opendir(path);
|
||||||
|
if (dir) {
|
||||||
|
closedir(dir);
|
||||||
|
//device is using /dev/spidev1.x
|
||||||
|
return 1;
|
||||||
|
} else if (ENOENT == errno) {
|
||||||
|
//device is using /dev/spidev2.x
|
||||||
|
return 2;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
59
source/common.h
Normal file
59
source/common.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2016 Robert Wolterman
|
||||||
|
|
||||||
|
Original BBIO Author Justin Cooper
|
||||||
|
Modified for CHIP_IO Author Robert Wolterman
|
||||||
|
|
||||||
|
This file incorporates work covered by the following copyright and
|
||||||
|
permission notice, all modified code adopts the original license:
|
||||||
|
|
||||||
|
Copyright (c) 2013 Adafruit
|
||||||
|
|
||||||
|
Original RPi.GPIO Author Ben Croston
|
||||||
|
Modified for BBIO Author Justin Cooper
|
||||||
|
|
||||||
|
This file incorporates work covered by the following copyright and
|
||||||
|
permission notice, all modified code adopts the original license:
|
||||||
|
|
||||||
|
Copyright (c) 2013 Ben Croston
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MODE_UNKNOWN -1
|
||||||
|
#define BOARD 10
|
||||||
|
#define BCM 11
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||||
|
|
||||||
|
#define FILENAME_BUFFER_SIZE 128
|
||||||
|
|
||||||
|
int gpio_mode;
|
||||||
|
int gpio_direction[120];
|
||||||
|
|
||||||
|
char ctrl_dir[35];
|
||||||
|
char ocp_dir[25];
|
||||||
|
|
||||||
|
int get_gpio_number(const char *key, unsigned int *gpio);
|
||||||
|
int get_pwm_key(const char *input, char *key);
|
||||||
|
int get_adc_ain(const char *key, unsigned int *ain);
|
||||||
|
int build_path(const char *partial_path, const char *prefix, char *full_path, size_t full_path_len);
|
||||||
|
int get_spi_bus_path_number(unsigned int spi);
|
||||||
|
int setup_error;
|
||||||
|
int module_setup;
|
81
source/constants.c
Normal file
81
source/constants.c
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2016 Robert Wolterman
|
||||||
|
|
||||||
|
Original BBIO Author Justin Cooper
|
||||||
|
Modified for CHIP_IO Author Robert Wolterman
|
||||||
|
|
||||||
|
This file incorporates work covered by the following copyright and
|
||||||
|
permission notice, all modified code adopts the original license:
|
||||||
|
|
||||||
|
Copyright (c) 2013 Adafruit
|
||||||
|
|
||||||
|
Original RPi.GPIO Author Ben Croston
|
||||||
|
Modified for BBIO Author Justin Cooper
|
||||||
|
|
||||||
|
This file incorporates work covered by the following copyright and
|
||||||
|
permission notice, all modified code adopts the original license:
|
||||||
|
|
||||||
|
Copyright (c) 2013 Ben Croston
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Python.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "event_gpio.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
void define_constants(PyObject *module)
|
||||||
|
{
|
||||||
|
high = Py_BuildValue("i", HIGH);
|
||||||
|
PyModule_AddObject(module, "HIGH", high);
|
||||||
|
|
||||||
|
low = Py_BuildValue("i", LOW);
|
||||||
|
PyModule_AddObject(module, "LOW", low);
|
||||||
|
|
||||||
|
output = Py_BuildValue("i", OUTPUT);
|
||||||
|
PyModule_AddObject(module, "OUT", output);
|
||||||
|
|
||||||
|
input = Py_BuildValue("i", INPUT);
|
||||||
|
PyModule_AddObject(module, "IN", input);
|
||||||
|
|
||||||
|
alt0 = Py_BuildValue("i", ALT0);
|
||||||
|
PyModule_AddObject(module, "ALT0", alt0);
|
||||||
|
|
||||||
|
pud_off = Py_BuildValue("i", PUD_OFF);
|
||||||
|
PyModule_AddObject(module, "PUD_OFF", pud_off);
|
||||||
|
|
||||||
|
pud_up = Py_BuildValue("i", PUD_UP);
|
||||||
|
PyModule_AddObject(module, "PUD_UP", pud_up);
|
||||||
|
|
||||||
|
pud_down = Py_BuildValue("i", PUD_DOWN);
|
||||||
|
PyModule_AddObject(module, "PUD_DOWN", pud_down);
|
||||||
|
|
||||||
|
rising_edge = Py_BuildValue("i", RISING_EDGE);
|
||||||
|
PyModule_AddObject(module, "RISING", rising_edge);
|
||||||
|
|
||||||
|
falling_edge = Py_BuildValue("i", FALLING_EDGE);
|
||||||
|
PyModule_AddObject(module, "FALLING", falling_edge);
|
||||||
|
|
||||||
|
both_edge = Py_BuildValue("i", BOTH_EDGE);
|
||||||
|
PyModule_AddObject(module, "BOTH", both_edge);
|
||||||
|
|
||||||
|
version = Py_BuildValue("s", "0.0.4");
|
||||||
|
PyModule_AddObject(module, "VERSION", version);
|
||||||
|
}
|
14
source/constants.h
Normal file
14
source/constants.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
PyObject *high;
|
||||||
|
PyObject *low;
|
||||||
|
PyObject *input;
|
||||||
|
PyObject *output;
|
||||||
|
PyObject *alt0;
|
||||||
|
PyObject *pud_off;
|
||||||
|
PyObject *pud_up;
|
||||||
|
PyObject *pud_down;
|
||||||
|
PyObject *rising_edge;
|
||||||
|
PyObject *falling_edge;
|
||||||
|
PyObject *both_edge;
|
||||||
|
PyObject *version;
|
||||||
|
|
||||||
|
void define_constants(PyObject *module);
|
660
source/event_gpio.c
Normal file
660
source/event_gpio.c
Normal file
@ -0,0 +1,660 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2016 Robert Wolterman
|
||||||
|
|
||||||
|
Original BBIO Author Justin Cooper
|
||||||
|
Modified for CHIP_IO Author Robert Wolterman
|
||||||
|
|
||||||
|
This file incorporates work covered by the following copyright and
|
||||||
|
permission notice, all modified code adopts the original license:
|
||||||
|
|
||||||
|
Copyright (c) 2013 Adafruit
|
||||||
|
|
||||||
|
Original RPi.GPIO Author Ben Croston
|
||||||
|
Modified for BBIO Author Justin Cooper
|
||||||
|
|
||||||
|
This file incorporates work covered by the following copyright and
|
||||||
|
permission notice, all modified code adopts the original license:
|
||||||
|
|
||||||
|
Copyright (c) 2013 Ben Croston
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "event_gpio.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
const char *stredge[4] = {"none", "rising", "falling", "both"};
|
||||||
|
|
||||||
|
// file descriptors
|
||||||
|
struct fdx
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
unsigned int gpio;
|
||||||
|
int initial;
|
||||||
|
unsigned int is_evented;
|
||||||
|
struct fdx *next;
|
||||||
|
};
|
||||||
|
struct fdx *fd_list = NULL;
|
||||||
|
|
||||||
|
// event callbacks
|
||||||
|
struct callback
|
||||||
|
{
|
||||||
|
unsigned int gpio;
|
||||||
|
void (*func)(unsigned int gpio);
|
||||||
|
struct callback *next;
|
||||||
|
};
|
||||||
|
struct callback *callbacks = NULL;
|
||||||
|
|
||||||
|
// gpio exports
|
||||||
|
struct gpio_exp
|
||||||
|
{
|
||||||
|
unsigned int gpio;
|
||||||
|
struct gpio_exp *next;
|
||||||
|
};
|
||||||
|
struct gpio_exp *exported_gpios = NULL;
|
||||||
|
|
||||||
|
pthread_t threads;
|
||||||
|
int event_occurred[430] = { 0 };
|
||||||
|
int thread_running = 0;
|
||||||
|
int epfd = -1;
|
||||||
|
|
||||||
|
int gpio_export(unsigned int gpio)
|
||||||
|
{
|
||||||
|
int fd, len;
|
||||||
|
char str_gpio[10];
|
||||||
|
struct gpio_exp *new_gpio, *g;
|
||||||
|
|
||||||
|
if ((fd = open("/sys/class/gpio/export", O_WRONLY)) < 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio);
|
||||||
|
write(fd, str_gpio, len);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
// add to list
|
||||||
|
new_gpio = malloc(sizeof(struct gpio_exp));
|
||||||
|
if (new_gpio == 0)
|
||||||
|
return -1; // out of memory
|
||||||
|
|
||||||
|
new_gpio->gpio = gpio;
|
||||||
|
new_gpio->next = NULL;
|
||||||
|
|
||||||
|
if (exported_gpios == NULL)
|
||||||
|
{
|
||||||
|
// create new list
|
||||||
|
exported_gpios = new_gpio;
|
||||||
|
} else {
|
||||||
|
// add to end of existing list
|
||||||
|
g = exported_gpios;
|
||||||
|
while (g->next != NULL)
|
||||||
|
g = g->next;
|
||||||
|
g->next = new_gpio;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_value_fd(unsigned int gpio)
|
||||||
|
{
|
||||||
|
struct fdx *f = fd_list;
|
||||||
|
struct fdx *temp;
|
||||||
|
struct fdx *prev = NULL;
|
||||||
|
|
||||||
|
while (f != NULL)
|
||||||
|
{
|
||||||
|
if (f->gpio == gpio)
|
||||||
|
{
|
||||||
|
close(f->fd);
|
||||||
|
if (prev == NULL)
|
||||||
|
fd_list = f->next;
|
||||||
|
else
|
||||||
|
prev->next = f->next;
|
||||||
|
temp = f;
|
||||||
|
f = f->next;
|
||||||
|
free(temp);
|
||||||
|
} else {
|
||||||
|
prev = f;
|
||||||
|
f = f->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd_lookup(unsigned int gpio)
|
||||||
|
{
|
||||||
|
struct fdx *f = fd_list;
|
||||||
|
while (f != NULL)
|
||||||
|
{
|
||||||
|
if (f->gpio == gpio)
|
||||||
|
return f->fd;
|
||||||
|
f = f->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_fd_list(unsigned int gpio, int fd)
|
||||||
|
{
|
||||||
|
struct fdx *new_fd;
|
||||||
|
|
||||||
|
new_fd = malloc(sizeof(struct fdx));
|
||||||
|
if (new_fd == 0)
|
||||||
|
return -1; // out of memory
|
||||||
|
|
||||||
|
new_fd->fd = fd;
|
||||||
|
new_fd->gpio = gpio;
|
||||||
|
new_fd->initial = 1;
|
||||||
|
new_fd->is_evented = 0;
|
||||||
|
if (fd_list == NULL) {
|
||||||
|
new_fd->next = NULL;
|
||||||
|
} else {
|
||||||
|
new_fd->next = fd_list;
|
||||||
|
}
|
||||||
|
fd_list = new_fd;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int open_value_file(unsigned int gpio)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char filename[MAX_FILENAME];
|
||||||
|
|
||||||
|
// create file descriptor of value file
|
||||||
|
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio);
|
||||||
|
|
||||||
|
if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0)
|
||||||
|
return -1;
|
||||||
|
add_fd_list(gpio, fd);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_unexport(unsigned int gpio)
|
||||||
|
{
|
||||||
|
int fd, len;
|
||||||
|
char str_gpio[10];
|
||||||
|
struct gpio_exp *g, *temp, *prev_g = NULL;
|
||||||
|
|
||||||
|
close_value_fd(gpio);
|
||||||
|
|
||||||
|
if ((fd = open("/sys/class/gpio/unexport", O_WRONLY)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio);
|
||||||
|
write(fd, str_gpio, len);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
// remove from list
|
||||||
|
g = exported_gpios;
|
||||||
|
while (g != NULL)
|
||||||
|
{
|
||||||
|
if (g->gpio == gpio)
|
||||||
|
{
|
||||||
|
if (prev_g == NULL)
|
||||||
|
exported_gpios = g->next;
|
||||||
|
else
|
||||||
|
prev_g->next = g->next;
|
||||||
|
temp = g;
|
||||||
|
g = g->next;
|
||||||
|
free(temp);
|
||||||
|
} else {
|
||||||
|
prev_g = g;
|
||||||
|
g = g->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_set_direction(unsigned int gpio, unsigned int in_flag)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char filename[40];
|
||||||
|
char direction[10] = { 0 };
|
||||||
|
|
||||||
|
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio);
|
||||||
|
if ((fd = open(filename, O_WRONLY)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (in_flag) {
|
||||||
|
strncpy(direction, "out", ARRAY_SIZE(direction) - 1);
|
||||||
|
} else {
|
||||||
|
strncpy(direction, "in", ARRAY_SIZE(direction) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
write(fd, direction, strlen(direction));
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_get_direction(unsigned int gpio, unsigned int *value)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char direction[4] = { 0 };
|
||||||
|
char filename[40];
|
||||||
|
|
||||||
|
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio);
|
||||||
|
if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
read(fd, &direction, sizeof(direction) - 1);
|
||||||
|
|
||||||
|
if (strcmp(direction, "out") == 0) {
|
||||||
|
*value = OUTPUT;
|
||||||
|
} else {
|
||||||
|
*value = INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_set_value(unsigned int gpio, unsigned int value)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char filename[MAX_FILENAME];
|
||||||
|
char vstr[10];
|
||||||
|
|
||||||
|
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio);
|
||||||
|
|
||||||
|
if ((fd = open(filename, O_WRONLY)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
strncpy(vstr, "1", ARRAY_SIZE(vstr) - 1);
|
||||||
|
} else {
|
||||||
|
strncpy(vstr, "0", ARRAY_SIZE(vstr) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
write(fd, vstr, strlen(vstr));
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_get_value(unsigned int gpio, unsigned int *value)
|
||||||
|
{
|
||||||
|
int fd = fd_lookup(gpio);
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
if (!fd)
|
||||||
|
{
|
||||||
|
if ((fd = open_value_file(gpio)) == -1)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
read(fd, &ch, sizeof(ch));
|
||||||
|
|
||||||
|
if (ch != '0') {
|
||||||
|
*value = 1;
|
||||||
|
} else {
|
||||||
|
*value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_set_edge(unsigned int gpio, unsigned int edge)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char filename[40];
|
||||||
|
|
||||||
|
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/edge", gpio);
|
||||||
|
|
||||||
|
if ((fd = open(filename, O_WRONLY)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
write(fd, stredge[edge], strlen(stredge[edge]) + 1);
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int gpio_lookup(int fd)
|
||||||
|
{
|
||||||
|
struct fdx *f = fd_list;
|
||||||
|
while (f != NULL)
|
||||||
|
{
|
||||||
|
if (f->fd == fd)
|
||||||
|
return f->gpio;
|
||||||
|
f = f->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void exports_cleanup(void)
|
||||||
|
{
|
||||||
|
// unexport everything
|
||||||
|
while (exported_gpios != NULL)
|
||||||
|
gpio_unexport(exported_gpios->gpio);
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio))
|
||||||
|
{
|
||||||
|
struct callback *cb = callbacks;
|
||||||
|
struct callback *new_cb;
|
||||||
|
|
||||||
|
new_cb = malloc(sizeof(struct callback));
|
||||||
|
if (new_cb == 0)
|
||||||
|
return -1; // out of memory
|
||||||
|
|
||||||
|
new_cb->gpio = gpio;
|
||||||
|
new_cb->func = func;
|
||||||
|
new_cb->next = NULL;
|
||||||
|
|
||||||
|
if (callbacks == NULL) {
|
||||||
|
// start new list
|
||||||
|
callbacks = new_cb;
|
||||||
|
} else {
|
||||||
|
// add to end of list
|
||||||
|
while (cb->next != NULL)
|
||||||
|
cb = cb->next;
|
||||||
|
cb->next = new_cb;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_callbacks(unsigned int gpio)
|
||||||
|
{
|
||||||
|
struct callback *cb = callbacks;
|
||||||
|
while (cb != NULL)
|
||||||
|
{
|
||||||
|
if (cb->gpio == gpio)
|
||||||
|
cb->func(cb->gpio);
|
||||||
|
cb = cb->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_callbacks(unsigned int gpio)
|
||||||
|
{
|
||||||
|
struct callback *cb = callbacks;
|
||||||
|
struct callback *temp;
|
||||||
|
struct callback *prev = NULL;
|
||||||
|
|
||||||
|
while (cb != NULL)
|
||||||
|
{
|
||||||
|
if (cb->gpio == gpio)
|
||||||
|
{
|
||||||
|
if (prev == NULL)
|
||||||
|
callbacks = cb->next;
|
||||||
|
else
|
||||||
|
prev->next = cb->next;
|
||||||
|
temp = cb;
|
||||||
|
cb = cb->next;
|
||||||
|
free(temp);
|
||||||
|
} else {
|
||||||
|
prev = cb;
|
||||||
|
cb = cb->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_initial_false(unsigned int gpio)
|
||||||
|
{
|
||||||
|
struct fdx *f = fd_list;
|
||||||
|
|
||||||
|
while (f != NULL)
|
||||||
|
{
|
||||||
|
if (f->gpio == gpio)
|
||||||
|
f->initial = 0;
|
||||||
|
f = f->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_initial(unsigned int gpio)
|
||||||
|
{
|
||||||
|
struct fdx *f = fd_list;
|
||||||
|
|
||||||
|
while (f != NULL)
|
||||||
|
{
|
||||||
|
if ((f->gpio == gpio) && f->initial)
|
||||||
|
return 1;
|
||||||
|
f = f->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *poll_thread(void *threadarg)
|
||||||
|
{
|
||||||
|
struct epoll_event events;
|
||||||
|
char buf;
|
||||||
|
unsigned int gpio;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
thread_running = 1;
|
||||||
|
while (thread_running)
|
||||||
|
{
|
||||||
|
if ((n = epoll_wait(epfd, &events, 1, -1)) == -1)
|
||||||
|
{
|
||||||
|
thread_running = 0;
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
if (n > 0) {
|
||||||
|
lseek(events.data.fd, 0, SEEK_SET);
|
||||||
|
if (read(events.data.fd, &buf, 1) != 1)
|
||||||
|
{
|
||||||
|
thread_running = 0;
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
gpio = gpio_lookup(events.data.fd);
|
||||||
|
if (gpio_initial(gpio)) { // ignore first epoll trigger
|
||||||
|
set_initial_false(gpio);
|
||||||
|
} else {
|
||||||
|
event_occurred[gpio] = 1;
|
||||||
|
run_callbacks(gpio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thread_running = 0;
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_is_evented(unsigned int gpio)
|
||||||
|
{
|
||||||
|
struct fdx *f = fd_list;
|
||||||
|
while (f != NULL)
|
||||||
|
{
|
||||||
|
if (f->gpio == gpio)
|
||||||
|
return 1;
|
||||||
|
f = f->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_event_add(unsigned int gpio)
|
||||||
|
{
|
||||||
|
struct fdx *f = fd_list;
|
||||||
|
while (f != NULL)
|
||||||
|
{
|
||||||
|
if (f->gpio == gpio)
|
||||||
|
{
|
||||||
|
if (f->is_evented)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
f->is_evented = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
f = f->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpio_event_remove(unsigned int gpio)
|
||||||
|
{
|
||||||
|
struct fdx *f = fd_list;
|
||||||
|
while (f != NULL)
|
||||||
|
{
|
||||||
|
if (f->gpio == gpio)
|
||||||
|
{
|
||||||
|
f->is_evented = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
f = f->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_edge_detect(unsigned int gpio, unsigned int edge)
|
||||||
|
// return values:
|
||||||
|
// 0 - Success
|
||||||
|
// 1 - Edge detection already added
|
||||||
|
// 2 - Other error
|
||||||
|
{
|
||||||
|
int fd = fd_lookup(gpio);
|
||||||
|
pthread_t threads;
|
||||||
|
struct epoll_event ev;
|
||||||
|
long t = 0;
|
||||||
|
|
||||||
|
// check to see if this gpio has been added already
|
||||||
|
if (gpio_event_add(gpio) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// export /sys/class/gpio interface
|
||||||
|
gpio_export(gpio);
|
||||||
|
gpio_set_direction(gpio, 0); // 0=input
|
||||||
|
gpio_set_edge(gpio, edge);
|
||||||
|
|
||||||
|
if (!fd)
|
||||||
|
{
|
||||||
|
if ((fd = open_value_file(gpio)) == -1)
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create epfd if not already open
|
||||||
|
if ((epfd == -1) && ((epfd = epoll_create(1)) == -1))
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
// add to epoll fd
|
||||||
|
ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
|
||||||
|
ev.data.fd = fd;
|
||||||
|
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
// start poll thread if it is not already running
|
||||||
|
if (!thread_running)
|
||||||
|
{
|
||||||
|
if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0)
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_edge_detect(unsigned int gpio)
|
||||||
|
{
|
||||||
|
struct epoll_event ev;
|
||||||
|
int fd = fd_lookup(gpio);
|
||||||
|
|
||||||
|
// delete callbacks for gpio
|
||||||
|
remove_callbacks(gpio);
|
||||||
|
|
||||||
|
// delete epoll of fd
|
||||||
|
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev);
|
||||||
|
|
||||||
|
// set edge to none
|
||||||
|
gpio_set_edge(gpio, NO_EDGE);
|
||||||
|
|
||||||
|
// unexport gpio
|
||||||
|
gpio_event_remove(gpio);
|
||||||
|
|
||||||
|
// clear detected flag
|
||||||
|
event_occurred[gpio] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int event_detected(unsigned int gpio)
|
||||||
|
{
|
||||||
|
if (event_occurred[gpio]) {
|
||||||
|
event_occurred[gpio] = 0;
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void event_cleanup(void)
|
||||||
|
{
|
||||||
|
close(epfd);
|
||||||
|
thread_running = 0;
|
||||||
|
exports_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
int blocking_wait_for_edge(unsigned int gpio, unsigned int edge)
|
||||||
|
// standalone from all the event functions above
|
||||||
|
{
|
||||||
|
int fd = fd_lookup(gpio);
|
||||||
|
int epfd, n, i;
|
||||||
|
struct epoll_event events, ev;
|
||||||
|
char buf;
|
||||||
|
|
||||||
|
if ((epfd = epoll_create(1)) == -1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// check to see if this gpio has been added already, if not, mark as added
|
||||||
|
if (gpio_event_add(gpio) != 0)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
// export /sys/class/gpio interface
|
||||||
|
gpio_export(gpio);
|
||||||
|
gpio_set_direction(gpio, 0); // 0=input
|
||||||
|
gpio_set_edge(gpio, edge);
|
||||||
|
|
||||||
|
if (!fd)
|
||||||
|
{
|
||||||
|
if ((fd = open_value_file(gpio)) == -1)
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to epoll fd
|
||||||
|
ev.events = EPOLLIN | EPOLLET | EPOLLPRI;
|
||||||
|
ev.data.fd = fd;
|
||||||
|
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
|
||||||
|
{
|
||||||
|
gpio_event_remove(gpio);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// epoll for event
|
||||||
|
for (i = 0; i<2; i++) // first time triggers with current state, so ignore
|
||||||
|
if ((n = epoll_wait(epfd, &events, 1, -1)) == -1)
|
||||||
|
{
|
||||||
|
gpio_event_remove(gpio);
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 0)
|
||||||
|
{
|
||||||
|
lseek(events.data.fd, 0, SEEK_SET);
|
||||||
|
if (read(events.data.fd, &buf, sizeof(buf)) != 1)
|
||||||
|
{
|
||||||
|
gpio_event_remove(gpio);
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
if (events.data.fd != fd)
|
||||||
|
{
|
||||||
|
gpio_event_remove(gpio);
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_event_remove(gpio);
|
||||||
|
close(epfd);
|
||||||
|
return 0;
|
||||||
|
}
|
74
source/event_gpio.h
Normal file
74
source/event_gpio.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2016 Robert Wolterman
|
||||||
|
|
||||||
|
Original BBIO Author Justin Cooper
|
||||||
|
Modified for CHIP_IO Author Robert Wolterman
|
||||||
|
|
||||||
|
This file incorporates work covered by the following copyright and
|
||||||
|
permission notice, all modified code adopts the original license:
|
||||||
|
|
||||||
|
Copyright (c) 2013 Adafruit
|
||||||
|
|
||||||
|
Original RPi.GPIO Author Ben Croston
|
||||||
|
Modified for BBIO Author Justin Cooper
|
||||||
|
|
||||||
|
This file incorporates work covered by the following copyright and
|
||||||
|
permission notice, all modified code adopts the original license:
|
||||||
|
|
||||||
|
Copyright (c) 2013 Ben Croston
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define NO_EDGE 0
|
||||||
|
#define RISING_EDGE 1
|
||||||
|
#define FALLING_EDGE 2
|
||||||
|
#define BOTH_EDGE 3
|
||||||
|
|
||||||
|
#define INPUT 0
|
||||||
|
#define OUTPUT 1
|
||||||
|
#define ALT0 4
|
||||||
|
|
||||||
|
#define HIGH 1
|
||||||
|
#define LOW 0
|
||||||
|
|
||||||
|
#define MAX_FILENAME 50
|
||||||
|
|
||||||
|
#define PUD_OFF 0
|
||||||
|
#define PUD_DOWN 1
|
||||||
|
#define PUD_UP 2
|
||||||
|
|
||||||
|
int gpio_export(unsigned int gpio);
|
||||||
|
int gpio_unexport(unsigned int gpio);
|
||||||
|
void exports_cleanup(void);
|
||||||
|
int gpio_set_direction(unsigned int gpio, unsigned int in_flag);
|
||||||
|
int gpio_get_direction(unsigned int gpio, unsigned int *value);
|
||||||
|
int gpio_set_value(unsigned int gpio, unsigned int value);
|
||||||
|
int gpio_get_value(unsigned int gpio, unsigned int *value);
|
||||||
|
|
||||||
|
int add_edge_detect(unsigned int gpio, unsigned int edge);
|
||||||
|
void remove_edge_detect(unsigned int gpio);
|
||||||
|
int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio));
|
||||||
|
int event_detected(unsigned int gpio);
|
||||||
|
int gpio_event_add(unsigned int gpio);
|
||||||
|
int gpio_event_remove(unsigned int gpio);
|
||||||
|
int gpio_is_evented(unsigned int gpio);
|
||||||
|
int event_initialise(void);
|
||||||
|
void event_cleanup(void);
|
||||||
|
int blocking_wait_for_edge(unsigned int gpio, unsigned int edge);
|
554
source/py_gpio.c
Normal file
554
source/py_gpio.c
Normal file
@ -0,0 +1,554 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2016 Robert Wolterman
|
||||||
|
|
||||||
|
Original BBIO Author Justin Cooper
|
||||||
|
Modified for CHIP_IO Author Robert Wolterman
|
||||||
|
|
||||||
|
This file incorporates work covered by the following copyright and
|
||||||
|
permission notice, all modified code adopts the original license:
|
||||||
|
|
||||||
|
Copyright (c) 2013 Adafruit
|
||||||
|
|
||||||
|
Original RPi.GPIO Author Ben Croston
|
||||||
|
Modified for BBIO Author Justin Cooper
|
||||||
|
|
||||||
|
This file incorporates work covered by the following copyright and
|
||||||
|
permission notice, all modified code adopts the original license:
|
||||||
|
|
||||||
|
Copyright (c) 2013 Ben Croston
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Python.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "event_gpio.h"
|
||||||
|
|
||||||
|
static int gpio_warnings = 1;
|
||||||
|
|
||||||
|
struct py_callback
|
||||||
|
{
|
||||||
|
char channel[32];
|
||||||
|
unsigned int gpio;
|
||||||
|
PyObject *py_cb;
|
||||||
|
unsigned long long lastcall;
|
||||||
|
unsigned int bouncetime;
|
||||||
|
struct py_callback *next;
|
||||||
|
};
|
||||||
|
static struct py_callback *py_callbacks = NULL;
|
||||||
|
|
||||||
|
static int init_module(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<430; i++)
|
||||||
|
gpio_direction[i] = -1;
|
||||||
|
|
||||||
|
module_setup = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// python function cleanup()
|
||||||
|
static PyObject *py_cleanup(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
// clean up any exports
|
||||||
|
event_cleanup();
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// python function setup(channel, direction, pull_up_down=PUD_OFF, initial=None)
|
||||||
|
static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||||
|
{
|
||||||
|
unsigned int gpio;
|
||||||
|
char *channel;
|
||||||
|
int direction;
|
||||||
|
int pud = PUD_OFF;
|
||||||
|
int initial = 0;
|
||||||
|
static char *kwlist[] = {"channel", "direction", "pull_up_down", "initial", NULL};
|
||||||
|
|
||||||
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|ii", kwlist, &channel, &direction, &pud, &initial))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!module_setup) {
|
||||||
|
init_module();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (direction != INPUT && direction != OUTPUT)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "An invalid direction was passed to setup()");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (direction == OUTPUT)
|
||||||
|
pud = PUD_OFF;
|
||||||
|
|
||||||
|
if (pud != PUD_OFF && pud != PUD_DOWN && pud != PUD_UP)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "Invalid value for pull_up_down - should be either PUD_OFF, PUD_UP or PUD_DOWN");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_gpio_number(channel, &gpio))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
gpio_export(gpio);
|
||||||
|
gpio_set_direction(gpio, direction);
|
||||||
|
if (gpio < 408) {
|
||||||
|
if (direction == OUTPUT) {
|
||||||
|
gpio_set_value(gpio, initial);
|
||||||
|
} else {
|
||||||
|
gpio_set_value(gpio, pud);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_direction[gpio] = direction;
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// python function output(channel, value)
|
||||||
|
static PyObject *py_output_gpio(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
unsigned int gpio;
|
||||||
|
int value;
|
||||||
|
char *channel;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "si", &channel, &value))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (get_gpio_number(channel, &gpio))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!module_setup || gpio_direction[gpio] != OUTPUT)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "The GPIO channel has not been setup() as an OUTPUT");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_set_value(gpio, value);
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// python function value = input(channel)
|
||||||
|
static PyObject *py_input_gpio(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
unsigned int gpio;
|
||||||
|
char *channel;
|
||||||
|
unsigned int value;
|
||||||
|
PyObject *py_value;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &channel))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (get_gpio_number(channel, &gpio))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// check channel is set up as an input or output
|
||||||
|
if (!module_setup || (gpio_direction[gpio] != INPUT && gpio_direction[gpio] != OUTPUT))
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel first");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_get_value(gpio, &value);
|
||||||
|
|
||||||
|
py_value = Py_BuildValue("i", value);
|
||||||
|
|
||||||
|
return py_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void run_py_callbacks(unsigned int gpio)
|
||||||
|
{
|
||||||
|
PyObject *result;
|
||||||
|
PyGILState_STATE gstate;
|
||||||
|
struct py_callback *cb = py_callbacks;
|
||||||
|
struct timeval tv_timenow;
|
||||||
|
unsigned long long timenow;
|
||||||
|
|
||||||
|
while (cb != NULL)
|
||||||
|
{
|
||||||
|
if (cb->gpio == gpio)
|
||||||
|
{
|
||||||
|
gettimeofday(&tv_timenow, NULL);
|
||||||
|
timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec;
|
||||||
|
if (cb->bouncetime == 0 || timenow - cb->lastcall > cb->bouncetime*1000 || cb->lastcall == 0 || cb->lastcall > timenow) {
|
||||||
|
|
||||||
|
// save lastcall before calling func to prevent reentrant bounce
|
||||||
|
cb->lastcall = timenow;
|
||||||
|
|
||||||
|
// run callback
|
||||||
|
gstate = PyGILState_Ensure();
|
||||||
|
result = PyObject_CallFunction(cb->py_cb, "s", cb->channel);
|
||||||
|
|
||||||
|
if (result == NULL && PyErr_Occurred())
|
||||||
|
{
|
||||||
|
PyErr_Print();
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
Py_XDECREF(result);
|
||||||
|
PyGILState_Release(gstate);
|
||||||
|
}
|
||||||
|
cb->lastcall = timenow;
|
||||||
|
}
|
||||||
|
cb = cb->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_py_callback(char *channel, unsigned int gpio, unsigned int bouncetime, PyObject *cb_func)
|
||||||
|
{
|
||||||
|
struct py_callback *new_py_cb;
|
||||||
|
struct py_callback *cb = py_callbacks;
|
||||||
|
|
||||||
|
// add callback to py_callbacks list
|
||||||
|
new_py_cb = malloc(sizeof(struct py_callback));
|
||||||
|
if (new_py_cb == 0)
|
||||||
|
{
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
new_py_cb->py_cb = cb_func;
|
||||||
|
Py_XINCREF(cb_func); // Add a reference to new callback
|
||||||
|
memset(new_py_cb->channel, 0, sizeof(new_py_cb->channel));
|
||||||
|
strncpy(new_py_cb->channel, channel, sizeof(new_py_cb->channel) - 1);
|
||||||
|
new_py_cb->gpio = gpio;
|
||||||
|
new_py_cb->lastcall = 0;
|
||||||
|
new_py_cb->bouncetime = bouncetime;
|
||||||
|
new_py_cb->next = NULL;
|
||||||
|
if (py_callbacks == NULL) {
|
||||||
|
py_callbacks = new_py_cb;
|
||||||
|
} else {
|
||||||
|
// add to end of list
|
||||||
|
while (cb->next != NULL)
|
||||||
|
cb = cb->next;
|
||||||
|
cb->next = new_py_cb;
|
||||||
|
}
|
||||||
|
add_edge_callback(gpio, run_py_callbacks);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// python function add_event_callback(gpio, callback, bouncetime=0)
|
||||||
|
static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||||
|
{
|
||||||
|
unsigned int gpio;
|
||||||
|
char *channel;
|
||||||
|
unsigned int bouncetime = 0;
|
||||||
|
PyObject *cb_func;
|
||||||
|
char *kwlist[] = {"gpio", "callback", "bouncetime", NULL};
|
||||||
|
|
||||||
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|i", kwlist, &channel, &cb_func, &bouncetime))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!PyCallable_Check(cb_func))
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Parameter must be callable");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_gpio_number(channel, &gpio))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// check channel is set up as an input
|
||||||
|
if (!module_setup || gpio_direction[gpio] != INPUT)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gpio_is_evented(gpio))
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Add event detection using add_event_detect first before adding a callback");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (add_py_callback(channel, gpio, bouncetime, cb_func) != 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// python function add_event_detect(gpio, edge, callback=None, bouncetime=0
|
||||||
|
static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||||
|
{
|
||||||
|
unsigned int gpio;
|
||||||
|
char *channel;
|
||||||
|
int edge, result;
|
||||||
|
unsigned int bouncetime = 0;
|
||||||
|
PyObject *cb_func = NULL;
|
||||||
|
char *kwlist[] = {"gpio", "edge", "callback", "bouncetime", NULL};
|
||||||
|
|
||||||
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|Oi", kwlist, &channel, &edge, &cb_func, &bouncetime))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (cb_func != NULL && !PyCallable_Check(cb_func))
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Parameter must be callable");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_gpio_number(channel, &gpio))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// check channel is set up as an input
|
||||||
|
if (!module_setup || gpio_direction[gpio] != INPUT)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is edge valid value
|
||||||
|
if (edge != RISING_EDGE && edge != FALLING_EDGE && edge != BOTH_EDGE)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "The edge must be set to RISING, FALLING or BOTH");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result = add_edge_detect(gpio, edge)) != 0) // starts a thread
|
||||||
|
{
|
||||||
|
if (result == 1)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Edge detection already enabled for this GPIO channel");
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Failed to add edge detection");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cb_func != NULL)
|
||||||
|
if (add_py_callback(channel, gpio, bouncetime, cb_func) != 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// python function remove_event_detect(gpio)
|
||||||
|
static PyObject *py_remove_event_detect(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
unsigned int gpio;
|
||||||
|
char *channel;
|
||||||
|
struct py_callback *cb = py_callbacks;
|
||||||
|
struct py_callback *temp;
|
||||||
|
struct py_callback *prev = NULL;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &channel))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (get_gpio_number(channel, &gpio))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// remove all python callbacks for gpio
|
||||||
|
while (cb != NULL)
|
||||||
|
{
|
||||||
|
if (cb->gpio == gpio)
|
||||||
|
{
|
||||||
|
Py_XDECREF(cb->py_cb);
|
||||||
|
if (prev == NULL)
|
||||||
|
py_callbacks = cb->next;
|
||||||
|
else
|
||||||
|
prev->next = cb->next;
|
||||||
|
temp = cb;
|
||||||
|
cb = cb->next;
|
||||||
|
free(temp);
|
||||||
|
} else {
|
||||||
|
prev = cb;
|
||||||
|
cb = cb->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_edge_detect(gpio);
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// python function value = event_detected(channel)
|
||||||
|
static PyObject *py_event_detected(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
unsigned int gpio;
|
||||||
|
char *channel;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &channel))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (get_gpio_number(channel, &gpio))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (event_detected(gpio))
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
else
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// python function py_wait_for_edge(gpio, edge)
|
||||||
|
static PyObject *py_wait_for_edge(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
unsigned int gpio;
|
||||||
|
int edge, result;
|
||||||
|
char *channel;
|
||||||
|
char error[30];
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "si", &channel, &edge))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (get_gpio_number(channel, &gpio))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// check channel is setup as an input
|
||||||
|
if (!module_setup || gpio_direction[gpio] != INPUT)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is edge a valid value?
|
||||||
|
if (edge != RISING_EDGE && edge != FALLING_EDGE && edge != BOTH_EDGE)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_ValueError, "The edge must be set to RISING, FALLING or BOTH");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS // disable GIL
|
||||||
|
result = blocking_wait_for_edge(gpio, edge);
|
||||||
|
Py_END_ALLOW_THREADS // enable GIL
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
} else if (result == 2) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Edge detection events already enabled for this GPIO channel");
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
sprintf(error, "Error #%d waiting for edge", result);
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, error);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// python function value = gpio_function(gpio)
|
||||||
|
static PyObject *py_gpio_function(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
unsigned int gpio;
|
||||||
|
unsigned int value;
|
||||||
|
PyObject *func;
|
||||||
|
char *channel;
|
||||||
|
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &channel))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (get_gpio_number(channel, &gpio))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (setup_error)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_get_direction(gpio, &value);
|
||||||
|
func = Py_BuildValue("i", value);
|
||||||
|
return func;
|
||||||
|
}
|
||||||
|
|
||||||
|
// python function setwarnings(state)
|
||||||
|
static PyObject *py_setwarnings(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple(args, "i", &gpio_warnings))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (setup_error)
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char moduledocstring[] = "GPIO functionality of a CHIP using Python";
|
||||||
|
|
||||||
|
PyMethodDef gpio_methods[] = {
|
||||||
|
{"setup", (PyCFunction)py_setup_channel, METH_VARARGS | METH_KEYWORDS, "Set up the GPIO channel, direction and (optional) pull/up down control\nchannel - Either: RPi board pin number (not BCM GPIO 00..nn number). Pins start from 1\n or : BCM GPIO number\ndirection - INPUT or OUTPUT\n[pull_up_down] - PUD_OFF (default), PUD_UP or PUD_DOWN\n[initial] - Initial value for an output channel"},
|
||||||
|
{"cleanup", py_cleanup, METH_VARARGS, "Clean up by resetting all GPIO channels that have been used by this program to INPUT with no pullup/pulldown and no event detection"},
|
||||||
|
{"output", py_output_gpio, METH_VARARGS, "Output to a GPIO channel\ngpio - gpio channel\nvalue - 0/1 or False/True or LOW/HIGH"},
|
||||||
|
{"input", py_input_gpio, METH_VARARGS, "Input from a GPIO channel. Returns HIGH=1=True or LOW=0=False\ngpio - gpio channel"},
|
||||||
|
{"add_event_detect", (PyCFunction)py_add_event_detect, METH_VARARGS | METH_KEYWORDS, "Enable edge detection events for a particular GPIO channel.\nchannel - either board pin number or BCM number depending on which mode is set.\nedge - RISING, FALLING or BOTH\n[callback] - A callback function for the event (optional)\n[bouncetime] - Switch bounce timeout in ms for callback"},
|
||||||
|
{"remove_event_detect", py_remove_event_detect, METH_VARARGS, "Remove edge detection for a particular GPIO channel\ngpio - gpio channel"},
|
||||||
|
{"event_detected", py_event_detected, METH_VARARGS, "Returns True if an edge has occured on a given GPIO. You need to enable edge detection using add_event_detect() first.\ngpio - gpio channel"},
|
||||||
|
{"add_event_callback", (PyCFunction)py_add_event_callback, METH_VARARGS | METH_KEYWORDS, "Add a callback for an event already defined using add_event_detect()\ngpio - gpio channel\ncallback - a callback function\n[bouncetime] - Switch bounce timeout in ms"},
|
||||||
|
{"wait_for_edge", py_wait_for_edge, METH_VARARGS, "Wait for an edge.\ngpio - gpio channel\nedge - RISING, FALLING or BOTH"},
|
||||||
|
{"gpio_function", py_gpio_function, METH_VARARGS, "Return the current GPIO function (IN, OUT, ALT0)\ngpio - gpio channel"},
|
||||||
|
{"setwarnings", py_setwarnings, METH_VARARGS, "Enable or disable warning messages"},
|
||||||
|
{NULL, NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION > 2
|
||||||
|
static struct PyModuleDef rpigpiomodule = {
|
||||||
|
PyModuleDef_HEAD_INIT,
|
||||||
|
"GPIO", // name of module
|
||||||
|
moduledocstring, // module documentation, may be NULL
|
||||||
|
-1, // size of per-interpreter state of the module, or -1 if the module keeps state in global variables.
|
||||||
|
gpio_methods
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION > 2
|
||||||
|
PyMODINIT_FUNC PyInit_GPIO(void)
|
||||||
|
#else
|
||||||
|
PyMODINIT_FUNC initGPIO(void)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
PyObject *module = NULL;
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION > 2
|
||||||
|
if ((module = PyModule_Create(&rpigpiomodule)) == NULL)
|
||||||
|
return NULL;
|
||||||
|
#else
|
||||||
|
if ((module = Py_InitModule3("GPIO", gpio_methods, moduledocstring)) == NULL)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
define_constants(module);
|
||||||
|
|
||||||
|
if (!PyEval_ThreadsInitialized())
|
||||||
|
PyEval_InitThreads();
|
||||||
|
|
||||||
|
if (Py_AtExit(event_cleanup) != 0)
|
||||||
|
{
|
||||||
|
setup_error = 1;
|
||||||
|
event_cleanup();
|
||||||
|
#if PY_MAJOR_VERSION > 2
|
||||||
|
return NULL;
|
||||||
|
#else
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION > 2
|
||||||
|
return module;
|
||||||
|
#else
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
36
source/setup.py
Normal file
36
source/setup.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
try:
|
||||||
|
from overlays import builder
|
||||||
|
builder.compile()
|
||||||
|
builder.copy()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
import distribute_setup
|
||||||
|
distribute_setup.use_setuptools()
|
||||||
|
from setuptools import setup, Extension, find_packages
|
||||||
|
|
||||||
|
classifiers = ['Development Status :: 3 - Alpha',
|
||||||
|
'Operating System :: POSIX :: Linux',
|
||||||
|
'License :: OSI Approved :: MIT License',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'Programming Language :: Python :: 2.7',
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
'Topic :: Software Development',
|
||||||
|
'Topic :: Home Automation',
|
||||||
|
'Topic :: System :: Hardware']
|
||||||
|
|
||||||
|
setup(name = 'CHIP_IO',
|
||||||
|
version = '0.0.4',
|
||||||
|
author = 'Robert Wolterman',
|
||||||
|
author_email = 'robert.wolterman@gmail.com',
|
||||||
|
description = 'A module to control CHIP IO channels',
|
||||||
|
long_description = open('README.md').read() + open('CHANGELOG.rst').read(),
|
||||||
|
license = 'MIT',
|
||||||
|
keywords = 'CHIP NextThingCo IO GPIO PWM ADC',
|
||||||
|
url = 'https://github.com/xtacocorex/CHIP_IO/',
|
||||||
|
classifiers = classifiers,
|
||||||
|
packages = find_packages(),
|
||||||
|
ext_modules = [Extension('CHIP_IO.GPIO', ['source/py_gpio.c', 'source/event_gpio.c', 'source/constants.c', 'source/common.c'], extra_compile_args=['-Wno-format-security'])]) #,
|
||||||
|
# Extension('CHIP_IO.PWM', ['source/py_pwm.c', 'source/c_pwm.c', 'source/constants.c', 'source/common.c'], extra_compile_args=['-Wno-format-security']),
|
||||||
|
# Extension('CHIP_IO.ADC', ['source/py_adc.c', 'source/c_adc.c', 'source/constants.c', 'source/common.c'], extra_compile_args=['-Wno-format-security']),
|
||||||
|
# Extension('CHIP_IO.SPI', ['source/spimodule.c', 'source/constants.c', 'source/common.c'], extra_compile_args=['-Wno-format-security'])])
|
BIN
test/__pycache__/test_gpio_input.cpython-27-PYTEST.pyc
Normal file
BIN
test/__pycache__/test_gpio_input.cpython-27-PYTEST.pyc
Normal file
Binary file not shown.
BIN
test/__pycache__/test_gpio_output.cpython-27-PYTEST.pyc
Normal file
BIN
test/__pycache__/test_gpio_output.cpython-27-PYTEST.pyc
Normal file
Binary file not shown.
BIN
test/__pycache__/test_gpio_setup.cpython-27-PYTEST.pyc
Normal file
BIN
test/__pycache__/test_gpio_setup.cpython-27-PYTEST.pyc
Normal file
Binary file not shown.
35
test/gptest.py
Executable file
35
test/gptest.py
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import CHIP_IO.GPIO as GPIO
|
||||||
|
import time, os
|
||||||
|
|
||||||
|
print "SETUP CSIDO"
|
||||||
|
GPIO.setup("CSID0", GPIO.OUT)
|
||||||
|
|
||||||
|
#print os.path.exists('/sys/class/gpio/gpio132')
|
||||||
|
|
||||||
|
print "SETUP XIO-P1"
|
||||||
|
GPIO.setup("XIO-P1", GPIO.IN)
|
||||||
|
#GPIO.setup("U14_13", GPIO.IN)
|
||||||
|
|
||||||
|
print "READING XIO-P1"
|
||||||
|
GPIO.output("CSID0", GPIO.HIGH)
|
||||||
|
print "HIGH", GPIO.input("XIO-P1")
|
||||||
|
|
||||||
|
GPIO.output("CSID0", GPIO.LOW)
|
||||||
|
GPIO.output("CSID0", GPIO.LOW)
|
||||||
|
time.sleep(1)
|
||||||
|
print "LOW", GPIO.input("XIO-P1")
|
||||||
|
|
||||||
|
GPIO.output("CSID0", GPIO.HIGH)
|
||||||
|
GPIO.output("CSID0", GPIO.HIGH)
|
||||||
|
print "HIGH", GPIO.input("XIO-P1")
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
GPIO.output("CSID0", GPIO.LOW)
|
||||||
|
GPIO.output("CSID0", GPIO.LOW)
|
||||||
|
print "LOW", GPIO.input("XIO-P1")
|
||||||
|
|
||||||
|
print "CLEANUP"
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
24
test/test_gpio_input.py
Executable file
24
test/test_gpio_input.py
Executable file
@ -0,0 +1,24 @@
|
|||||||
|
import pytest
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
import CHIP_IO.GPIO as GPIO
|
||||||
|
|
||||||
|
def teardown_module(module):
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
class TestGPIOInput:
|
||||||
|
def test_input(self):
|
||||||
|
GPIO.setup("CSID6", GPIO.IN)
|
||||||
|
#returned as an int type
|
||||||
|
input_value = GPIO.input("CSID6")
|
||||||
|
#value read from the file will have a \n new line
|
||||||
|
value = open('/sys/class/gpio/gpio138/value').read()
|
||||||
|
assert int(value) == input_value
|
||||||
|
time.sleep(30)
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
def test_direction_readback(self):
|
||||||
|
GPIO.setup("CSID6", GPIO.IN)
|
||||||
|
direction = GPIO.gpio_function("CSID6")
|
||||||
|
assert direction == GPIO.IN
|
44
test/test_gpio_output.py
Normal file
44
test/test_gpio_output.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import pytest
|
||||||
|
import os
|
||||||
|
|
||||||
|
import CHIP_IO.GPIO as GPIO
|
||||||
|
|
||||||
|
def teardown_module(module):
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
class TestGPIOOutput:
|
||||||
|
def test_output_high(self):
|
||||||
|
GPIO.setup("CSID6", GPIO.OUT)
|
||||||
|
GPIO.output("CSID6", GPIO.HIGH)
|
||||||
|
value = open('/sys/class/gpio/gpio138/value').read()
|
||||||
|
assert int(value)
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
def test_output_low(self):
|
||||||
|
GPIO.setup("CSID6", GPIO.OUT)
|
||||||
|
GPIO.output("CSID6", GPIO.LOW)
|
||||||
|
value = open('/sys/class/gpio/gpio138/value').read()
|
||||||
|
assert not int(value)
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
def test_direction_readback(self):
|
||||||
|
GPIO.setup("CSID6", GPIO.OUT)
|
||||||
|
direction = GPIO.gpio_function("CSID6")
|
||||||
|
assert direction == GPIO.OUT
|
||||||
|
def test_output_greater_than_one(self):
|
||||||
|
GPIO.setup("CSID6", GPIO.OUT)
|
||||||
|
GPIO.output("CSID6", 2)
|
||||||
|
value = open('/sys/class/gpio/gpio138/value').read()
|
||||||
|
assert int(value)
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
def test_output_of_pin_not_setup(self):
|
||||||
|
with pytest.raises(RuntimeError):
|
||||||
|
GPIO.output("CSID7", GPIO.LOW)
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
def test_output_setup_as_input(self):
|
||||||
|
GPIO.setup("CSID6", GPIO.IN)
|
||||||
|
with pytest.raises(RuntimeError):
|
||||||
|
GPIO.output("CSID6", GPIO.LOW)
|
||||||
|
GPIO.cleanup()
|
72
test/test_gpio_setup.py
Normal file
72
test/test_gpio_setup.py
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import pytest
|
||||||
|
import os
|
||||||
|
|
||||||
|
import CHIP_IO.GPIO as GPIO
|
||||||
|
|
||||||
|
def teardown_module(module):
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
class TestSetup:
|
||||||
|
def test_setup_output_key(self):
|
||||||
|
GPIO.setup("U14_37", GPIO.OUT)
|
||||||
|
assert os.path.exists('/sys/class/gpio/gpio138')
|
||||||
|
direction = open('/sys/class/gpio/gpio138/direction').read()
|
||||||
|
assert direction == 'out\n'
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
def test_setup_output_name(self):
|
||||||
|
GPIO.setup("CSID6", GPIO.OUT)
|
||||||
|
assert os.path.exists('/sys/class/gpio/gpio138')
|
||||||
|
direction = open('/sys/class/gpio/gpio138/direction').read()
|
||||||
|
assert direction == 'out\n'
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
def test_setup_input_key(self):
|
||||||
|
GPIO.setup("U14_37", GPIO.IN)
|
||||||
|
assert os.path.exists('/sys/class/gpio/gpio138')
|
||||||
|
direction = open('/sys/class/gpio/gpio138/direction').read()
|
||||||
|
assert direction == 'in\n'
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
def test_setup_input_name(self):
|
||||||
|
GPIO.setup("CSID6", GPIO.IN)
|
||||||
|
assert os.path.exists('/sys/class/gpio/gpio138')
|
||||||
|
direction = open('/sys/class/gpio/gpio138/direction').read()
|
||||||
|
assert direction == 'in\n'
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
def test_setup_input_pull_up(self):
|
||||||
|
GPIO.setup("U14_37", GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
||||||
|
assert os.path.exists('/sys/class/gpio/gpio138')
|
||||||
|
direction = open('/sys/class/gpio/gpio138/direction').read()
|
||||||
|
assert direction == 'in\n'
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
def test_setup_input_pull_down(self):
|
||||||
|
GPIO.setup("U14_37", GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||||
|
assert os.path.exists('/sys/class/gpio/gpio138')
|
||||||
|
direction = open('/sys/class/gpio/gpio138/direction').read()
|
||||||
|
assert direction == 'in\n'
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
def test_setup_cleanup(self):
|
||||||
|
GPIO.setup("U14_37", GPIO.OUT)
|
||||||
|
assert os.path.exists('/sys/class/gpio/gpio138')
|
||||||
|
GPIO.cleanup()
|
||||||
|
assert not os.path.exists('/sys/class/gpio/gpio138')
|
||||||
|
|
||||||
|
def test_setup_failed_type_error(self):
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
GPIO.setup("U14_37", "WEIRD")
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
def test_setup_failed_value_error(self):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
GPIO.setup("U14_37", 3)
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
def test_setup_expanded_gpio(self):
|
||||||
|
GPIO.setup("XIO-P1", GPIO.OUT)
|
||||||
|
assert os.path.exists('/sys/class/gpio/gpio409')
|
||||||
|
GPIO.cleanup()
|
||||||
|
assert not os.path.exists('/sys/class/gpio/gpio409')
|
11
tox.ini
Normal file
11
tox.ini
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Tox (http://tox.testrun.org/) is a tool for running tests
|
||||||
|
# in multiple virtualenvs. This configuration file will run the
|
||||||
|
# test suite on all supported python versions. To use it, "pip install tox"
|
||||||
|
# and then run "tox" from this directory.
|
||||||
|
|
||||||
|
[tox]
|
||||||
|
envlist = py27, py34
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
commands =
|
||||||
|
deps =
|
Reference in New Issue
Block a user