1
0
mirror of https://github.com/xtacocorex/CHIP_IO synced 2025-07-20 12:53:22 +00:00

52 Commits

Author SHA1 Message Date
7489fd21b4 Removing i2c-1 custom support in OverlayManager as it's back in 4.4.13, this is to close #31. Update to version 0.2.5 2016-12-31 05:10:26 +00:00
87303b6083 fixed the issue with the softpwm pytest code for #22 2016-12-31 04:52:57 +00:00
8aa402fbd5 mods to test_pwm_setup.py to mark some tests that are failing as expected to fail (#22). the issue appears to be the pwm cleanup stuff. added some code to help with future work 2016-12-31 04:37:24 +00:00
e82f62133a Closing out #17 and #18, version upped to 0.2.4 2016-12-31 02:19:57 +00:00
993ea29213 added the unexport_all() function to CHIP_IO.Utilities to address #18 2016-12-31 02:09:30 +00:00
7d91bbc47e fixes for #17, hardware pwm works now, still can't change polarity, but i think that's a kernel driver/dtb thing. 2016-12-31 01:43:42 +00:00
b12c0ad2fe Merge branch 'master' into hotfix/hwpwmfix 2016-12-30 17:16:17 +00:00
5d8c0f6aaa removing time step in the makefile as the CHIP doesn't have ntpdate installed by default (at least in headless OS) 2016-12-30 16:43:14 +00:00
4aaff04375 removing ropeproject file in test directory 2016-12-30 16:42:10 +00:00
eeb98d468f Merge pull request #39 from blueSolder/master
working
2016-12-26 07:43:41 -06:00
51c38843d9 Add files via upload 2016-12-26 16:34:47 +11:00
5aa08351c2 Merge pull request #37 from zerotri/patch-1
Add 'TARGET_DIR' prefix env var to builder.py
2016-12-16 18:24:42 -06:00
9d7fb634a3 Add 'TARGET_DIR' prefix env var to builder.py
This allows CHIP_IO to build and install successfully in buildroot.
2016-12-16 15:32:02 -08:00
3cd69cfe93 Updating the Makefile to aid in the package and publish to pypi 2016-12-02 01:15:01 +00:00
cf9916018b Merge pull request #33 from WereCatf/master
Improve the code for setting the 1V8-pin, including get-function
2016-12-01 10:31:40 -06:00
e0c65de9a8 Update README.rst 2016-12-01 18:18:17 +02:00
794ce98ed2 Improve the code for setting the 1V8-pin, including get-function 2016-12-01 17:47:11 +02:00
617f562b1c Merge pull request #30 from xtacocorex/feature/lradc
LRADC support
2016-12-01 08:25:09 -06:00
89cbea038e LRADC support to close out feature #15. Added Utilities to enable and disable the 1.8v pin on U13. Updated README. Updated version to 2.3 2016-12-01 05:55:26 +00:00
82d6fef173 checking in debug stuff for the hw pwm issue #17 2016-09-24 14:22:05 -05:00
e2173f0235 Merge pull request #23 from streamnsight/streamnsight-patch-1-3
update readme indent / code
2016-09-22 10:49:46 -05:00
30593306a3 update readme indent / code 2016-09-22 08:45:03 -07:00
a9902d1267 Updating the readme to add Python3 installation process 2016-09-18 19:15:44 -05:00
fcd5afcdc8 Merge pull request #20 from fabien-gigante/master
Minor enhancement to C library (only)
2016-08-26 10:58:38 -05:00
d66032ed93 Merge pull request #1 from fabien-gigante/patch-1
Patch 1
2016-08-26 16:29:18 +02:00
9a83cf765a Update py_gpio.c
allow passing data arguments to c callbacks
2016-08-26 16:06:43 +02:00
d95847eb5a Update event_gpio.c
allow passing data arguments to c callbacks
2016-08-26 16:05:25 +02:00
12bc9dec67 Update event_gpio.h
allow passing data arguments to c callbacks
2016-08-26 16:03:09 +02:00
29eb018e78 Update common.c
unnecessary include of Python
2016-08-26 15:57:07 +02:00
ee0e27cb22 Update c_softpwm.c
unnecessary include of Python
2016-08-26 15:55:43 +02:00
c8e4323c27 Updating spwmtest.py to check for Issue #16. Updated Changelog and version to 0.2.2 2016-07-30 14:46:25 -05:00
1e3e801e60 Adds runtime err if softpwm fails for Issue #16 2016-07-28 12:49:28 +00:00
40ae9a5cdc Merge pull request #12 from xtacocorex/feature/overlays
Feature/overlays
2016-07-25 19:48:21 -05:00
20b72490f2 Merging in the latest master for Issue #10, PR #12 2016-07-25 19:47:05 -05:00
7e83fa8435 Updating version to 0.1.2, fixing the SoftPWM verification test case 2016-07-25 19:38:27 -05:00
c3448ec661 Fixes softpwm mutex stallout and assert 2016-07-25 14:27:31 +00:00
42e17edc4a Merge branch 'master' of github.com:xtacocorex/CHIP_IO 2016-07-24 21:37:54 -05:00
b180fe1d6f Adding my test code for Issue #14 2016-07-24 21:37:11 -05:00
a62a26dae0 Adding Manifest file for pypi to enable pip installation 2016-07-22 23:27:46 -05:00
0ed1cfb352 Updating the builder script to let the user know what's happening. PR#12, Issue #10 2016-07-20 08:49:42 -05:00
4f6acf4676 Pull Request #12 fixes for Issue #10. 2016-07-19 21:03:40 -05:00
01347416ab Update to Issue #10 that fixes the errors on SPI loading. Have to not set spidev as compatible for spidev. Such meta, much fail, wow 2016-07-17 14:23:55 -05:00
e270080af8 Last commit for #10 to get the Overlay Manager implemented. i2c-1 still shows up as i2c-3, but everything should work. Will add new bug to investigate. Bumping rev to 0.2.0 as this is a big feature. Custom Overlay should work now 2016-07-16 17:33:09 -05:00
44121ed5eb Fixed SPI dtbo and verification. i2c-1 is still off, waiting to hear back from NTC crew on that. Added test case for the OverlayManager. Fof feature #10 2016-07-16 15:23:43 -05:00
00140c2008 Totally forgot to add the OverlayManager code in the last commit. This update is for #10 2016-07-16 13:49:29 -05:00
ee8445918e More work on #10. PWM0 Loading is complete and verified, i2c-1 loading loads to i2c-3, verification fails, spi2 is loaded, but no verification. No work on custom overlay loading. Fixed issues with test_pwm_setup.py; only 2 tests fail now (when PWM0 is loaded 2016-07-16 10:45:13 -05:00
1c4168cf0d Start of the overlay feature, grabbed the sample dts from CHIP-dt-overlay, modified builder.py from the BeagleBone Black repo 2016-07-15 23:32:44 -05:00
ea4a21235d Some refactoring of the edge detection code to clean stuff up, added more tests 2016-07-11 21:14:40 -05:00
bff65d346d Initial work at refactoring the edge detection code I added to get it working 2016-07-10 22:00:01 -05:00
a4dd1558f0 Realized that the AP-EINT1/3 test code wasn't actually testing callbacks, they do work properly in my testing. Reverting gptest.py to what it was. Revision Update. Issue #9 is resolved. 2016-07-10 19:23:45 -05:00
3d1ecb6b5e Edge detection callback is now working for the XIO's. Blocking wait_for_edge works for both the AP-EINT1/3 and the XIO's. Need to figure out why AP-EINT1/3 don't work for the callback. This is to help fix issue #9. 2016-07-10 16:37:22 -05:00
db4493322d Inital attempt at fixing #9. Things are still broken. wait_for_edge no longer works on AP-EINT1/3, XIO will trigger only one on falling edge. 2016-07-10 14:56:40 -05:00
35 changed files with 1688 additions and 321 deletions

View File

@ -1,3 +1,58 @@
0.2.5
----
* Updates to the pytest code for HWPWM and SoftPWM
* Removed the i2c-1 load/unload support in OverlayManager as CHIP Kernel 4.4.13 has that bus brought back by default
0.2.4
----
* HW PWM Fixed
- Start/Stop/Duty Cycle/Frequency settings work
- Polarity cannot be changed, so don't bother setting it to 1 in start()
* Added the unexport_all() function to Utilites
0.2.3
----
* LRADC Support
* Added Utilities
- Enable/Disable the 1.8V Pin
- Change 1.8V Pin to output either 2.0V, 2.6V, or 3.3V
(Current limited to 50mA)
0.2.2
----
* Fixes for Issue #16
- Pass SoftPWM setup errors to Python layer (aninternetof)
- Updated spwmtest.py to test for this issue
0.2.1
----
* Pull request #12 fixes:
- Fixed indent in the i2c-1 dts
- Removed import dependencies in the SPI and PWM overlays
- Re-enabled building of the dtbo on setup.py install
0.2.0
----
* Added the ability to load DTB Overlays from within CHIP_IO
- Support for PWM0, SPI2, and I2C-1 (which comes back as i2c-3 on the 4.4 CHIP
- Support for a custom DTB Overlay
* Fixes to the pwm unit test, all but 2 now pass :)
0.1.2
----
* SoftPWM Fix by aninternetof
* Added a verification test for SoftPWM
0.1.1
----
* Some refactoring of the edge detection code, made it function better
* Added Rising and Both edge detection tests to gptest.py
- Small issue with both edge triggering double pumping on first callback hit
0.1.0
----
* Fixed edge detection code, will trigger proper for callbacks now
0.0.9
----
* Fixed SoftPWM segfault

228
CHIP_IO/LRADC.py Normal file
View File

@ -0,0 +1,228 @@
# Copyright (c) 2016 Robert Wolterman
#
# 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.
import os
import time
# Global Variables
DEBUG = False
DEVICE_EXIST = True
# Default Sample Rate Variables
SAMPLE_RATE_32P25 = 32.25
SAMPLE_RATE_62O5 = 62.5
SAMPLE_RATE_125 = 125
SAMPLE_RATE_250 = 250
SAMPLE_RATES = []
# Scale Factor
SCALE_FACTOR = 31.25
# File Locations
LRADC_BASE_DEVICE_FILE = "/sys/bus/iio/devices/iio:device0"
AVAILABLE_SAMPLE_RATE_FILE = "/sampling_frequency_available"
SCALE_FACTOR_FILE = "/in_voltage_scale"
CURRENT_SAMPLE_RATE_FILE = "/in_voltage_sampling_frequency"
RAW_VOLTAGE_CHAN0_FILE = "/in_voltage0_raw"
RAW_VOLTAGE_CHAN1_FILE = "/in_voltage1_raw"
def enable_debug():
global DEBUG
DEBUG = True
def setup(rate=250):
# First we determine if the device exists
if not os.path.exists(LRADC_BASE_DEVICE_FILE):
global DEVICE_EXIST
DEVICE_EXIST = False
raise Exception("LRADC Device does not exist")
else:
# Set the Sample Rate
set_sample_rate(rate)
def get_device_exist():
return DEVICE_EXIST
def get_scale_factor():
# If we do not have a device, lets throw an exception
if not DEVICE_EXIST:
raise Exception("LRADC Device does not exist")
# Get the data from the file
f = open(LRADC_BASE_DEVICE_FILE+SCALE_FACTOR_FILE,"r")
dat = f.readline()
f.close()
# Set the Scale Factor
global SCALE_FACTOR
SCALE_FACTOR = float(dat.strip())
# Debug
if DEBUG:
print("Current LRADC Scaling Factor: {0}").format(SCALE_FACTOR)
return SCALE_FACTOR
def get_allowable_sample_rates():
# If we do not have a device, lets throw an exception
if not DEVICE_EXIST:
raise Exception("LRADC Device does not exist")
# Get the data from the file
f = open(LRADC_BASE_DEVICE_FILE+AVAILABLE_SAMPLE_RATE_FILE,"r")
dat = f.readline()
f.close()
global SAMPLE_RATES
tmp = dat.strip().split(" ")
for i in xrange(len(tmp)):
if "." in tmp[i]:
tmp[i] = float(tmp[i])
else:
tmp[i] = int(tmp[i])
SAMPLE_RATES = tmp
# Debug
if DEBUG:
print("Allowable Sampling Rates:")
for rate in SAMPLE_RATES:
print("{0}").format(rate)
return tuple(SAMPLE_RATES)
def set_sample_rate(rate):
# If we do not have a device, lets throw an exception
if not DEVICE_EXIST:
raise Exception("LRADC Device does not exist")
# Debug
if DEBUG:
print("Setting Sample Rate to: {0}").format(rate)
# Check to see if the rates were gathered already
global SAMPLE_RATES
if SAMPLE_RATES == []:
tmp = get_allowable_sample_rates()
# Range check the input rate
if rate not in SAMPLE_RATES:
raise ValueError("Input Rate an Acceptable Value")
# Write the rate
f = open(LRADC_BASE_DEVICE_FILE+CURRENT_SAMPLE_RATE_FILE,"w")
mystr = "%.2f" % rate
f.write(mystr)
f.close()
# Verify write went well
crate = get_sample_rate()
if crate != rate:
raise Exception("Unable to write new Sampling Rate")
def get_sample_rate():
# If we do not have a device, lets throw an exception
if not DEVICE_EXIST:
raise Exception("LRADC Device does not exist")
# Get the data from the file
f = open(LRADC_BASE_DEVICE_FILE+CURRENT_SAMPLE_RATE_FILE,"r")
dat = f.read()
f.close()
dat = dat.strip()
if "." in dat:
dat = float(dat)
else:
dat = int(dat)
# Debug
if DEBUG:
print("Current Sampling Rate: {0}").format(dat)
return dat
def get_chan0_raw():
# If we do not have a device, lets throw an exception
if not DEVICE_EXIST:
raise Exception("LRADC Device does not exist")
# Get the data from the file
f = open(LRADC_BASE_DEVICE_FILE+RAW_VOLTAGE_CHAN0_FILE,"r")
dat = f.readline()
f.close()
dat = float(dat.strip())
# Debug
if DEBUG:
print("CHAN0 RAW: {0}").format(dat)
return dat
def get_chan1_raw():
# If we do not have a device, lets throw an exception
if not DEVICE_EXIST:
raise Exception("LRADC Device does not exist")
# Get the data from the file
f = open(LRADC_BASE_DEVICE_FILE+RAW_VOLTAGE_CHAN1_FILE,"r")
dat = f.readline()
f.close()
dat = float(dat.strip())
# Debug
if DEBUG:
print("CHAN1 RAW: {0}").format(dat)
return dat
def get_chan0():
# If we do not have a device, lets throw an exception
if not DEVICE_EXIST:
raise Exception("LRADC Device does not exist")
# Get the raw data first
dat = get_chan0_raw()
# Apply scale factor
dat *= SCALE_FACTOR
# Debug
if DEBUG:
print("CHAN0: {0}").format(dat)
return dat
def get_chan1():
# If we do not have a device, lets throw an exception
if not DEVICE_EXIST:
raise Exception("LRADC Device does not exist")
# Get the raw data first
dat = get_chan1_raw()
# Apply scale factor
dat *= SCALE_FACTOR
# Debug
if DEBUG:
print("CHAN1: {0}").format(dat)
return dat

197
CHIP_IO/OverlayManager.py Normal file
View File

@ -0,0 +1,197 @@
# Copyright (c) 2016 Robert Wolterman
#
# 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.
import os
import shutil
import time
DEBUG = False
OVERLAYINSTALLPATH = "/lib/firmware/chip_io"
OVERLAYCONFIGPATH = "/sys/kernel/config/device-tree/overlays"
CUSTOMOVERLAYFILEPATH = ""
PWMSYSFSPATH = "/sys/class/pwm/pwmchip0"
# USING THE BASE DIRECTORY FOR SPI AS THE DEVICE NUMBER CHANGES ON LOAD/UNLOAD
SPI2SYSFSPATH = "/sys/class/spi_master/"
# LOADED VARIABLES
# DO NOT MODIFY BY HAND WHEN USING
# AS IT COULD BREAK FUNCTIONALITY
_LOADED = {
"SPI2" : False,
"PWM0" : False,
"CUST" : False
}
_OVERLAYS = {
"SPI2" : "chip-spi2.dtbo",
"PWM0" : "chip-pwm0.dtbo",
"CUST" : ""
}
_FOLDERS = {
"SPI2" : "chip-spi",
"PWM0" : "chip-pwm",
"CUST" : "chip-cust"
}
def enable_debug():
global DEBUG
DEBUG = True
def get_spi_loaded():
"""
get_spi_loaded - Returns True/False based upon if the spi2 Overlay is loaded
"""
global _LOADED
return _LOADED["SPI2"]
def get_pwm_loaded():
"""
get_pwm_loaded - Returns True/False based upon if the pwm0 Overlay is loaded
"""
global _LOADED
return _LOADED["PWM0"]
def get_custom_loaded():
"""
get_custom_loaded - Returns True/False based upon if a Custom Overlay is loaded
"""
global _LOADED
return _LOADED["CUST"]
def _set_overlay_verify(name, overlay_path, config_path):
"""
_set_overlay_verify - Function to load the overlay and verify it was setup properly
"""
global DEBUG
# VERIFY PATH IS NOT THERE
if os.path.exists(config_path):
print("Config path already exists! Not moving forward")
print("config_path: {0}".format(config_path))
return -1
# MAKE THE CONFIGURATION PATH
os.makedirs(config_path)
# CAT THE OVERLAY INTO THE CONFIG FILESYSTEM
with open(config_path + "/dtbo", 'wb') as outfile:
with open(overlay_path, 'rb') as infile:
shutil.copyfileobj(infile, outfile)
# SLEEP TO ENABLE THE KERNEL TO DO ITS JOB
time.sleep(0.2)
# VERIFY
if name == "CUST":
# BLINDLY ACCEPT THAT IT LOADED
return 0
elif name == "PWM0":
if os.path.exists(PWMSYSFSPATH):
if DEBUG:
print("PWM IS LOADED!")
return 0
else:
if DEBUG:
print("ERROR LOAIDNG PWM0")
return 1
elif name == "SPI2":
if os.listdir(SPI2SYSFSPATH) != "":
if DEBUG:
print("SPI2 IS LOADED!")
return 0
else:
if DEBUG:
print("ERROR LOADING SPI2")
return 0
def load(overlay, path=""):
"""
load - Load a DTB Overlay
Inputs:
overlay - Overlay Key: SPI2, PWM0, CUST
path - Full Path to where the custom overlay is stored
Returns:
0 - Successful Load
1 - Unsuccessful Load
2 - Overlay was previously set
"""
global DEBUG
global _LOADED
if DEBUG:
print("LOAD OVERLAY: {0} @ {1}".format(overlay,path))
# SEE IF OUR OVERLAY NAME IS IN THE KEYS
if overlay.upper() in _OVERLAYS.keys():
cpath = OVERLAYCONFIGPATH + "/" + _FOLDERS[overlay.upper()]
if DEBUG:
print("VALID OVERLAY")
print("CONFIG PATH: {0}".format(cpath))
# CHECK TO SEE IF WE HAVE A PATH FOR CUSTOM OVERLAY
if overlay.upper() == "CUST" and path == "":
raise ValueError("Path must be specified for Custom Overlay Choice")
elif overlay.upper() == "CUST" and _LOADED[overlay.upper()]:
print("Custom Overlay already loaded")
return 2
elif overlay.upper() == "CUST" and not os.path.exists(path):
print("Custom Overlay path does not exist")
return 1
# SET UP THE OVERLAY PATH FOR OUR USE
if overlay.upper() != "CUST":
opath = OVERLAYINSTALLPATH + "/" + _OVERLAYS[overlay.upper()]
else:
opath = path
if DEBUG:
print("OVERLAY PATH: {0}".format(opath))
if overlay.upper() == "PWM0" and _LOADED[overlay.upper()]:
print("PWM0 Overlay already loaded")
return 2
if overlay.upper() == "SPI2" and _LOADED[overlay.upper()]:
print("SPI2 Overlay already loaded")
return 2
# LOAD THE OVERLAY
errc = _set_overlay_verify(overlay.upper(), opath, cpath)
if DEBUG:
print("_SET_OVERLAY_VERIFY ERRC: {0}".format(errc))
if errc == 0:
_LOADED[overlay.upper()] = True
else:
raise ValueError("Invalid Overlay name specified! Choose between: SPI2, PWM0, CUST")
def unload(overlay):
global DEBUG
global _LOADED
if DEBUG:
print("UNLOAD OVERLAY: {0}".format(overlay))
# SEE IF OUR OVERLAY NAME IS IN THE KEYS
if overlay.upper() in _OVERLAYS.keys():
# BRUTE FORCE REMOVE AS THE DIRECTORY CONTAINS FILES
os.system('rmdir \"{}\"'.format(OVERLAYCONFIGPATH + "/" + _FOLDERS[overlay.upper()]))
_LOADED[overlay.upper()] = False
else:
raise ValueError("Invalid Overlay name specified! Choose between: SPI2, PWM0, CUST")

79
CHIP_IO/Utilities.py Normal file
View File

@ -0,0 +1,79 @@
# Copyright (c) 2016 Robert Wolterman
#
# 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.
# CHIP_IO Utilities
# Random functions to enable fun stuff on the CHIP!
# Credit goes to nonokuono (https://bbs.nextthing.co/users/nonokunono)
# for gathering the i2cset commands from the AXP-209 datasheet for 2.0, 2.6, and 3.3V output
# and for figuring out the ADC setup on the AXP-209
import subprocess
import glob
import re
# Set the 1.8V-pin on the CHIP U13-header to given voltage
# Return False on error
def set_1v8_pin_voltage(voltage):
if not isinstance(voltage, int) and not isinstance(voltage, float):
return False
if voltage < 1.8 or voltage > 3.3:
return False
voltage=round((voltage - 1.8) / 0.1) << 4
if subprocess.call(["/usr/sbin/i2cset", "-f", "-y" ,"0", "0x34", "0x90", "0x03"]):
return False
if subprocess.call(["/usr/sbin/i2cset", "-f", "-y", "0", "0x34", "0x91", str(voltage)]):
return False
return True
# Get the voltage the 1.8V-pin on the CHIP U13-header has been configured as
# Return False on error
def get_1v8_pin_voltage():
p=subprocess.Popen(["/usr/sbin/i2cget", "-f", "-y", "0", "0x34", "0x90"], stdout=subprocess.PIPE)
output=p.communicate()[0].decode("utf-8").strip()
#Not configured as an output
if output != "0x03":
return False
p=subprocess.Popen(["/usr/sbin/i2cget", "-f", "-y", "0", "0x34", "0x91"], stdout=subprocess.PIPE)
output=p.communicate()[0].decode("utf-8").strip()
voltage=round((int(output, 16) >> 4) * 0.1 + 1.8, 1)
return voltage
# Enable 1.8V Pin on CHIP U13 Header
def enable_1v8_pin():
set_1v8_pin_voltage(1.8)
# Disable 1.8V Pin on CHIP U13 Header
def disable_1v8_pin():
# CANNOT USE I2C LIB AS WE NEED TO FORCE THE COMMAND DUE TO THE KERNEL OWNING THE DEVICE
# First we have to write 0x05 to AXP-209 Register 0x91
subprocess.call('/usr/sbin/i2cset -f -y 0 0x34 0x91 0x05', shell=True)
# Then we have to write 0x07 to AXP-209 Register 0x90
subprocess.call('/usr/sbin/i2cset -f -y 0 0x34 0x90 0x07', shell=True)
# Unexport All
def unexport_all():
gpios = glob.glob("/sys/class/gpio/gpio[0-9]*")
for g in gpios:
tmp = g.split("/")
gpio = tmp[4]
num = re.sub("[a-z]","",gpio)
cmd = "echo " + num + " > /sys/class/gpio/unexport"
subprocess.Popen(cmd,shell=True, stdout=subprocess.PIPE)

5
MANIFEST.in Normal file
View File

@ -0,0 +1,5 @@
include distribute_setup.py
include README.rst
include CHANGELOG.rst
recursive-include source *.h
recursive-include overlays *.dts *.py

View File

@ -1,8 +1,8 @@
time:
/usr/bin/ntpdate -b -s -u pool.ntp.org
package: clean
python setup.py sdist
publish: clean
python setup.py sdist upload
publish: package
twine upload dist/*
clean:
rm -rf CHIP_IO.* build dist

View File

@ -2,22 +2,45 @@ CHIP_IO
============================
A CHIP GPIO library
NOTE: Now requires the custom DTC to install the library
Manual::
sudo ntpdate pool.ntp.org
For Python2.7::
sudo apt-get update
sudo apt-get install git build-essential python-dev python-pip -y
sudo apt-get install git build-essential python-dev python-pip flex bison -y
git clone https://github.com/atenart/dtc
cd dtc
make
sudo make install PREFIX=/usr
cd ..
git clone git://github.com/xtacocorex/CHIP_IO.git
cd CHIP_IO
sudo python setup.py install
cd ..
sudo rm -rf CHIP_IO
For Python3::
sudo apt-get update
sudo apt-get install git build-essential python3-dev python3-pip flex bison -y
git clone https://github.com/atenart/dtc
cd dtc
make
sudo make install PREFIX=/usr
cd ..
git clone git://github.com/xtacocorex/CHIP_IO.git
cd CHIP_IO
sudo python3 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.
All scripts that require GPIO and PWM (HW and/or SW) access need to be run with super user permissions!
All scripts that require GPIO, PWM (HW and/or SW), and Overlay Manager need to be run with super user permissions!
**Allowable Pin Names for the Library**
@ -170,10 +193,10 @@ Polling inputs::
Waiting for an edge (GPIO.RISING, GPIO.FALLING, or GPIO.BOTH::
This only works for the AP-EINT1, AP-EINT3, and XPO Pins on the CHIP
GPIO.wait_for_edge(channel, GPIO.RISING)
This only works for the AP-EINT1, AP-EINT3, and XPO Pins on the CHIP
Detecting events::
GPIO.setup("XIO-P0", GPIO.IN)
@ -192,46 +215,124 @@ To clean up the GPIO when done, do the following::
**PWM**::
Hardware PWM requires a DTB Overlay loaded on the CHIP to allow the kernel to know there is a PWM device available to use.
::
import CHIP_IO.PWM as PWM
#PWM.start(channel, duty, freq=2000, polarity=0)
#duty values are valid 0 (off) to 100 (on)
PWM.start("PWM0", 50)
PWM.set_duty_cycle("PWM0", 25.5)
PWM.set_frequency("PWM0", 10)
# To stop PWM
PWM.stop("PWM0")
PWM.cleanup()
#set polarity to 1 on start:
#For specific polarity: this example sets polarity to 1 on start:
PWM.start("PWM0", 50, 2000, 1)
**SOFTPWM**::
import CHIP_IO.SOFTPWM as PWM
#PWM.start(channel, duty, freq=2000, polarity=0)
import CHIP_IO.SOFTPWM as SPWM
#SPWM.start(channel, duty, freq=2000, polarity=0)
#duty values are valid 0 (off) to 100 (on)
#you can choose any pin
PWM.start("XIO-P7", 50)
PWM.set_duty_cycle("XIO-P7", 25.5)
PWM.set_frequency("XIO-P7", 10)
PWM.stop("XIO-P7")
PWM.cleanup()
#set polarity to 1 on start:
PWM.start("XIO-P7", 50, 2000, 1)
SPWM.start("XIO-P7", 50)
SPWM.set_duty_cycle("XIO-P7", 25.5)
SPWM.set_frequency("XIO-P7", 10)
# To Stop SPWM
SPWM.stop("XIO-P7")
SPWM.cleanup()
#For specific polarity: this example sets polarity to 1 on start:
SPWM.start("XIO-P7", 50, 2000, 1)
Use SOFTPWM at low speeds (hundreds of Hz) for the best results. Do not use for anything that needs high precision or reliability.
**ADC**::
If using SOFTPWM and PWM at the same time, import CHIP_IO.SOFTPWM as SPWM or something different than PWM as to not confuse the library.
Not Implemented yet
**LRADC**::
The LRADC was enabled in the 4.4.13-ntc-mlc. This is a 6 bit ADC that is 2 Volt tolerant.
Sample code below details how to talk to the LRADC.::
import CHIP_IO.LRADC as ADC
# Enable Debug
ADC.enable_debug()
# Check to see if the LRADC Device exists
# Returns True/False
ADC.get_device_exists()
# Setup the LRADC
# Specify a sampling rate if needed
ADC.setup(rate)
# Get the Scale Factor
factor = ADC.get_scale_factor()
# Get the allowable Sampling Rates
sampleratestuple = ADC.get_allowable_sample_rates()
# Set the sampling rate
ADC.set_sample_rate(rate)
# Get the current sampling rate
currentrate = ADC.get_sample_rate()
# Get the Raw Channel 0 or 1 data
raw = ADC.get_chan0_raw()
raw = ADC.get_chan1_raw()
# Get the factored ADC Channel data
fulldata = ADC.get_chan0()
fulldata = ADC.get_chan1()
**SPI**::
SPI requires a DTB Overlay to access. CHIP_IO does not contain any SPI specific code as the Python spidev module works when it can see the SPI bus.
**Overlay Manager**::
The Overlay Manager enables you to quickly load simple Device Tree Overlays. The options for loading are:
PWM0, SPI2, I2C1, CUST
Only one of each type of overlay can be loaded at a time, but all three options can be loaded simultaneously. So you can have SPI2 and I2C1 without PWM0, but you cannot have SPI2 loaded twice.
::
import CHIP_IO.OverlayManager as OM
# The enable_debug() function turns on debug printing
#OM.enable_debug()
# To load an overlay, feed in the name to load()
OM.load("PWM0")
# To verify the overlay was properly loaded, the get_ functions return booleans
OM.get_pwm_loaded()
OM.get_spi_loaded()
# To unload an overlay, feed in the name to unload()
OM.unload("PWM0")
To use a custom overlay, you must build and compile it properly per the DIP Docs: http://docs.getchip.com/dip.html#development-by-example
There is no verification that the Custom Overlay is setup properly, it's fire and forget
::
import CHIP_IO.OverlayManager as OM
# The full path to the dtbo file needs to be specified
OM.load("CUST","/home/chip/projects/myfunproject/overlays/mycustomoverlay.dtbo")
# You can check for loading like above, but it's really just there for sameness
OM.get_custom_loaded()
# To unload, just call unload()
OM.unload("CUST")
**OverlayManager requires a 4.4 kernel with the CONFIG_OF_CONFIGFS option enabled in the kernel config.**
**Utilties**::
CHIP_IO now supports the ability to enable and disable the 1.8V port on U13. This voltage rail isn't enabled during boot.
To use the utilities, here is sample code::
import CHIP_IO.Utilities as UT
# Enable 1.8V Output
UT.enable_1v8_pin()
# Set 2.0V Output
UT.set_1v8_pin_voltage(2.0)
# Set 2.6V Output
UT.set_1v8_pin_voltage(2.6)
# Set 3.3V Output
UT.set_1v8_pin_voltage(3.3)
# Disable 1.8V Output
UT.disable_1v8_pin()
# Get currently-configured voltage (returns False if the pin is not enabled as output)
UT.get_1v8_pin_voltage()
# Unexport Everything
UT.unexport_all()
**Running tests**
Install py.test to run the tests. You'll also need the python compiler package for py.test.::

0
overlays/__init__.py Normal file
View File

26
overlays/builder.py Normal file
View File

@ -0,0 +1,26 @@
from subprocess import call
import os
import shutil
import glob
import sys
def compile():
print("Compiling DTS Files")
call(["dtc", "-O", "dtb", "-o", "overlays/chip-spi2.dtbo", "-b", "o", "-@", "overlays/chip-spi2.dts"])
call(["dtc", "-O", "dtb", "-o", "overlays/chip-i2c1.dtbo", "-b", "o", "-@", "overlays/chip-i2c1.dts"])
call(["dtc", "-O", "dtb", "-o", "overlays/chip-pwm0.dtbo", "-b", "o", "-@", "overlays/chip-pwm0.dts"])
def copy():
target_dir = os.environ.get('TARGET_DIR', '')
overlay_path = target_dir + "/lib/firmware/chip_io"
print("Checking for DTBO Install Path")
if not os.path.exists(overlay_path):
print("Path not found, creating "+overlay_path)
os.makedirs(overlay_path)
print("Removing old DTBO files (if applicable)")
for fl in glob.glob(overlay_path+"/chip-*-.dtbo"):
os.remove(fl)
print("Moving DTBO files to "+overlay_path)
shutil.move("overlays/chip-spi2.dtbo", overlay_path+"/chip-spi2.dtbo")
shutil.move("overlays/chip-i2c1.dtbo", overlay_path+"/chip-i2c1.dtbo")
shutil.move("overlays/chip-pwm0.dtbo", overlay_path+"/chip-pwm0.dtbo")

61
overlays/chip-pwm0.dts Normal file
View File

@ -0,0 +1,61 @@
/*
* Copyright 2016 Free Electrons
* Copyright 2016 NextThing Co
*
* Maxime Ripard <maxime.ripard@free-electrons.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
* licensing only applies to this file, and not this project as a
* whole.
*
* a) This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Or, alternatively,
*
* b) 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.
*/
/dts-v1/;
/plugin/;
/ {
compatible = "nextthing,chip", "allwinner,sun5i-r8";
/* Enable the PWM */
fragment@0 {
target = <&pwm>;
__overlay__ {
pinctrl-names = "default";
pinctrl-0 = <&pwm0_pins>;
status = "okay";
};
};
};

93
overlays/chip-spi2.dts Normal file
View File

@ -0,0 +1,93 @@
/*
* Copyright 2016, Robert Wolterman
* This file is an amalgamation of stuff from Kolja Windeler, Maxime Ripard, and Renzo.
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
* licensing only applies to this file, and not this project as a
* whole.
*
* a) This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Or, alternatively,
*
* b) 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.
*/
/dts-v1/;
/plugin/;
/ {
compatible = "nextthing,chip", "allwinner,sun5i-r8";
/* activate the gpio for interrupt */
fragment@0 {
target-path = <&pio>;
__overlay__ {
chip_spi2_pins: spi2@0 {
allwinner,pins = "PE1", "PE2", "PE3";
allwinner,function = "spi2";
allwinner,drive = "0"; //<SUN4I_PINCTRL_10_MA>;
allwinner,pull = "0"; //<SUN4I_PINCTRL_NO_PULL>;
};
chip_spi2_cs0_pins: spi2_cs0@0 {
allwinner,pins = "PE0";
allwinner,function = "spi2";
allwinner,drive = "0"; //<SUN4I_PINCTRL_10_MA>;
allwinner,pull = "0"; //<SUN4I_PINCTRL_NO_PULL>;
};
};
};
/*
* Enable our SPI device, with an spidev device connected
* to it
*/
fragment@1 {
target = <&spi2>;
__overlay__ {
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&chip_spi2_pins>, <&chip_spi2_cs0_pins>;
status = "okay";
spi2@0 {
compatible = "rohm,dh2228fv";
reg = <0>;
spi-max-frequency = <24000000>;
};
};
};
};

View File

@ -20,7 +20,7 @@ classifiers = ['Development Status :: 3 - Alpha',
'Topic :: System :: Hardware']
setup(name = 'CHIP_IO',
version = '0.0.9',
version = '0.2.5',
author = 'Robert Wolterman',
author_email = 'robert.wolterman@gmail.com',
description = 'A module to control CHIP IO channels',

View File

@ -42,8 +42,37 @@ SOFTWARE.
#define PERIOD 0
#define DUTY 1
#define ENABLE 1
#define DISABLE 0
// Global variables
int pwm_initialized = 0;
int DEBUG = 0;
//int ENABLE = 1;
//int DISABLE = 0;
// pwm devices (future chip pro use)
struct pwm_dev
{
char key[KEYLEN+1]; /* leave room for terminating NUL byte */
int gpio;
int initialized;
struct pwm_dev *next;
};
struct pwm_dev *initialized_pwms = NULL;
struct pwm_dev *lookup_initialized_pwm(const char *key)
{
struct pwm_dev *dev = initialized_pwms;
while (dev != NULL)
{
if (strcmp(dev->key, key) == 0) {
return dev;
}
dev = dev->next;
}
return NULL;
}
// pwm exports
struct pwm_exp
@ -71,7 +100,6 @@ struct pwm_exp *lookup_exported_pwm(const char *key)
}
pwm = pwm->next;
}
return NULL; /* standard for pointers */
}
@ -84,12 +112,16 @@ int initialize_pwm(void)
// we need to export 0 here to enable pwm0
int gpio = 0;
if (DEBUG)
printf(" ** EXPORTING PWM0 **\n");
if ((fd = open("/sys/class/pwm/pwmchip0/export", O_WRONLY)) < 0)
{
return -1;
}
len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio); BUF2SMALL(str_gpio);
ssize_t s = write(fd, str_gpio, len); ASSRT(s == len);
if (DEBUG)
printf(" ** IN initialize_pwm: s = %d, len = %d\n", s, len);
close(fd);
pwm_initialized = 1;
@ -101,46 +133,68 @@ int initialize_pwm(void)
int pwm_set_frequency(const char *key, float freq) {
int len;
int rtnval = -1;
char buffer[80];
unsigned long period_ns;
struct pwm_exp *pwm;
if (freq <= 0.0)
return -1;
return rtnval;
pwm = lookup_exported_pwm(key);
if (pwm == NULL) {
return -1;
return rtnval;
}
period_ns = (unsigned long)(1e9 / freq);
if (pwm->enable) {
if (DEBUG)
printf(" ** IN pwm_set_frequency: pwm_initialized = %d\n", pwm_initialized);
if (period_ns != pwm->period_ns) {
pwm->period_ns = period_ns;
len = snprintf(buffer, sizeof(buffer), "%lu", period_ns); BUF2SMALL(buffer);
ssize_t s = write(pwm->period_fd, buffer, len); ASSRT(s == len);
if (DEBUG)
printf(" ** pwm_set_frequency: buffer: %s\n", buffer);
ssize_t s = write(pwm->period_fd, buffer, len); //ASSRT(s == len);
if (DEBUG)
printf(" ** IN pwm_set_frequency: s = %d, len = %d\n", s, len);
if (s != len) {
rtnval = -1;
} else {
rtnval = 1;
}
} else {
rtnval = 0;
}
} else {
rtnval = 0;
}
return 1;
return rtnval;
}
int pwm_set_polarity(const char *key, int polarity) {
int len;
int rtnval = -1;
char buffer[80];
struct pwm_exp *pwm;
pwm = lookup_exported_pwm(key);
if (pwm == NULL) {
return -1;
return rtnval;
}
if (polarity < 0 || polarity > 1) {
return -1;
if (polarity != 0 && polarity != 1) {
return rtnval;
}
if (pwm->enable) {
if (DEBUG)
printf(" ** IN pwm_set_polarity: pwm_initialized = %d\n", pwm_initialized);
if (polarity == 0) {
len = snprintf(buffer, sizeof(buffer), "%s", "normal"); BUF2SMALL(buffer);
}
@ -148,54 +202,102 @@ int pwm_set_polarity(const char *key, int polarity) {
{
len = snprintf(buffer, sizeof(buffer), "%s", "inverted"); BUF2SMALL(buffer);
}
ssize_t s = write(pwm->polarity_fd, buffer, len); ASSRT(s == len);
return 0;
if (DEBUG)
printf(" ** pwm_set_poliarity: buffer: %s\n", buffer);
ssize_t s = write(pwm->polarity_fd, buffer, len); //ASSRT(s == len);
if (DEBUG)
printf(" ** IN pwm_set_polarity: s = %d, len = %d\n", s, len);
if (s != len) {
rtnval = -1;
} else {
rtnval = 1;
}
} else {
rtnval = 0;
}
return rtnval;
}
int pwm_set_duty_cycle(const char *key, float duty) {
int len;
int rtnval = -1;
char buffer[80];
struct pwm_exp *pwm;
if (duty < 0.0 || duty > 100.0)
return -1;
if (duty < 0.0 || duty > 100.0) {
return rtnval;
}
pwm = lookup_exported_pwm(key);
if (pwm == NULL) {
return -1;
return rtnval;
}
pwm->duty = (unsigned long)(pwm->period_ns * (duty / 100.0));
if (pwm->enable) {
if (DEBUG)
printf(" ** IN pwm_set_duty_cycle: pwm_initialized = %d\n", pwm_initialized);
len = snprintf(buffer, sizeof(buffer), "%lu", pwm->duty); BUF2SMALL(buffer);
ssize_t s = write(pwm->duty_fd, buffer, len); ASSRT(s == len);
if (DEBUG)
printf(" ** pwm_set_duty_cycle: buffer: %s\n", buffer);
ssize_t s = write(pwm->duty_fd, buffer, len); //ASSRT(s == len);
if (DEBUG)
printf(" ** IN pwm_set_duty_cycle: s = %d, len = %d\n", s, len);
if (s != len) {
rtnval = -1;
} else {
rtnval = 1;
}
} else {
rtnval = 0;
}
return 0;
return rtnval;
}
int pwm_set_enable(const char *key, int enable)
{
int len;
int rtnval = -1;
char buffer[80];
struct pwm_exp *pwm;
if (enable != 0 || enable != 1)
return -1;
if (enable != 0 && enable != 1) {
if (DEBUG)
printf(" ** INVALID ENABLE OPTION, NEEDS TO BE EITHER 0 OR 1! **\n");
return rtnval;
}
pwm = lookup_exported_pwm(key);
if (pwm == NULL) {
return -1;
if (DEBUG)
printf(" ** SOMETHING BAD HAPPEND IN pwm_set_enable, WE'RE EXITING WITH -1 NOW! **\n");
return rtnval;
}
len = snprintf(buffer, sizeof(buffer), "%d", enable); BUF2SMALL(buffer);
ssize_t s = write(pwm->enable_fd, buffer, len); //ASSRT(s == len);
if (DEBUG) {
printf(" ** IN pwm_set_enable: pwm_initialized = %d\n", pwm_initialized);
printf(" ** pwm_set_enable: buffer: %s\n", buffer);
printf(" ** IN pwm_set_enable: s = %d, len = %d\n", s, len);
}
if (s == len)
{
if (DEBUG)
printf(" ** SETTING pwm->enable to %d\n", enable);
pwm->enable = enable;
rtnval = 0;
} else {
rtnval = -1;
}
len = snprintf(buffer, sizeof(buffer), "%d", pwm->enable); BUF2SMALL(buffer);
ssize_t s = write(pwm->enable_fd, buffer, len); ASSRT(s == len);
return 0;
return rtnval;
}
int pwm_start(const char *key, float duty, float freq, int polarity)
@ -208,9 +310,17 @@ int pwm_start(const char *key, float duty, float freq, int polarity)
int period_fd, duty_fd, polarity_fd, enable_fd;
struct pwm_exp *new_pwm, *pwm;
if (DEBUG)
printf(" ** IN pwm_start: pwm_initialized = %d\n", pwm_initialized);
if(!pwm_initialized) {
initialize_pwm();
} else {
if (DEBUG)
printf(" ** ALREADY INITIALIZED, CALLING CLEANUP TO START FRESH **");
pwm_cleanup();
}
if (DEBUG)
printf(" ** IN pwm_start: pwm_initialized = %d\n", pwm_initialized);
//setup the pwm base path, the chip only has one pwm
snprintf(pwm_base_path, sizeof(pwm_base_path), "/sys/class/pwm/pwmchip0/pwm%d", 0); BUF2SMALL(pwm_base_path);
@ -221,24 +331,31 @@ int pwm_start(const char *key, float duty, float freq, int polarity)
snprintf(duty_path, sizeof(duty_path), "%s/duty_cycle", pwm_base_path); BUF2SMALL(duty_path);
snprintf(polarity_path, sizeof(polarity_path), "%s/polarity", pwm_base_path); BUF2SMALL(polarity_path);
if (DEBUG) {
printf(" ** IN pwm_start: pwm_base_path: %s\n", pwm_base_path);
printf(" ** IN pwm_start: enable_path: %s\n", enable_path);
printf(" ** IN pwm_start: period_path: %s\n", period_path);
printf(" ** IN pwm_start: duty_path: %s\n", duty_path);
printf(" **IN pwm_start: polarity_path: %s\n", polarity_path);
}
//add period and duty fd to pwm list
if ((enable_fd = open(enable_path, O_RDWR)) < 0)
if ((enable_fd = open(enable_path, O_WRONLY)) < 0)
return -1;
if ((period_fd = open(period_path, O_RDWR)) < 0) {
if ((period_fd = open(period_path, O_WRONLY)) < 0) {
close(enable_fd);
return -1;
}
if ((duty_fd = open(duty_path, O_RDWR)) < 0) {
if ((duty_fd = open(duty_path, O_WRONLY)) < 0) {
//error, close already opened period_fd.
close(enable_fd);
close(period_fd);
return -1;
}
if ((polarity_fd = open(polarity_path, O_RDWR)) < 0) {
if ((polarity_fd = open(polarity_path, O_WRONLY)) < 0) {
//error, close already opened period_fd and duty_fd.
close(enable_fd);
close(period_fd);
@ -252,6 +369,8 @@ int pwm_start(const char *key, float duty, float freq, int polarity)
return -1; // out of memory
}
if (DEBUG)
printf(" ** IN pwm_start: IF WE MAKE IT HERE, THE FILES WERE SUCCESSFULLY OPEN **\n");
strncpy(new_pwm->key, key, KEYLEN); /* can leave string unterminated */
new_pwm->key[KEYLEN] = '\0'; /* terminate string */
new_pwm->period_fd = period_fd;
@ -272,12 +391,16 @@ int pwm_start(const char *key, float duty, float freq, int polarity)
pwm->next = new_pwm;
}
pwm_set_frequency(key, freq);
pwm_set_polarity(key, polarity);
pwm_set_enable(key, 1);
pwm_set_duty_cycle(key, duty);
int rtnval = 0;
rtnval = pwm_set_enable(key, ENABLE);
rtnval = 0;
rtnval = pwm_set_frequency(key, freq);
rtnval = 0;
//rtnval = pwm_set_polarity(key, polarity);
//rtnval = 0;
rtnval = pwm_set_duty_cycle(key, duty);
return 1;
return rtnval;
}
int pwm_disable(const char *key)
@ -292,9 +415,9 @@ int pwm_disable(const char *key)
// Disable the PWM
pwm_set_frequency(key, 0);
pwm_set_polarity(key, 0);
pwm_set_enable(key, 0);
//pwm_set_polarity(key, 0);
pwm_set_duty_cycle(key, 0);
pwm_set_enable(key, DISABLE);
if ((fd = open("/sys/class/pwm/pwmchip0/unexport", O_WRONLY)) < 0)
{
@ -323,7 +446,6 @@ int pwm_disable(const char *key)
} else {
prev_pwm->next = pwm->next;
}
temp = pwm;
pwm = pwm->next;
free(temp);
@ -341,3 +463,12 @@ void pwm_cleanup(void)
pwm_disable(exported_pwms->key);
}
}
void pwm_toggle_debug(void)
{
if (DEBUG) {
DEBUG = 0;
} else {
DEBUG = 1;
}
}

View File

@ -35,3 +35,4 @@ int pwm_set_frequency(const char *key, float freq);
int pwm_set_duty_cycle(const char *key, float duty);
int pwm_set_enable(const char *key, int enable);
void pwm_cleanup(void);
void pwm_toggle_debug(void);

View File

@ -41,7 +41,6 @@ SOFTWARE.
#include "c_pwm.h"
#include "common.h"
#include "event_gpio.h"
#include "Python.h"
#define KEYLEN 7
@ -101,7 +100,7 @@ int softpwm_set_frequency(const char *key, float freq) {
pwm->params.freq = freq;
pthread_mutex_unlock(pwm->params_lock);
return 1;
return 0;
}
int softpwm_set_polarity(const char *key, int polarity) {
@ -241,8 +240,12 @@ int softpwm_start(const char *key, float duty, float freq, int polarity)
if (get_gpio_number(key, &gpio) < 0)
return -1;
if (gpio_export(gpio) < 0)
if (gpio_export(gpio) < 0) {
char err[2000];
snprintf(err, sizeof(err), "Error setting up softpwm on pin %d, maybe already exported? (%s)", gpio, get_error_msg());
add_error_msg(err);
return -1;
}
if (gpio_set_direction(gpio, OUTPUT) < 0)
return -1;
@ -274,11 +277,13 @@ int softpwm_start(const char *key, float duty, float freq, int polarity)
pwm = pwm->next;
pwm->next = new_pwm;
}
pthread_mutex_unlock(new_params_lock);
ASSRT(softpwm_set_duty_cycle(new_pwm->key, duty) == 0);
ASSRT(softpwm_set_frequency(new_pwm->key, freq) == 0);
ASSRT(softpwm_set_polarity(new_pwm->key, polarity) == 0);
pthread_mutex_lock(new_params_lock);
// create thread for pwm
ret = pthread_create(&new_thread, NULL, softpwm_thread_toggle, (void *)new_pwm);
ASSRT(ret == 0);

View File

@ -36,7 +36,6 @@ 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"
@ -352,10 +351,12 @@ int get_pwm_key_by_name(const char *name, char *key)
pins_t *p;
for (p = pins_info; p->name != NULL; ++p) {
if (strcmp(p->name, name) == 0) {
printf("## FOUND PWM KEY, VALIDATING MUX MODE ##\n");
//validate it's a valid pwm pin
if (p->pwm_mux_mode == -1)
return 0;
printf("## PWM KEY IS VALID ##\n");
strncpy(key, p->key, 7);
key[7] = '\0';
return 1;

View File

@ -77,7 +77,6 @@ struct dyn_int_array_s {
};
typedef struct dyn_int_array_s dyn_int_array_t;
#define FILENAME_BUFFER_SIZE 128
int setup_error;

View File

@ -76,6 +76,6 @@ void define_constants(PyObject *module)
both_edge = Py_BuildValue("i", BOTH_EDGE);
PyModule_AddObject(module, "BOTH", both_edge);
version = Py_BuildValue("s", "0.0.9");
version = Py_BuildValue("s", "0.2.5");
PyModule_AddObject(module, "VERSION", version);
}

View File

@ -63,8 +63,11 @@ struct fdx *fd_list = NULL;
// event callbacks
struct callback
{
int fde;
int gpio;
void (*func)(int gpio);
int edge;
void* data;
void (*func)(int gpio, void* data);
struct callback *next;
};
struct callback *callbacks = NULL;
@ -158,7 +161,6 @@ void close_value_fd(int gpio)
}
} /* close_value_fd */
int fd_lookup(int gpio)
{
struct fdx *f = fd_list;
@ -172,6 +174,18 @@ int fd_lookup(int gpio)
return 0;
}
int fde_lookup(int gpio)
{
struct callback *cb = callbacks;
while (cb != NULL)
{
if (cb->gpio == gpio)
return cb->fde;
cb = cb->next;
}
return 0;
}
int add_fd_list(int gpio, int fd)
{
@ -212,6 +226,23 @@ int open_value_file(int gpio)
return fd;
} /* open_value_file */
int open_edge_file(int gpio)
{
int fd;
char filename[MAX_FILENAME];
// create file descriptor of value file
snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/edge", gpio); BUF2SMALL(filename);
if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0) {
char err[256];
snprintf(err, sizeof(err), "open_edge_file: could not open '%s' (%s)", filename, strerror(errno));
add_error_msg(err);
return -1;
}
return fd;
} /* open_edge_file */
int gpio_unexport(int gpio)
{
@ -446,6 +477,59 @@ int gpio_set_edge(int gpio, unsigned int edge)
return 0;
}
int gpio_get_edge(int gpio)
{
int fd = fde_lookup(gpio);
int rtnedge = -1;
if (!fd)
{
if ((fd = open_edge_file(gpio)) == -1) {
char err[256];
snprintf(err, sizeof(err), "gpio_get_value: could not open GPIO %d edge file", gpio);
add_error_msg(err);
return -1;
}
}
if (lseek(fd, 0, SEEK_SET) < 0) {
char err[256];
snprintf(err, sizeof(err), "gpio_get_value: could not seek GPIO %d (%s)", gpio, strerror(errno));
add_error_msg(err);
return -1;
}
char edge[16] = { 0 }; /* make sure read is null-terminated */
ssize_t s = read(fd, &edge, sizeof(edge) - 1);
close(fd);
while (s > 0 && edge[s-1] == '\n') { /* strip trailing newlines */
edge[s-1] = '\0';
s --;
}
if (s < 0) {
char err[256];
snprintf(err, sizeof(err), "gpio_get_value: could not read GPIO %d (%s)", gpio, strerror(errno));
add_error_msg(err);
return -1;
}
if (strcmp(edge, "rising") == 0)
{
rtnedge = 1;
}
else if (strcmp(edge, "falling") == 0)
{
rtnedge = 2;
}
else if (strcmp(edge, "both") == 0)
{
rtnedge = 3;
}
return rtnedge;
}
int gpio_lookup(int fd)
{
struct fdx *f = fd_list;
@ -466,14 +550,17 @@ void exports_cleanup(void)
gpio_unexport(exported_gpios->gpio);
}
int add_edge_callback(int gpio, void (*func)(int gpio))
int add_edge_callback(int gpio, int edge, void (*func)(int gpio, void* data), void* data)
{
struct callback *cb = callbacks;
struct callback *new_cb;
new_cb = malloc(sizeof(struct callback)); ASSRT(new_cb != NULL);
new_cb->fde = open_edge_file(gpio);
new_cb->gpio = gpio;
new_cb->edge = edge;
new_cb->data = data;
new_cb->func = func;
new_cb->next = NULL;
@ -495,7 +582,32 @@ void run_callbacks(int gpio)
while (cb != NULL)
{
if (cb->gpio == gpio)
cb->func(cb->gpio);
{
int canrun = 0;
unsigned int value = 0;
gpio_get_value(gpio, &value);
// Both Edge
if (cb->edge == 3)
{
canrun = 1;
}
// Rising Edge
else if ((cb->edge == 1) && (value == 1))
{
canrun = 1;
}
// Falling Edge
else if ((cb->edge == 2) && (value == 0))
{
canrun = 1;
}
// Only run if we are allowed
if (canrun)
{
cb->func(cb->gpio, cb->data);
}
}
cb = cb->next;
}
}
@ -510,6 +622,7 @@ void remove_callbacks(int gpio)
{
if (cb->gpio == gpio)
{
close(cb->fde);
if (prev == NULL)
callbacks = cb->next;
else

View File

@ -61,10 +61,16 @@ int gpio_set_direction(int gpio, unsigned int in_flag);
int gpio_get_direction(int gpio, unsigned int *value);
int gpio_set_value(int gpio, unsigned int value);
int gpio_get_value(int gpio, unsigned int *value);
int fd_lookup(int gpio);
int open_value_file(int gpio);
int fde_lookup(int gpio);
int open_edge_file(int gpio);
int gpio_set_edge(int gpio, unsigned int edge);
int gpio_get_edge(int gpio);
int add_edge_detect(int gpio, unsigned int edge);
void remove_edge_detect(int gpio);
int add_edge_callback(int gpio, void (*func)(int gpio));
int add_edge_callback(int gpio, int edge, void (*func)(int gpio, void* data), void* data);
int event_detected(int gpio);
int gpio_event_add(int gpio);
int gpio_event_remove(int gpio);

View File

@ -225,7 +225,7 @@ static PyObject *py_input_gpio(PyObject *self, PyObject *args)
return py_value;
}
static void run_py_callbacks(int gpio)
static void run_py_callbacks(int gpio, void* data)
{
PyObject *result;
PyGILState_STATE gstate;
@ -264,7 +264,7 @@ static void run_py_callbacks(int gpio)
}
}
static int add_py_callback(char *channel, int gpio, unsigned int bouncetime, PyObject *cb_func)
static int add_py_callback(char *channel, int gpio, int edge, unsigned int bouncetime, PyObject *cb_func)
{
struct py_callback *new_py_cb;
struct py_callback *cb = py_callbacks;
@ -294,7 +294,7 @@ static int add_py_callback(char *channel, int gpio, unsigned int bouncetime, PyO
cb = cb->next;
cb->next = new_py_cb;
}
add_edge_callback(gpio, run_py_callbacks);
add_edge_callback(gpio, edge, run_py_callbacks, NULL);
return 0;
}
@ -343,7 +343,8 @@ static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject
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)
// Defaulting to Falling edge
if (add_py_callback(channel, gpio, 2, bouncetime, cb_func) != 0)
return NULL;
Py_RETURN_NONE;
@ -410,7 +411,7 @@ static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *k
}
if (cb_func != NULL)
if (add_py_callback(channel, gpio, bouncetime, cb_func) != 0)
if (add_py_callback(channel, gpio, edge, bouncetime, cb_func) != 0)
return NULL;
Py_RETURN_NONE;
@ -748,6 +749,54 @@ static PyObject *py_selftest(PyObject *self, PyObject *args)
static const char moduledocstring[] = "GPIO functionality of a CHIP using Python";
/*
mine for changing pin directipn
*/
static PyObject *py_set_direction(PyObject *self, PyObject *args, PyObject *kwargs)
{
int gpio;
char *channel;
int direction;
static char *kwlist[] = { "channel", "direction", NULL };
clear_error_msg();
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|ii", kwlist, &channel, &direction))
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 (get_gpio_number(channel, &gpio) < 0) {
char err[2000];
snprintf(err, sizeof(err), "Invalid channel %s. (%s)", channel, get_error_msg());
PyErr_SetString(PyExc_ValueError, err);
return NULL;
}
if (gpio_set_direction(gpio, direction) < 0) {
char err[2000];
snprintf(err, sizeof(err), "Error setting direction %d on channel %s. (%s)", direction, channel, get_error_msg());
PyErr_SetString(PyExc_RuntimeError, err);
return NULL;
}
remember_gpio_direction(gpio, direction);
Py_RETURN_NONE;
}
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: CHIP board pin number (not R8 GPIO 00..nn number). Pins start from 1\n or : CHIP GPIO name\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"},
@ -762,9 +811,11 @@ PyMethodDef gpio_methods[] = {
{"setwarnings", py_setwarnings, METH_VARARGS, "Enable or disable warning messages"},
{"get_gpio_base", py_gpio_base, METH_VARARGS, "Get the XIO base number for sysfs"},
{"selftest", py_selftest, METH_VARARGS, "Internal unit tests"},
{ "direction", (PyCFunction)py_set_direction, METH_VARARGS, "Change direction of gpio channel. Either INPUT or OUTPUT\n" },
{NULL, NULL, 0, NULL}
};
#if PY_MAJOR_VERSION > 2
static struct PyModuleDef rpigpiomodule = {
PyModuleDef_HEAD_INIT,

View File

@ -43,6 +43,15 @@ static PyObject *py_cleanup(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
// python function toggle_debug()
static PyObject *py_toggle_debug(PyObject *self, PyObject *args)
{
// toggle debug printing
pwm_toggle_debug();
Py_RETURN_NONE;
}
// python function start(channel, duty_cycle, freq)
static PyObject *py_start_channel(PyObject *self, PyObject *args, PyObject *kwargs)
{
@ -170,9 +179,10 @@ static const char moduledocstring[] = "Hardware PWM functionality of a CHIP usin
PyMethodDef pwm_methods[] = {
{"start", (PyCFunction)py_start_channel, METH_VARARGS | METH_KEYWORDS, "Set up and start the PWM channel. channel can be in the form of 'PWM0', or 'U13_18'"},
{"stop", (PyCFunction)py_stop_channel, METH_VARARGS | METH_KEYWORDS, "Stop the PWM channel. channel can be in the form of 'PWM0', or 'U13_18'"},
{ "set_duty_cycle", (PyCFunction)py_set_duty_cycle, METH_VARARGS, "Change the duty cycle\ndutycycle - between 0.0 and 100.0" },
{ "set_frequency", (PyCFunction)py_set_frequency, METH_VARARGS, "Change the frequency\nfrequency - frequency in Hz (freq > 0.0)" },
{"set_duty_cycle", (PyCFunction)py_set_duty_cycle, METH_VARARGS, "Change the duty cycle\ndutycycle - between 0.0 and 100.0" },
{"set_frequency", (PyCFunction)py_set_frequency, METH_VARARGS, "Change the frequency\nfrequency - frequency in Hz (freq > 0.0)" },
{"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"},
{"toggle_debug", py_toggle_debug, METH_VARARGS, "Toggles the enabling/disabling of Debug print output"},
//{"setwarnings", py_setwarnings, METH_VARARGS, "Enable or disable warning messages"},
{NULL, NULL, 0, NULL}
};

View File

@ -80,8 +80,14 @@ static PyObject *py_start_channel(PyObject *self, PyObject *args, PyObject *kwar
return NULL;
}
if (!softpwm_start(key, duty_cycle, frequency, polarity))
if (softpwm_start(key, duty_cycle, frequency, polarity) < 0)
{
printf("softpwm_start failed");
char err[2000];
snprintf(err, sizeof(err), "Error starting softpwm on pin %s (%s)", key, get_error_msg());
PyErr_SetString(PyExc_RuntimeError, err);
return NULL;
}
Py_RETURN_NONE;
}

View File

@ -1,96 +0,0 @@
# The default ``config.py``
def set_prefs(prefs):
"""This function is called before opening the project"""
# Specify which files and folders to ignore in the project.
# Changes to ignored resources are not added to the history and
# VCSs. Also they are not returned in `Project.get_files()`.
# Note that ``?`` and ``*`` match all characters but slashes.
# '*.pyc': matches 'test.pyc' and 'pkg/test.pyc'
# 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc'
# '.svn': matches 'pkg/.svn' and all of its children
# 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o'
# 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o'
prefs['ignored_resources'] = [
'*.pyc', '*~', '.ropeproject', '.hg', '.svn', '_svn', '.git',
'.tox', '.env', 'node_modules', 'bower_components']
# Specifies which files should be considered python files. It is
# useful when you have scripts inside your project. Only files
# ending with ``.py`` are considered to be python files by
# default.
#prefs['python_files'] = ['*.py']
# Custom source folders: By default rope searches the project
# for finding source folders (folders that should be searched
# for finding modules). You can add paths to that list. Note
# that rope guesses project source folders correctly most of the
# time; use this if you have any problems.
# The folders should be relative to project root and use '/' for
# separating folders regardless of the platform rope is running on.
# 'src/my_source_folder' for instance.
#prefs.add('source_folders', 'src')
# You can extend python path for looking up modules
#prefs.add('python_path', '~/python/')
# Should rope save object information or not.
prefs['save_objectdb'] = True
prefs['compress_objectdb'] = False
# If `True`, rope analyzes each module when it is being saved.
prefs['automatic_soa'] = True
# The depth of calls to follow in static object analysis
prefs['soa_followed_calls'] = 0
# If `False` when running modules or unit tests "dynamic object
# analysis" is turned off. This makes them much faster.
prefs['perform_doa'] = True
# Rope can check the validity of its object DB when running.
prefs['validate_objectdb'] = True
# How many undos to hold?
prefs['max_history_items'] = 32
# Shows whether to save history across sessions.
prefs['save_history'] = True
prefs['compress_history'] = False
# Set the number spaces used for indenting. According to
# :PEP:`8`, it is best to use 4 spaces. Since most of rope's
# unit-tests use 4 spaces it is more reliable, too.
prefs['indent_size'] = 4
# Builtin and c-extension modules that are allowed to be imported
# and inspected by rope.
prefs['extension_modules'] = []
# Add all standard c-extensions to extension_modules list.
prefs['import_dynload_stdmods'] = True
# If `True` modules with syntax errors are considered to be empty.
# The default value is `False`; When `False` syntax errors raise
# `rope.base.exceptions.ModuleSyntaxError` exception.
prefs['ignore_syntax_errors'] = False
# If `True`, rope ignores unresolvable imports. Otherwise, they
# appear in the importing namespace.
prefs['ignore_bad_imports'] = False
# If `True`, rope will transform a comma list of imports into
# multiple separate import statements when organizing
# imports.
prefs['split_imports'] = False
# If `True`, rope will sort imports alphabetically by module name
# instead of alphabetically by import statement, with from imports
# after normal imports.
prefs['sort_imports_alphabetically'] = False
def project_opened(project):
"""This function is called after opening the project"""
# Do whatever you like here!

View File

@ -1,2 +0,0 @@
<EFBFBD>}q(Utest_softpwm_setup]q(Uteardown_moduleqUTestSoftpwmSetupqeUtest_gpio_output]q(hUTestGPIOOutputqeUtest_pwm_setup]q(hU TestPwmSetupqeUtest_gpio_setup]q (hU TestSetupq
eUtest_gpio_input]q (hU

View File

@ -1 +0,0 @@
<EFBFBD>]q(]q]qe.

