diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dd694ea..17e9c76 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,11 @@ +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 diff --git a/CHIP_IO/LRADC.py b/CHIP_IO/LRADC.py new file mode 100644 index 0000000..ed67b63 --- /dev/null +++ b/CHIP_IO/LRADC.py @@ -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 + + diff --git a/CHIP_IO/OverlayManager.py b/CHIP_IO/OverlayManager.py index 7b8f37c..b4d3a0e 100644 --- a/CHIP_IO/OverlayManager.py +++ b/CHIP_IO/OverlayManager.py @@ -1,3 +1,22 @@ +# 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 @@ -79,7 +98,7 @@ def _set_overlay_verify(name, overlay_path, 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) @@ -198,5 +217,5 @@ def unload(overlay): _LOADED[overlay.upper()] = False else: raise ValueError("Invalid Overlay name specified! Choose between: I2C1, SPI2, PWM0, CUST") - + diff --git a/CHIP_IO/Utilities.py b/CHIP_IO/Utilities.py new file mode 100644 index 0000000..6b43716 --- /dev/null +++ b/CHIP_IO/Utilities.py @@ -0,0 +1,66 @@ +# 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 + +# 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) diff --git a/Makefile b/Makefile index 8ac7781..c494367 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/README.rst b/README.rst index 5e76d9d..12bf6b0 100644 --- a/README.rst +++ b/README.rst @@ -6,6 +6,8 @@ NOTE: Now requires the custom DTC to install the library Manual:: +For Python2.7:: + sudo apt-get update sudo apt-get install git build-essential python-dev python-pip flex bison -y git clone https://github.com/atenart/dtc @@ -19,6 +21,21 @@ Manual:: 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. @@ -170,16 +187,16 @@ Inputs work similarly to outputs.:: Polling inputs:: if GPIO.input("CSID0"): - print("HIGH") + print("HIGH") else: - print("LOW") + print("LOW") 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) @@ -187,7 +204,7 @@ Detecting events:: #your amazing code here #detect wherever: if GPIO.event_detected("XIO-P0"): - print "event detected!" + print "event detected!" **GPIO Cleanup** @@ -198,18 +215,17 @@ 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**:: @@ -221,20 +237,44 @@ Hardware PWM requires a DTB Overlay loaded on the CHIP to allow the kernel to kn 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() - - #set polarity to 1 on start: + #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. 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. -**ADC**:: +**LRADC**:: - Not Implemented yet +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**:: @@ -246,7 +286,7 @@ The Overlay Manager enables you to quickly load simple Device Tree Overlays. Th 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() @@ -261,7 +301,7 @@ Only one of each type of overlay can be loaded at a time, but all three options 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") @@ -270,7 +310,27 @@ There is no verification that the Custom Overlay is setup properly, it's fire an # To unload, just call unload() OM.unload("CUST") -Note that this requires the 4.4 kernel with the CONFIG_OF_CONFIGFS option enabled in the kernel config. +**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() **Running tests** diff --git a/overlays/builder.py b/overlays/builder.py index 4355f96..a4408e2 100644 --- a/overlays/builder.py +++ b/overlays/builder.py @@ -2,6 +2,7 @@ from subprocess import call import os import shutil import glob +import sys def compile(): print("Compiling DTS Files") @@ -10,15 +11,16 @@ def compile(): 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("/lib/firmware/chip_io/"): - print("Path not found, creating /lib/firmware/chip_io/") - os.makedirs("/lib/firmware/chip_io/") + 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("/lib/firmware/chip_io/chip-*-.dtbo"): + for fl in glob.glob(overlay_path+"/chip-*-.dtbo"): os.remove(fl) - print("Moving DTBO files to /lib/firmware/chip_io/") - shutil.move("overlays/chip-spi2.dtbo", "/lib/firmware/chip_io/chip-spi2.dtbo") - shutil.move("overlays/chip-i2c1.dtbo", "/lib/firmware/chip_io/chip-i2c1.dtbo") - shutil.move("overlays/chip-pwm0.dtbo", "/lib/firmware/chip_io/chip-pwm0.dtbo") - + 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") diff --git a/setup.py b/setup.py index 96a2127..e626b6a 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ classifiers = ['Development Status :: 3 - Alpha', 'Topic :: System :: Hardware'] setup(name = 'CHIP_IO', - version = '0.2.2', + version = '0.2.3', author = 'Robert Wolterman', author_email = 'robert.wolterman@gmail.com', description = 'A module to control CHIP IO channels', diff --git a/source/c_softpwm.c b/source/c_softpwm.c index d5fadc4..f8a13aa 100644 --- a/source/c_softpwm.c +++ b/source/c_softpwm.c @@ -41,7 +41,6 @@ SOFTWARE. #include "c_pwm.h" #include "common.h" #include "event_gpio.h" -#include "Python.h" #define KEYLEN 7 diff --git a/source/common.c b/source/common.c index 49055a9..d198370 100644 --- a/source/common.c +++ b/source/common.c @@ -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 #include #include "common.h" diff --git a/source/constants.c b/source/constants.c index f14c2af..88d2745 100644 --- a/source/constants.c +++ b/source/constants.c @@ -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.2.2"); + version = Py_BuildValue("s", "0.2.3"); PyModule_AddObject(module, "VERSION", version); } diff --git a/source/event_gpio.c b/source/event_gpio.c index f76f9da..a643abd 100644 --- a/source/event_gpio.c +++ b/source/event_gpio.c @@ -66,7 +66,8 @@ struct callback int fde; int gpio; int edge; - void (*func)(int gpio); + void* data; + void (*func)(int gpio, void* data); struct callback *next; }; struct callback *callbacks = NULL; @@ -549,7 +550,7 @@ void exports_cleanup(void) gpio_unexport(exported_gpios->gpio); } -int add_edge_callback(int gpio, int edge, 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; @@ -559,6 +560,7 @@ int add_edge_callback(int gpio, int edge, void (*func)(int gpio)) 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; @@ -602,7 +604,7 @@ void run_callbacks(int gpio) // Only run if we are allowed if (canrun) { - cb->func(cb->gpio); + cb->func(cb->gpio, cb->data); } } diff --git a/source/event_gpio.h b/source/event_gpio.h index efe8737..7c03db0 100644 --- a/source/event_gpio.h +++ b/source/event_gpio.h @@ -70,7 +70,7 @@ 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, int edge, 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); diff --git a/source/py_gpio.c b/source/py_gpio.c index 5cc8a8e..d757123 100644 --- a/source/py_gpio.c +++ b/source/py_gpio.c @@ -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; @@ -294,7 +294,7 @@ static int add_py_callback(char *channel, int gpio, int edge, unsigned int bounc cb = cb->next; cb->next = new_py_cb; } - add_edge_callback(gpio, edge, run_py_callbacks); + add_edge_callback(gpio, edge, run_py_callbacks, NULL); return 0; } @@ -749,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"}, @@ -763,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, @@ -815,4 +865,4 @@ PyMODINIT_FUNC initGPIO(void) #else return; #endif -} +} \ No newline at end of file diff --git a/test/.ropeproject/config.py b/test/.ropeproject/config.py deleted file mode 100644 index 3745e30..0000000 --- a/test/.ropeproject/config.py +++ /dev/null @@ -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! diff --git a/test/.ropeproject/globalnames b/test/.ropeproject/globalnames deleted file mode 100644 index 1060686..0000000 --- a/test/.ropeproject/globalnames +++ /dev/null @@ -1,2 +0,0 @@ -€}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 TestGPIOInputq eUgptest]q (U num_callbacksqUmystrqUfU loopfunctionqU myfuncallbackqUDO_APEINT3_TESTqUedgeqUgfileqUtUbaseqU DO_XIOP2_TESTqUexqUloopfunction_exitqUDO_APEINT1_TESTqUnum_errsqeu. \ No newline at end of file diff --git a/test/.ropeproject/history b/test/.ropeproject/history deleted file mode 100644 index fcd9c96..0000000 --- a/test/.ropeproject/history +++ /dev/null @@ -1 +0,0 @@ -€]q(]q]qe. \ No newline at end of file diff --git a/test/.ropeproject/objectdb b/test/.ropeproject/objectdb deleted file mode 100644 index 29c40cd..0000000 --- a/test/.ropeproject/objectdb +++ /dev/null @@ -1 +0,0 @@ -€}q. \ No newline at end of file diff --git a/test/lradc_test.py b/test/lradc_test.py new file mode 100644 index 0000000..2b1552d --- /dev/null +++ b/test/lradc_test.py @@ -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) +