View File

@ -1 +0,0 @@
<EFBFBD>}q.

118
test/gptest.py Executable file → Normal file
View File

@ -4,13 +4,8 @@ import CHIP_IO.GPIO as GPIO
import time
import threading
DO_APEINT1_TEST = False
DO_APEINT3_TEST = False
DO_XIOP2_TEST = True
num_callbacks = 0
def myfuncallback(channel):
global num_callbacks
num_callbacks += 1
@ -19,9 +14,8 @@ def myfuncallback(channel):
loopfunction_exit = False
def loopfunction():
print("LOOP FUNCTION")
print("LOOP FUNCTION START")
for i in xrange(4):
if loopfunction_exit:
break
@ -33,12 +27,16 @@ def loopfunction():
mystr = "SETTING CSID0 HIGH (i=%d)" % i
print(mystr)
GPIO.output("CSID0", GPIO.HIGH)
print("SLEEPING")
print(" LOOP FUNCTION SLEEPING")
time.sleep(1)
num_errs = 0
print("RUNNING GPIO SELF TEST")
print("GETTING CHIP_IO VERSION")
mystr = "CHIP_IO VERSION: %s" % GPIO.VERSION
print(mystr)
print("\nRUNNING GPIO SELF TEST")
GPIO.selftest(0)
print("\nVERIFYING SIMPLE FUNCTIONALITY")
@ -52,7 +50,7 @@ else:
print(" Able to use alternate names for GPIO")
GPIO.cleanup()
GPIO.setup("U14_15", GPIO.IN) # XIO-P0
GPIO.setup("U14_15", GPIO.IN) # XIO-P2
GPIO.setup("CSID0", GPIO.OUT, initial=GPIO.LOW)
if (GPIO.input("XIO-P2") != GPIO.LOW):
print(" A low output on CSI0 does not lead to a low input on XIO-P2.")
@ -73,69 +71,81 @@ GPIO.output("CSID0", GPIO.LOW)
print "LOW", GPIO.input("GPIO1")
assert(GPIO.input("GPIO1") == GPIO.LOW)
print("SWAP GPIO WIRES FOR EDGE DETECTION TESTS AS NEEDED")
raw_input("PRESS ENTER WHEN READY TO START EDGE DETECTION TESTS")
# ==============================================
# EDGE DETECTION - AP-EINT1
if DO_APEINT1_TEST:
print("\nSETTING UP RISING EDGE DETECTION ON AP-EINT1")
GPIO.setup("AP-EINT1", GPIO.IN)
GPIO.add_event_detect("AP-EINT1", GPIO.RISING)
print("VERIFYING EDGE DETECT")
f = open("/sys/class/gpio/gpio193/edge", "r")
edge = f.read()
f.close()
assert(edge == "rising\n")
GPIO.remove_event_detect("AP-EINT1")
print("\nSETTING UP RISING EDGE DETECTION ON AP-EINT1")
GPIO.setup("AP-EINT1", GPIO.IN)
GPIO.add_event_detect("AP-EINT1", GPIO.RISING, myfuncallback)
print("VERIFYING EDGE DETECT WAS SET PROPERLY")
f = open("/sys/class/gpio/gpio193/edge", "r")
edge = f.read()
f.close()
assert(edge == "rising\n")
GPIO.remove_event_detect("AP-EINT1")
# ==============================================
# EDGE DETECTION - AP-EINT3
if DO_APEINT3_TEST:
print("\nSETTING UP BOTH EDGE DETECTION ON AP-EINT3")
GPIO.setup("AP-EINT3", GPIO.IN)
GPIO.add_event_detect("AP-EINT3", GPIO.BOTH)
print("VERIFYING EDGE DETECT")
f = open("/sys/class/gpio/gpio35/edge", "r")
edge = f.read()
f.close()
assert(edge == "both\n")
GPIO.remove_event_detect("AP-EINT3")
print("\nSETTING UP BOTH EDGE DETECTION ON AP-EINT3")
GPIO.setup("AP-EINT3", GPIO.IN)
GPIO.add_event_detect("AP-EINT3", GPIO.BOTH, myfuncallback)
print("VERIFYING EDGE DETECT WAS SET PROPERLY")
f = open("/sys/class/gpio/gpio35/edge", "r")
edge = f.read()
f.close()
assert(edge == "both\n")
GPIO.remove_event_detect("AP-EINT3")
# ==============================================
# EDGE DETECTION - EXPANDED GPIO
if DO_XIOP2_TEST:
print("\nSETTING UP FALLING EDGE DETECTION ON XIO-P2")
GPIO.add_event_detect("XIO-P2", GPIO.FALLING, myfuncallback)
print("\nSETTING UP FALLING EDGE DETECTION ON XIO-P2")
# WRITING CSID0 LOW FIRST AS THERE IS A DOUBLE HIT ON HIGH
GPIO.output("CSID0", GPIO.LOW)
GPIO.add_event_detect("XIO-P2", GPIO.FALLING, myfuncallback)
print("VERIFYING EDGE DETECT")
base = GPIO.get_gpio_base()
gfile = "/sys/class/gpio/gpio%d/edge" % (base + 2)
f = open(gfile, "r")
edge = f.read()
f.close()
assert(edge == "falling\n")
print("VERIFYING EDGE DETECT")
base = GPIO.get_gpio_base()
gfile = "/sys/class/gpio/gpio%d/edge" % (base + 2)
f = open(gfile, "r")
edge = f.read()
f.close()
assert(edge == "falling\n")
# LOOP WRITING ON CSID0 TO HOPEFULLY GET CALLBACK TO WORK
print("WAITING FOR CALLBACKS")
print("WAITING FOR CALLBACKS ON XIO-P2")
loopfunction()
mystr = " num_callbacks = %d" % num_callbacks
print(mystr)
print("PRESS CONTROL-C TO EXIT IF SCRIPT GETS STUCK")
GPIO.remove_event_detect("XIO-P2")
print("\nSETTING UP RISING EDGE DETECTION ON XIO-P2")
# WRITING CSID0 LOW FIRST AS THERE IS A DOUBLE HIT ON HIGH
GPIO.output("CSID0", GPIO.LOW)
num_callbacks = 0
GPIO.add_event_detect("XIO-P2", GPIO.RISING, myfuncallback)
print("WAITING FOR CALLBACKS ON XIO-P2")
loopfunction()
mystr = " num_callbacks = %d" % num_callbacks
print(mystr)
GPIO.remove_event_detect("XIO-P2")
print("\nSETTING UP BOTH EDGE DETECTION ON XIO-P2")
# WRITING CSID0 LOW FIRST AS THERE IS A DOUBLE HIT ON HIGH
GPIO.output("CSID0", GPIO.LOW)
num_callbacks = 0
GPIO.add_event_detect("XIO-P2", GPIO.BOTH, myfuncallback)
print("WAITING FOR CALLBACKS ON XIO-P2")
loopfunction()
mystr = " num_callbacks = %d" % num_callbacks
print(mystr)
GPIO.remove_event_detect("XIO-P2")
print("\nWAIT FOR EDGE TESTING, SETUP FOR FALLING EDGE")
print("PRESS CONTROL-C TO EXIT IF SCRIPT GETS STUCK")
try:
# WAIT FOR EDGE
t = threading.Thread(target=loopfunction)
t.start()
print("WAITING FOR EDGE")
if DO_APEINT1_TEST:
GPIO.wait_for_edge("AP-EINT1", GPIO.FALLING)
if DO_APEINT3_TEST:
GPIO.wait_for_edge("AP-EINT3", GPIO.FALLING)
if DO_XIOP2_TEST:
print("WAITING FOR EDGE ON XIO-P2")
GPIO.wait_for_edge("XIO-P2", GPIO.FALLING)
# THIS SHOULD ONLY PRINT IF WE'VE HIT THE EDGE DETECT
print("WE'VE FALLEN LIKE COOLIO'S CAREER")

67
test/lradc_test.py Normal file
View File

@ -0,0 +1,67 @@
#!/usr/bin/python
import CHIP_IO.LRADC as ADC
# == ENABLE DEBUG ==
print("ENABLING LRADC DEBUG OUTPUT")
ADC.enable_debug()
# == SETUP ==
print("LRADC SETUP WITH SAMPLE RATE OF 125")
ADC.setup(125)
# == SCALE FACTOR ==
print("GETTING SCALE FACTOR")
scalefactor = ADC.get_scale_factor()
print(scalefactor)
print("")
# == ALLOWABLE SAMPLING RATES ==
print("GETTING ALLOWABLE SAMPLE RATES")
rates = ADC.get_allowable_sample_rates()
print(rates)
print("IS 32.25 IN RATE TUPLE")
print(ADC.SAMPLE_RATE_32P25 in rates)
print("")
# == CURRENT SAMPLE RATE ==
print("CURRENT SAMPLING RATE")
crate = ADC.get_sample_rate()
print(crate)
print("")
# == SET SAMPLE RATE ==
print("SETTING SAMPLE RATE TO 62.5")
ADC.set_sample_rate(62.5)
crate = ADC.get_sample_rate()
print(crate)
print("")
# == CHAN 0 RAW ==
print("READING LRADC CHAN0 RAW")
raw0 = ADC.get_chan0_raw()
print(raw0)
print("")
# == CHAN 1 RAW ==
print("READING LRADC CHAN1 RAW")
raw1 = ADC.get_chan1_raw()
print(raw1)
print("")
# == CHAN 0 ==
print("READING LRADC CHAN0 WITH SCALE APPLIED")
full0 = ADC.get_chan0()
print(full0)
print("")
# == CHAN 1 ==
print("READING LRADC CHAN1 WITH SCALE APPLIED")
full1 = ADC.get_chan1()
print(full1)
print("")
# == RESET ==
print("RESETING SAMPLE RATE TO 250")
ADC.set_sample_rate(250)

49
test/omtest.py Normal file
View File

@ -0,0 +1,49 @@
#!/usr/bin/python
import CHIP_IO.OverlayManager as OM
import os
# ENABLE DEBUG
print("ENABLING OVERLAY MANAGER DEBUG")
OM.enable_debug()
# **************** PWM *******************
print("\nIS PWM ENABLED: {0}".format(OM.get_pwm_loaded()))
OM.load("PWM0")
print("IS PWM ENABLED: {0}".format(OM.get_pwm_loaded()))
# VERIFY PWM0 EXISTS
if os.path.exists('/sys/class/pwm/pwmchip0'):
print("PWM DEVICE EXISTS")
else:
print("PWM DEVICE DID NOT LOAD PROPERLY")
print("UNLOADING PWM0")
OM.unload("PWM0")
print("IS PWM ENABLED: {0}".format(OM.get_pwm_loaded()))
# **************** I2C-1 *******************
print("\nIS I2C ENABLED: {0}".format(OM.get_i2c_loaded()))
OM.load("I2C1")
print("IS I2C ENABLED: {0}".format(OM.get_i2c_loaded()))
# VERIFY I2C-1 EXISTS
if os.path.exists('/sys/class/i2c-dev/i2c-1'):
print("I2C1 DEVICE EXISTS")
else:
print("I2C1 DEVICE DID NOT LOAD PROPERLY")
print("UNLOADING I2C1")
OM.unload("I2C1")
print("IS I2C ENABLED: {0}".format(OM.get_i2c_loaded()))
# **************** SPI2 *******************
print("\nIS SPI ENABLED: {0}".format(OM.get_spi_loaded()))
OM.load("SPI2")
print("IS SPI ENABLED: {0}".format(OM.get_spi_loaded()))
# VERIFY SPI2 EXISTS
if os.listdir('/sys/class/spi_master') != "":
print("SPI DEVICE EXISTS")
else:
print("SPI DEVICE DID NOT LOAD PROPERLY")
print("UNLOADING SPI")
OM.unload("SPI2")
print("IS SPI ENABLED: {0}".format(OM.get_spi_loaded()))

99
test/pwmtest.py Normal file
View File

@ -0,0 +1,99 @@
#!/usr/bin/python
import CHIP_IO.PWM as PWM
import CHIP_IO.GPIO as GPIO
import CHIP_IO.OverlayManager as OM
import time
import datetime
import threading
class PWMReceiver(threading.Thread):
def __init__(self,gpio,key,maxcount=20,sleeptime=0.5):
self.gpio = gpio
self.key = key
self.counter = 0
self.maxcount = maxcount
self.sleeptime = sleeptime
threading.Thread.__init__(self)
def run(self):
print("SETTING UP RECEIVER GPIO")
self.gpio.cleanup()
self.gpio.setup(self.key, self.gpio.IN)
print("STARTING RECEIVE LOOP")
try:
while self.counter < self.maxcount:
pwmval = self.gpio.input(self.key)
print("PWM VALUE: {0} @ {1}".format(pwmval, datetime.datetime.now()))
time.sleep(self.sleeptime)
self.counter += 1
except KeyboardInterrupt:
self.gpio.cleanup(self.key)
def PrintPwmData():
print("PRINTING PWM SYSFS DATA")
f = open("/sys/class/pwm/pwmchip0/pwm0/enable")
print("PWM0 ENABLE:\t{}".format(f.readline()))
f.close()
f = open("/sys/class/pwm/pwmchip0/pwm0/period")
print("PWM0 PERIOD:\t{}".format(f.readline()))
f.close()
f = open("/sys/class/pwm/pwmchip0/pwm0/duty_cycle")
print("PWM0 DUTY CYCLE:\t{}".format(f.readline()))
f.close()
f = open("/sys/class/pwm/pwmchip0/pwm0/polarity")
print("PWM0 POLARITY:\t{}".format(f.readline()))
f.close()
if __name__ == "__main__":
# SETUP VARIABLES
PWMGPIO = "PWM0"
RECEIVERGPIO = "CSID0"
COUNT = 150
SLEEPTIME = 0.01
# LOAD THE PWM OVERLAY
print("LOADING PWM OVERLAY")
OM.load("PWM0")
time.sleep(1)
# CLEANUP THE GPIO
#GPIO.cleanup()
#PWM.cleanup()
# SETUP PWM
try:
print("PWM START")
PWM.toggle_debug()
PWM.start(PWMGPIO, 15, 50, 1)
PrintPwmData()
# UNCOMMENT FOR CRASH
#print("PWM SET FREQUENCY")
#PWM.set_frequency(PWMGPIO, 200)
#PrintPwmData()
# UNCOMMENT FOR CRASH
#print("PWM SET DUTY CYCLE")
#PWM.set_duty_cycle(PWMGPIO, 25)
#PrintPwmData()
# SETUP PWM RECEIVER
#rcvr = PWMReceiver(GPIO, RECEIVERGPIO, COUNT, SLEEPTIME)
#rcvr.start()
#time.sleep(COUNT*SLEEPTIME + 1)
raw_input("PRESS ENTER WHEN DONE")
except:
raise
finally:
# CLEANUP
print("CLEANUP")
PWM.stop(PWMGPIO)
PWM.cleanup()
#OM.unload("PWM0")
#GPIO.cleanup()

70
test/spwmtest.py Normal file
View File

@ -0,0 +1,70 @@
#!/usr/bin/python
import CHIP_IO.SOFTPWM as SPWM
import CHIP_IO.GPIO as GPIO
import time
import datetime
import threading
class SPWMReceiver(threading.Thread):
def __init__(self,gpio,key,maxcount=20,sleeptime=0.5):
self.gpio = gpio
self.key = key
self.counter = 0
self.maxcount = maxcount
self.sleeptime = sleeptime
threading.Thread.__init__(self)
def run(self):
print("SETTING UP RECEIVER GPIO")
self.gpio.cleanup()
self.gpio.setup(self.key, self.gpio.IN)
print("STARTING RECEIVE LOOP")
try:
while self.counter < self.maxcount:
pwmval = self.gpio.input(self.key)
print("SPWM VALUE: {0} @ {1}".format(pwmval, datetime.datetime.now()))
time.sleep(self.sleeptime)
self.counter += 1
except KeyboardInterrupt:
self.gpio.cleanup(self.key)
if __name__ == "__main__":
# SETUP VARIABLES
SPWMGPIO = "XIO-P7"
RECEIVERGPIO = "CSID0"
COUNT = 200
SLEEPTIME = 0.01
# CLEANUP THE GPIO
GPIO.cleanup()
SPWM.cleanup()
# ISSUE #16 VERIFICATION
try:
print("VERIFYING FIX FOR ISSUE #16, GPIO CONFIGURED THAT SPWM WANTS TO USE")
GPIO.setup(SPWMGPIO, GPIO.OUT)
SPWM.start(SPWMGPIO, 50, 1)
except Exception as e:
print("EXCEPTION: {}".format(e))
print("GPIO CLEANUP")
GPIO.cleanup()
# SETUP SOFTPWM
print("STARTING SOFTPWM TEST")
SPWM.start(SPWMGPIO, 50, 1)
SPWM.set_frequency(SPWMGPIO, 2)
# SETUP SOFTPWM RECEIVER
rcvr = SPWMReceiver(GPIO, RECEIVERGPIO, COUNT, SLEEPTIME)
rcvr.start()
time.sleep(COUNT*SLEEPTIME + 1)
# CLEANUP
print("CLEANUP")
SPWM.stop(SPWMGPIO)
SPWM.cleanup()
GPIO.cleanup()

0
test/test_gpio_input.py Executable file → Normal file
View File

View File

@ -1,65 +1,84 @@
import pytest
import os
import time
import CHIP_IO.PWM as PWM
import CHIP_IO.OverlayManager as OM
def setup_module(module):
OM.load("PWM0")
def teardown_module(module):
PWM.cleanup()
OM.unload("PWM0")
class TestPwmSetup:
def setup_method(self, test_method):
time.sleep(0.5)
#def teardown_method(self, test_method):
# PWM.cleanup()
#OM.unload("PWM0")
#def setup_module(self, module):
# OM.load("PWM0")
#def teardown_module(self, module):
# OM.unload("PWM0")
def test_start_pwm(self):
PWM.start("PWM0", 0)
pwm_test = '/sys/class/pwm/pwmchip0/pwm0'
pwm_test = '/sys/class/pwm/pwmchip0/pwm0/'
assert os.path.exists(pwm_test)
duty = open(pwm_test + '/duty_cycle').read()
period = open(pwm_test + '/period').read()
assert os.path.exists(pwm_test) == True
duty = open(pwm_test + 'duty_cycle').readline().strip()
period = open(pwm_test + 'period').readline().strip()
assert int(duty) == 0
assert int(period) == 500000
PWM.cleanup()
@pytest.mark.xfail(reason="pwm cleanup is doing weirdness for this test")
def test_start_pwm_with_polarity_one(self):
PWM.start("PWM0", 0, 2000, 1)
pwm_test = '/sys/class/pwm/pwmchip0/pwm0'
pwm_test = '/sys/class/pwm/pwmchip0/pwm0/'
assert os.path.exists(pwm_test)
duty = open(pwm_test + '/duty_cycle').read()
period = open(pwm_test + '/period').read()
polarity = open(pwm_test + '/polarity').read()
#assert os.path.exists(pwm_test) == True
duty = open(pwm_test + 'duty_cycle').readline().strip()
period = open(pwm_test + 'period').readline().strip()
polarity = open(pwm_test + 'polarity').readline().strip()
assert int(duty) == 0
assert int(period) == 500000
assert string(polarity) == "inverted"
PWM.cleanup()
assert str(polarity) == "inverted"
@pytest.mark.xfail(reason="pwm cleanup is doing weirdness for this test")
def test_start_pwm_with_polarity_default(self):
PWM.start("PWM0", 0, 2000, 0)
pwm_test = '/sys/class/pwm/pwmchip0/pwm0'
pwm_test = '/sys/class/pwm/pwmchip0/pwm0/'
assert os.path.exists(pwm_test)
duty = open(pwm_test + '/duty_cycle').read()
period = open(pwm_test + '/period').read()
polarity = open(pwm_test + '/polarity').read()
#assert os.path.exists(pwm_test) == True
duty = open(pwm_test + 'duty_cycle').readline().strip()
period = open(pwm_test + 'period').readline().strip()
polarity = open(pwm_test + 'polarity').readline().strip()
assert int(duty) == 0
assert int(period) == 500000
assert string(polarity) == "normal"
PWM.cleanup()
assert str(polarity) == "normal"
@pytest.mark.xfail(reason="pwm cleanup is doing weirdness for this test")
def test_start_pwm_with_polarity_zero(self):
PWM.start("PWM0", 0, 2000, 0)
pwm_test = '/sys/class/pwm/pwmchip0/pwm0'
pwm_test = '/sys/class/pwm/pwmchip0/pwm0/'
assert os.path.exists(pwm_test)
duty = open(pwm_test + '/duty_cycle').read()
period = open(pwm_test + '/period').read()
polarity = open(pwm_test + '/polarity').read()
#assert os.path.exists(pwm_test) == True
duty = open(pwm_test + 'duty_cycle').readline().strip()
period = open(pwm_test + 'period').readline().strip()
polarity = open(pwm_test + 'polarity').readline().strip()
assert int(duty) == 0
assert int(period) == 500000
assert string(polarity) == "normal"
PWM.cleanup()
assert str(polarity) == "normal"
def test_pwm_start_invalid_pwm_key(self):
with pytest.raises(ValueError):
@ -72,12 +91,10 @@ class TestPwmSetup:
def test_pwm_start_valid_duty_cycle_min(self):
#testing an exception isn't thrown
PWM.start("PWM0", 0)
PWM.cleanup()
def test_pwm_start_valid_duty_cycle_max(self):
#testing an exception isn't thrown
PWM.start("PWM0", 100)
PWM.cleanup()
def test_pwm_start_invalid_duty_cycle_high(self):
with pytest.raises(ValueError):
@ -107,79 +124,62 @@ class TestPwmSetup:
with pytest.raises(TypeError):
PWM.start("PWM0", 0, 100, "1")
@pytest.mark.xfail(reason="pwm cleanup is doing weirdness for this test")
def test_pwm_duty_modified(self):
PWM.start("PWM0", 0)
pwm_test = '/sys/class/pwm/pwmchip0/pwm0'
pwm_test = '/sys/class/pwm/pwmchip0/pwm0/'
assert os.path.exists(pwm_test)
duty = open(pwm_test + '/duty_cycle').read()
period = open(pwm_test + '/period').read()
assert os.path.exists(pwm_test) == True
duty = open(pwm_test + 'duty_cycle').readline().strip()
period = open(pwm_test + 'period').readline().strip()
assert int(duty) == 0
assert int(period) == 500000
PWM.set_duty_cycle("PWM0", 100)
duty = open(pwm_test + '/duty_cycle').read()
period = open(pwm_test + '/period').read()
duty = open(pwm_test + 'duty_cycle').readline().strip()
period = open(pwm_test + 'period').readline().strip()
assert int(duty) == 500000
assert int(period) == 500000
PWM.cleanup()
def test_pwm_duty_cycle_non_setup_key(self):
with pytest.raises(RuntimeError):
PWM.set_duty_cycle("PWM0", 100)
PWM.cleanup()
def test_pwm_duty_cycle_invalid_key(self):
with pytest.raises(ValueError):
PWM.set_duty_cycle("P9_15", 100)
PWM.cleanup()
def test_pwm_duty_cycle_invalid_value_high(self):
PWM.start("PWM0", 0)
with pytest.raises(ValueError):
PWM.set_duty_cycle("PWM0", 101)
PWM.cleanup()
def test_pwm_duty_cycle_invalid_value_negative(self):
PWM.start("PWM0", 0)
with pytest.raises(ValueError):
PWM.set_duty_cycle("PWM0", -1)
PWM.cleanup()
def test_pwm_duty_cycle_invalid_value_string(self):
PWM.start("PWM0", 0)
with pytest.raises(TypeError):
PWM.set_duty_cycle("PWM0", "a")
PWM.cleanup()
def test_pwm_frequency_invalid_value_negative(self):
PWM.start("PWM0", 0)
with pytest.raises(ValueError):
PWM.set_frequency("PWM0", -1)
PWM.cleanup()
def test_pwm_frequency_invalid_value_string(self):
PWM.start("PWM0", 0)
with pytest.raises(TypeError):
PWM.set_frequency("PWM0", "11")
PWM.cleanup()
def test_pwm_freq_non_setup_key(self):
with pytest.raises(RuntimeError):
PWM.set_frequency("PWM0", 100)
PWM.cleanup()
def test_pwm_freq_non_setup_key(self):
with pytest.raises(ValueError):
PWM.set_frequency("P9_15", 100)
PWM.cleanup()
def test_stop_pwm(self):
pass
#PWM.start("PWM0", 1)
#PWM.stop("PWM0")
#assert os.path.exists('/sys/class/gpio/gpio68')
#direction = open('/sys/class/gpio/gpio68/direction').read()
#assert direction == 'out\n'
#PWM.cleanup()

View File

@ -10,6 +10,10 @@ def teardown_module(module):
class TestSoftpwmSetup:
def setup_method(self, test_method):
PWM.cleanup()
def test_start_pwm(self):
PWM.start("XIO-P7", 50, 10)
base = GPIO.get_gpio_base() + 7