├── ASUS ├── __init__.py └── __init__.pyc ├── CHANGELOG.txt ├── GPIOLIST.ods ├── INSTALL.txt ├── LICENCE.txt ├── Makefile ├── PKG-INFO ├── README.md ├── README.txt ├── RPi ├── __init__.py └── __init__.pyc ├── setup.py ├── source ├── RKIO.h ├── c_gpio.c ├── c_gpio.h ├── common.c ├── common.h ├── constants.c ├── constants.h ├── cpuinfo.c ├── cpuinfo.h ├── event_gpio.c ├── event_gpio.h ├── py_gpio.c ├── py_gpio_RPi.c ├── py_pwm.c ├── py_pwm.h ├── soft_pwm.c ├── soft_pwm.h ├── wiringTB.c └── wiringTB.h └── test ├── .btc.py.swp ├── GPIO_IN_OUT_test.py ├── add_event_callback.py ├── btc.py ├── forloop.py ├── gpio_backup.py ├── pwm.py ├── pwm_input.py ├── test.py └── test3.py /ASUS/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TinkerBoard/gpio_lib_python/31fb5d7971fa57d6ef5b6206b287826a7e5597e2/ASUS/__init__.py -------------------------------------------------------------------------------- /ASUS/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TinkerBoard/gpio_lib_python/31fb5d7971fa57d6ef5b6206b287826a7e5597e2/ASUS/__init__.pyc -------------------------------------------------------------------------------- /CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | Change Log 2 | ========== 3 | 4 | 0.5.11 5 | ------ 6 | - Fix - pins > 26 missing when using BOARD mode 7 | - Add getmode() 8 | - Raise exception when a mix of modes is used 9 | - GPIO.cleanaup() unsets the current pin mode 10 | 11 | 0.5.10 12 | ------ 13 | - Issue 95 - support RPi 2 boards 14 | - Introduce RPI_INFO 15 | - Deprecate RPI_REVISION 16 | - Issue 97 - fixed docstring for setup() 17 | 18 | 0.5.9 19 | ----- 20 | - Issue 87 - warn about pull up/down on i2c pins 21 | - Issue 86/75 - wait_for_edge() bugfix 22 | - Issue 84 - recognise RPi properly when using a custom kernel 23 | - Issue 90 - cleanup() on a list/tuple of channels 24 | 25 | 0.5.8 26 | ----- 27 | - Allow lists/tuples of channels in GPIO.setup() 28 | - GPIO.output() now allows lists/tuples of values 29 | - GPIO.wait_for_edge() bug fixes (issue 78) 30 | 31 | 0.5.7 32 | ----- 33 | - Issue 67 - speed up repeated calls to GPIO.wait_for_event() 34 | - Added bouncetime keyword to GPIO.wait_for_event() 35 | - Added extra edge/interrupt unit tests 36 | - GPIO.wait_for_event() can now be mixed with GPIO.add_event_detect() 37 | - Improved cleanups of events 38 | - Issue 69 resolved 39 | 40 | 0.5.6 41 | ----- 42 | - Issue 68 - support for RPi Model B+ 43 | - Fix gpio_function() 44 | 45 | 0.5.5 46 | ----- 47 | - Issue 52 - 'unallocate' a channel 48 | - Issue 35 - use switchbounce with GPIO.event_detected() 49 | - Refactored events code 50 | - Rewrote tests to use unittest mechanism and new test board with loopbacks 51 | - Fixed adding events after a GPIO.cleanup() 52 | - Issue 64 - misleading /dev/mem permissions error 53 | - Issue 59 - name collision with PWM constant and class 54 | 55 | 0.5.4 56 | ----- 57 | - Changed release status (from alpha to full release) 58 | - Warn when GPIO.cleanup() used with nothing to clean up (issue 44) 59 | - Avoid collisions in constants (e.g. HIGH / RISING / PUD_DOWN) 60 | - Accept BOARD numbers in gpio_function (issue 34) 61 | - More return values for gpio_function (INPUT, OUTPUT, SPI, I2C, PWM, SERIAL, UNKNOWN) 62 | - Tidy up docstrings 63 | - Fix /dev/mem access error with gpio_function 64 | 65 | 0.5.3a 66 | ------ 67 | - Allow pydoc for non-root users (issue 27) 68 | - Fix add_event_detect error when run as daemon (issue 32) 69 | - Simplified exception types 70 | - Changed from distribute to pip 71 | 72 | 0.5.2a 73 | ------ 74 | - Added software PWM (experimental) 75 | - Added switch bounce handling to event callbacks 76 | - Added channel number parameter to event callbacks (issue 31) 77 | - Internal refactoring and code tidy up 78 | 79 | 0.5.1a 80 | ------ 81 | - Fixed callbacks for multiple GPIOs (issue 28) 82 | 83 | 0.5.0a 84 | ------ 85 | - Added new edge detection events (interrupt handling) 86 | - Added add_event_detect() 87 | - Added remove_event_detect() 88 | - Added add_event_callback() 89 | - Added wait_for_edge() 90 | - Removed old experimental event functions 91 | - Removed set_rising_event() 92 | - Removed set_falling_event() 93 | - Removed set_high_event() 94 | - Removed set_low_event() 95 | - Changed event_detected() for new edge detection functionality 96 | - input() now returns 0/LOW == False or 1/HIGH == True (integers) instead of False or True (booleans). 97 | - Fix error on repeated import (issue 3) 98 | - Change SetupException to a RuntimeError so it can be caught on import (issue 25, Chris Hager ) 99 | - Improved docstrings of functions 100 | 101 | 0.4.2a 102 | ------ 103 | - Fix for installing on Arch Linux (Python 3.3) (issue 20) 104 | - Initial value when setting a channel as an output (issue 19) 105 | 106 | 0.4.1a 107 | ------ 108 | - Added VERSION 109 | - Permit input() of channels set as outputs (Eric Ptak ) 110 | 111 | 0.4.0a 112 | ------ 113 | - Added support for Revision 2 boards 114 | - Added RPI_REVISION 115 | - Added cleanup() function and removed automatic reset functionality on program exit 116 | - Added get_function() to read existing GPIO channel functionality (suggestion from Eric Ptak ) 117 | - Added set_rising_event() 118 | - Added set_falling_event() 119 | - Added set_high_event() 120 | - Added set_low_event() 121 | - Added event_detected() 122 | - Added test/test.py 123 | - Converted debian to armhf 124 | - Fixed C function short_wait() (thanks to Thibault Porteboeuf ) 125 | 126 | 0.3.1a 127 | ------ 128 | - Fixed critical bug with swapped high/low state on outputs 129 | - Added pull-up / pull-down setup functionality for inputs 130 | 131 | 0.3.0a 132 | ------ 133 | - Rewritten as a C extension 134 | - Now uses /dev/mem and SoC registers instead of /sys/class/gpio 135 | - Faster! 136 | - Make call to GPIO.setmode() mandatory 137 | - Added GPIO.HIGH and GPIO.LOW constants 138 | 139 | 0.2.0 140 | ----- 141 | - Changed status from alpha to beta 142 | - Added setmode() to be able to use BCM GPIO 00.nn channel numbers 143 | - Renamed InvalidPinException to InvalidChannelException 144 | 145 | 0.1.0 146 | ------ 147 | - Fixed direction bug 148 | - Added MANIFEST.in (to include missing file) 149 | - Changed GPIO channel number to pin number 150 | - Tested and working! 151 | 152 | 0.0.3a 153 | ------ 154 | - Added GPIO table 155 | - Refactored 156 | - Fixed a few critical bugs 157 | - Still completely untested! 158 | 159 | 0.0.2a 160 | ------ 161 | - Internal refactoring. Still completely untested! 162 | 163 | 0.0.1a 164 | ------ 165 | - First version. Completely untested until I can get hold of a Raspberry Pi! 166 | 167 | 0.2a 168 | - Add the the functions of GPIO pull up and down 169 | -------------------------------------------------------------------------------- /GPIOLIST.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TinkerBoard/gpio_lib_python/31fb5d7971fa57d6ef5b6206b287826a7e5597e2/GPIOLIST.ods -------------------------------------------------------------------------------- /INSTALL.txt: -------------------------------------------------------------------------------- 1 | If you are using ASUS, all you need to do to install the latest release is: 2 | $ sudo apt-get update 3 | $ sudo apt-get install python-ASUS.gpio python3-ASUS.gpio 4 | 5 | ------------ 6 | 7 | If you are not using ASUS, it is recommended that you install this module using pip: 8 | $ sudo pip install RPi.GPIO 9 | 10 | ------------ 11 | 12 | If you want to build your own version from this downloaded copy, make 13 | sure that you have the Python development source installed first! 14 | 15 | On Raspbian: 16 | $ sudo apt-get install python-dev python3-dev 17 | 18 | To install the module: 19 | 20 | $ sudo python setup.py install 21 | or 22 | $ sudo python3 setup.py install 23 | -------------------------------------------------------------------------------- /LICENCE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2014 Ben Croston 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROG=ASUS.GPIO 2 | 3 | install: 4 | sudo python setup.py install --record log 5 | uninstall: 6 | cat log |xargs rm -rf 7 | clean: 8 | sudo python setup.py clean 9 | 10 | -------------------------------------------------------------------------------- /PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.1 2 | Name: ASUS.GPIO 3 | Version: 0.5.11 4 | Summary: A module to control Raspberry Pi GPIO channels 5 | Home-page: http://sourceforge.net/projects/raspberry-gpio-python/ 6 | Author: Ben Croston 7 | Author-email: ben@croston.org 8 | License: MIT 9 | Description: This package provides a class to control the GPIO on a Raspberry Pi. 10 | 11 | Note that this module is unsuitable for real-time or timing critical applications. This is because you 12 | can not predict when Python will be busy garbage collecting. It also runs under the Linux kernel which 13 | is not suitable for real time applications - it is multitasking O/S and another process may be given 14 | priority over the CPU, causing jitter in your program. If you are after true real-time performance and 15 | predictability, buy yourself an Arduino http://www.arduino.cc ! 16 | 17 | Note that the current release does not support SPI, I2C, hardware PWM or serial functionality on the RPi yet. 18 | This is planned for the near future - watch this space! One-wire functionality is also planned. 19 | 20 | Although hardware PWM is not available yet, software PWM is available to use on all channels. 21 | 22 | For examples and documentation, visit http://sourceforge.net/p/raspberry-gpio-python/wiki/Home/ 23 | 24 | Change Log 25 | ========== 26 | 27 | 0.5.11 28 | ------ 29 | - Fix - pins > 26 missing when using BOARD mode 30 | - Add getmode() 31 | - Raise exception when a mix of modes is used 32 | - GPIO.cleanaup() unsets the current pin mode 33 | 34 | 0.5.10 35 | ------ 36 | - Issue 95 - support RPi 2 boards 37 | - Introduce RPI_INFO 38 | - Deprecate RPI_REVISION 39 | - Issue 97 - fixed docstring for setup() 40 | 41 | 0.5.9 42 | ----- 43 | - Issue 87 - warn about pull up/down on i2c pins 44 | - Issue 86/75 - wait_for_edge() bugfix 45 | - Issue 84 - recognise RPi properly when using a custom kernel 46 | - Issue 90 - cleanup() on a list/tuple of channels 47 | 48 | 0.5.8 49 | ----- 50 | - Allow lists/tuples of channels in GPIO.setup() 51 | - GPIO.output() now allows lists/tuples of values 52 | - GPIO.wait_for_edge() bug fixes (issue 78) 53 | 54 | 0.5.7 55 | ----- 56 | - Issue 67 - speed up repeated calls to GPIO.wait_for_event() 57 | - Added bouncetime keyword to GPIO.wait_for_event() 58 | - Added extra edge/interrupt unit tests 59 | - GPIO.wait_for_event() can now be mixed with GPIO.add_event_detect() 60 | - Improved cleanups of events 61 | - Issue 69 resolved 62 | 63 | 0.5.6 64 | ----- 65 | - Issue 68 - support for RPi Model B+ 66 | - Fix gpio_function() 67 | 68 | 0.5.5 69 | ----- 70 | - Issue 52 - 'unallocate' a channel 71 | - Issue 35 - use switchbounce with GPIO.event_detected() 72 | - Refactored events code 73 | - Rewrote tests to use unittest mechanism and new test board with loopbacks 74 | - Fixed adding events after a GPIO.cleanup() 75 | - Issue 64 - misleading /dev/mem permissions error 76 | - Issue 59 - name collision with PWM constant and class 77 | 78 | 0.5.4 79 | ----- 80 | - Changed release status (from alpha to full release) 81 | - Warn when GPIO.cleanup() used with nothing to clean up (issue 44) 82 | - Avoid collisions in constants (e.g. HIGH / RISING / PUD_DOWN) 83 | - Accept BOARD numbers in gpio_function (issue 34) 84 | - More return values for gpio_function (INPUT, OUTPUT, SPI, I2C, PWM, SERIAL, UNKNOWN) 85 | - Tidy up docstrings 86 | - Fix /dev/mem access error with gpio_function 87 | 88 | 0.5.3a 89 | ------ 90 | - Allow pydoc for non-root users (issue 27) 91 | - Fix add_event_detect error when run as daemon (issue 32) 92 | - Simplified exception types 93 | - Changed from distribute to pip 94 | 95 | 0.5.2a 96 | ------ 97 | - Added software PWM (experimental) 98 | - Added switch bounce handling to event callbacks 99 | - Added channel number parameter to event callbacks (issue 31) 100 | - Internal refactoring and code tidy up 101 | 102 | 0.5.1a 103 | ------ 104 | - Fixed callbacks for multiple GPIOs (issue 28) 105 | 106 | 0.5.0a 107 | ------ 108 | - Added new edge detection events (interrupt handling) 109 | - Added add_event_detect() 110 | - Added remove_event_detect() 111 | - Added add_event_callback() 112 | - Added wait_for_edge() 113 | - Removed old experimental event functions 114 | - Removed set_rising_event() 115 | - Removed set_falling_event() 116 | - Removed set_high_event() 117 | - Removed set_low_event() 118 | - Changed event_detected() for new edge detection functionality 119 | - input() now returns 0/LOW == False or 1/HIGH == True (integers) instead of False or True (booleans). 120 | - Fix error on repeated import (issue 3) 121 | - Change SetupException to a RuntimeError so it can be caught on import (issue 25, Chris Hager ) 122 | - Improved docstrings of functions 123 | 124 | 0.4.2a 125 | ------ 126 | - Fix for installing on Arch Linux (Python 3.3) (issue 20) 127 | - Initial value when setting a channel as an output (issue 19) 128 | 129 | 0.4.1a 130 | ------ 131 | - Added VERSION 132 | - Permit input() of channels set as outputs (Eric Ptak ) 133 | 134 | 0.4.0a 135 | ------ 136 | - Added support for Revision 2 boards 137 | - Added RPI_REVISION 138 | - Added cleanup() function and removed automatic reset functionality on program exit 139 | - Added get_function() to read existing GPIO channel functionality (suggestion from Eric Ptak ) 140 | - Added set_rising_event() 141 | - Added set_falling_event() 142 | - Added set_high_event() 143 | - Added set_low_event() 144 | - Added event_detected() 145 | - Added test/test.py 146 | - Converted debian to armhf 147 | - Fixed C function short_wait() (thanks to Thibault Porteboeuf ) 148 | 149 | 0.3.1a 150 | ------ 151 | - Fixed critical bug with swapped high/low state on outputs 152 | - Added pull-up / pull-down setup functionality for inputs 153 | 154 | 0.3.0a 155 | ------ 156 | - Rewritten as a C extension 157 | - Now uses /dev/mem and SoC registers instead of /sys/class/gpio 158 | - Faster! 159 | - Make call to GPIO.setmode() mandatory 160 | - Added GPIO.HIGH and GPIO.LOW constants 161 | 162 | 0.2.0 163 | ----- 164 | - Changed status from alpha to beta 165 | - Added setmode() to be able to use BCM GPIO 00.nn channel numbers 166 | - Renamed InvalidPinException to InvalidChannelException 167 | 168 | 0.1.0 169 | ------ 170 | - Fixed direction bug 171 | - Added MANIFEST.in (to include missing file) 172 | - Changed GPIO channel number to pin number 173 | - Tested and working! 174 | 175 | 0.0.3a 176 | ------ 177 | - Added GPIO table 178 | - Refactored 179 | - Fixed a few critical bugs 180 | - Still completely untested! 181 | 182 | 0.0.2a 183 | ------ 184 | - Internal refactoring. Still completely untested! 185 | 186 | 0.0.1a 187 | ------ 188 | - First version. Completely untested until I can get hold of a Raspberry Pi! 189 | 190 | 191 | Keywords: Raspberry Pi GPIO 192 | Platform: UNKNOWN 193 | Classifier: Development Status :: 5 - Production/Stable 194 | Classifier: Operating System :: POSIX :: Linux 195 | Classifier: License :: OSI Approved :: MIT License 196 | Classifier: Intended Audience :: Developers 197 | Classifier: Programming Language :: Python :: 2.6 198 | Classifier: Programming Language :: Python :: 2.7 199 | Classifier: Programming Language :: Python :: 3 200 | Classifier: Topic :: Software Development 201 | Classifier: Topic :: Home Automation 202 | Classifier: Topic :: System :: Hardware 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ASUS PYTHON GPIO LIB README 2 | =========================== 3 | 4 | #Download source code\ 5 | git clone https://github.com/TinkerBoard/gpio_lib_python.git 6 | 7 | #Build\ 8 | sudo apt-get install python-dev python2.7-dev python3-dev\ 9 | cd ASUS_GPIO_PYTHON_PATH/gpio/\ 10 | sudo python setup.py install 11 | 12 | #A Simple Python Program\ 13 | import ASUS.GPIO as GPIO\ 14 | GPIO.setmode(GPIO.ASUS)\ 15 | GPIO.setup(17, GPIO.OUT)\ 16 | GPIO.output(17, GPIO.HIGH) 17 | 18 | #More Informaion\ 19 | Send an email to scorpio_chang@asus.com 20 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | This package provides a class to control the GPIO on a ASUS. 2 | 3 | Note that this module is unsuitable for real-time or timing critical applications. This is because you 4 | can not predict when Python will be busy garbage collecting. It also runs under the Linux kernel which 5 | is not suitable for real time applications - it is multitasking O/S and another process may be given 6 | priority over the CPU, causing jitter in your program. If you are after true real-time performance and 7 | predictability, buy yourself an Arduino http://www.arduino.cc ! 8 | 9 | Note that the current release does not support SPI, I2C, hardware PWM or serial functionality on 10 | the ASUS yet. 11 | This is planned for the near future - watch this space! One-wire functionality is also planned. 12 | 13 | Although hardware PWM is not available yet, software PWM is available to use on all channels. 14 | 15 | For examples and documentation, visit http://sourceforge.net/p/raspberry-gpio-python/wiki/Home/ 16 | 17 | -------------------------------------------------------------------------------- /RPi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TinkerBoard/gpio_lib_python/31fb5d7971fa57d6ef5b6206b287826a7e5597e2/RPi/__init__.py -------------------------------------------------------------------------------- /RPi/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TinkerBoard/gpio_lib_python/31fb5d7971fa57d6ef5b6206b287826a7e5597e2/RPi/__init__.pyc -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2012-2015 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | """ 22 | 23 | from distutils.core import setup, Extension 24 | 25 | classifiers = ['Development Status :: 5 - Production/Stable', 26 | 'Operating System :: POSIX :: Linux', 27 | 'License :: OSI Approved :: MIT License', 28 | 'Intended Audience :: Developers', 29 | 'Programming Language :: Python :: 2.6', 30 | 'Programming Language :: Python :: 2.7', 31 | 'Programming Language :: Python :: 3', 32 | 'Topic :: Software Development', 33 | 'Topic :: Home Automation', 34 | 'Topic :: System :: Hardware'] 35 | 36 | setup(name = 'ASUS.GPIO', 37 | version = '0.1', 38 | author = 'ASUS', 39 | author_email = 'ASUS@asus.com', 40 | description = 'A module to control ASUS GPIO channels', 41 | long_description = open('README.txt').read() + open('CHANGELOG.txt').read(), 42 | license = 'MIT', 43 | keywords = 'ASUS GPIO', 44 | url = 'https://github.com/TinkerBoard/gpio_lib_python', 45 | classifiers = classifiers, 46 | packages = ['ASUS'], 47 | ext_modules = [Extension('ASUS.GPIO', ['source/py_gpio.c', 'source/c_gpio.c', 'source/cpuinfo.c', 'source/event_gpio.c', 'source/soft_pwm.c', 'source/py_pwm.c', 'source/common.c', 'source/constants.c', 'source/wiringTB.c'])]) 48 | 49 | setup(name = 'RPi.GPIO', 50 | version = '0.1', 51 | author = 'ASUS', 52 | author_email = 'ASUS@asus.com', 53 | description = 'A module to control ASUS GPIO channels', 54 | long_description = open('README.txt').read() + open('CHANGELOG.txt').read(), 55 | license = 'MIT', 56 | keywords = 'ASUS GPIO', 57 | url = 'https://github.com/TinkerBoard/gpio_lib_python', 58 | classifiers = classifiers, 59 | packages = ['RPi'], 60 | ext_modules = [Extension('RPi.GPIO', ['source/py_gpio_RPi.c', 'source/c_gpio.c', 'source/cpuinfo.c', 'source/event_gpio.c', 'source/soft_pwm.c', 'source/py_pwm.c', 'source/common.c', 'source/constants.c', 'source/wiringTB.c'])]) 61 | -------------------------------------------------------------------------------- /source/RKIO.h: -------------------------------------------------------------------------------- 1 | #ifndef __RKIO_H__ 2 | #define __RKIO_H__ 3 | 4 | #define MAX_PIN_NUM (0x40) 5 | #define CENTERPWM 0x01 6 | //asuspi gpio 7 | //asus 8 | #define SERIAL 40 9 | #define SPI 41 10 | #define I2C 42 11 | #define PWM 43 12 | #define GPIO 44 13 | #define TS_XXXX 45 14 | #define RESERVED 46 15 | #define I2S 47 16 | #define GPS_MAG 48 17 | #define HSADCT 49 18 | #define USB 50 19 | #define HDMI 51 20 | #define SC_XXX 52 21 | #define GPIOIN 53 22 | #define GPIOOUT 54 23 | #define CLKOUT 55 24 | #define CLK1_27M 56 25 | #define VOP0_PWM 57 26 | #define VOP1_PWM 58 27 | 28 | 29 | #define GPIO0_C1 17 //7----->17 30 | 31 | #define GPIO5_B0 (8+152) //8----->160 32 | #define GPIO5_B1 (9+152) //9----->161 33 | #define GPIO5_B2 (10+152) //10----->162 34 | #define GPIO5_B3 (11+152) //11----->163 35 | #define GPIO5_B4 (12+152) //12----->164 36 | #define GPIO5_B5 (13+152) //13----->165 37 | #define GPIO5_B6 (14+152) //14----->166 38 | #define GPIO5_B7 (15+152) //15----->167 39 | #define GPIO5_C0 (16+152) //16----->168 40 | #define GPIO5_C1 (17+152) //17----->169 41 | #define GPIO5_C2 (18+152) //18----->170 42 | #define GPIO5_C3 (19+152) //19----->171 43 | 44 | #define GPIO6_A0 (184) //0----->184 45 | #define GPIO6_A1 (1+184) //1----->185 46 | #define GPIO6_A3 (3+184) //3----->187 47 | #define GPIO6_A4 (4+184) //4----->188 48 | 49 | #define GPIO7_A0 (0+216) //0----->216 50 | #define GPIO7_A7 (7+216) //7----->223 51 | #define GPIO7_B0 (8+216) //8----->224 52 | #define GPIO7_B1 (9+216) //9----->225 53 | #define GPIO7_B2 (10+216) //10----->226 54 | #define GPIO7_C1 (17+216) //17----->233 55 | #define GPIO7_C2 (18+216) //18----->234 56 | #define GPIO7_C6 (22+216) //22----->238 57 | #define GPIO7_C7 (23+216) //23----->239 58 | 59 | #define GPIO8_A3 (3+248) //3----->251 60 | #define GPIO8_A4 (4+248) //4----->252 61 | #define GPIO8_A5 (5+248) //5----->253 62 | #define GPIO8_A6 (6+248) //6----->254 63 | #define GPIO8_A7 (7+248) //7----->255 64 | #define GPIO8_B0 (8+248) //8----->256 65 | #define GPIO8_B1 (9+248) //9----->257 66 | 67 | #define RK3288_PMU 0xff730000 68 | #define PMU_GPIO0C_IOMUX 0x008c 69 | 70 | 71 | #define RK3288_GPIO(x) (GPIO0_BASE+x*GPIO_LENGTH+(x>0)*GPIO_CHANNEL) 72 | #define GPIO_LENGTH 0x00010000 73 | #define GPIO_CHANNEL 0x00020000 74 | #define GPIO0_BASE 0xff750000 75 | #define GPIO_BANK 9 76 | #define RK3288_GRF_PHYS 0xff770000 77 | 78 | #define GRF_GPIO5B_IOMUX 0x0050 79 | #define GRF_GPIO5C_IOMUX 0x0054 80 | #define GRF_GPIO6A_IOMUX 0x005c 81 | #define GRF_GPIO6B_IOMUX 0x0060 82 | #define GRF_GPIO6C_IOMUX 0x0064 83 | #define GRF_GPIO7A_IOMUX 0x006c 84 | #define GRF_GPIO7B_IOMUX 0x0070 85 | #define GRF_GPIO7CL_IOMUX 0x0074 86 | #define GRF_GPIO7CH_IOMUX 0x0078 87 | #define GRF_GPIO8A_IOMUX 0x0080 88 | #define GRF_GPIO8B_IOMUX 0x0084 89 | 90 | /* Pull up / down / Z */ 91 | #define PMU_GPIO0C_P 0x006c 92 | #define GRF_GPIO1D_P 0x014c 93 | #define GRF_GPIO2A_P 0x0150 94 | #define GRF_GPIO2B_P 0x0154 95 | #define GRF_GPIO2C_P 0x0158 96 | #define GRF_GPIO3A_P 0x0160 97 | #define GRF_GPIO3B_P 0x0164 98 | #define GRF_GPIO3C_P 0x0168 99 | #define GRF_GPIO3D_P 0x016c 100 | #define GRF_GPIO4A_P 0x0170 101 | #define GRF_GPIO4B_P 0x0174 102 | #define GRF_GPIO4C_P 0x0178 103 | #define GRF_GPIO4D_P 0x017c 104 | #define GRF_GPIO5B_P 0x0184 105 | #define GRF_GPIO5C_P 0x0188 106 | #define GRF_GPIO6A_P 0x0190 107 | #define GRF_GPIO6B_P 0x0194 108 | #define GRF_GPIO6C_P 0x0198 109 | #define GRF_GPIO7A_P 0x01a0 110 | #define GRF_GPIO7B_P 0x01a4 111 | #define GRF_GPIO7C_P 0x01a8 112 | #define GRF_GPIO8A_P 0x01b0 113 | #define GRF_GPIO8B_P 0x01b4 114 | 115 | /* Drive Strength */ 116 | #define PMU_GPIO0C_E 0x0078 117 | #define GRF_GPIO1D_E 0x01cc 118 | #define GRF_GPIO2A_E 0x01d0 119 | #define GRF_GPIO2B_E 0x01d4 120 | #define GRF_GPIO2C_E 0x01d8 121 | #define GRF_GPIO3A_E 0x01e0 122 | #define GRF_GPIO3B_E 0x01e4 123 | #define GRF_GPIO3C_E 0x01e8 124 | #define GRF_GPIO3D_E 0x01ec 125 | #define GRF_GPIO4A_E 0x01f0 126 | #define GRF_GPIO4B_E 0x01f4 127 | #define GRF_GPIO4C_E 0x01f8 128 | #define GRF_GPIO4D_E 0x01fc 129 | #define GRF_GPIO5B_E 0x0204 130 | #define GRF_GPIO5C_E 0x0208 131 | #define GRF_GPIO6A_E 0x0210 132 | #define GRF_GPIO6B_E 0x0214 133 | #define GRF_GPIO6C_E 0x0218 134 | #define GRF_GPIO7A_E 0x0220 135 | #define GRF_GPIO7B_E 0x0224 136 | #define GRF_GPIO7C_E 0x0228 137 | #define GRF_GPIO8A_E 0x0230 138 | #define GRF_GPIO8B_E 0x0234 139 | 140 | 141 | #define RK3288_PWM 0xff680000 142 | #define RK3288_PWM0_CNT 0x0000 143 | #define RK3288_PWM0_PERIOD 0x0004 144 | #define RK3288_PWM0_DUTY 0x0008 145 | #define RK3288_PWM0_CTR 0x000c 146 | #define RK3288_PWM1_CNT 0x0010 147 | #define RK3288_PWM1_PERIOD 0x0014 148 | #define RK3288_PWM1_DUTY 0x0018 149 | #define RK3288_PWM1_CTR 0x001c 150 | #define RK3288_PWM2_CNT 0x0020 151 | #define RK3288_PWM2_PERIOD 0x0024 152 | #define RK3288_PWM2_DUTY 0x0028 153 | #define RK3288_PWM2_CTR 0x002c 154 | #define RK3288_PWM3_CNT 0x0030 155 | #define RK3288_PWM3_PERIOD 0x0034 156 | #define RK3288_PWM3_DUTY 0x0038 157 | #define RK3288_PWM3_CTR 0x003c 158 | 159 | 160 | #define GPIO_SWPORTA_DR_OFFSET 0x0000 161 | #define GPIO_SWPORTA_DDR_OFFSET 0x0004 162 | #define GPIO_INTEN_OFFSET 0x0030 163 | #define GPIO_INTMASK_OFFSET 0x0034 164 | #define GPIO_INTTYPE_LEVEL_OFFSET 0x0038 165 | #define GPIO_INT_POLARITY_OFFSET 0x003c 166 | #define GPIO_INT_STATUS_OFFSET 0x0040 167 | #define GPIO_INT_RAWSTATUS_OFFSET 0x0044 168 | #define GPIO_DEBOUNCE_OFFSET 0x0048 169 | #define GPIO_PORTA_EOF_OFFSET 0x004c 170 | #define GPIO_EXT_PORTA_OFFSET 0x0050 171 | #define GPIO_LS_SYNC_OFFSET 0x0060 172 | 173 | #define RK3288_CRU 0xff760000 174 | #define CRU_CLKSEL2_CON 0x0068 175 | #define CRU_CLKGATE14_CON 0x0198 176 | #define CRU_CLKGATE17_CON 0x01a4 177 | //#define PWM0 26 178 | //#define PWM1 27 179 | #define PWM0 GPIO7_A0 180 | #define PWM2 GPIO7_C6 181 | #define PWM3 GPIO7_C7 182 | 183 | 184 | 185 | #endif 186 | -------------------------------------------------------------------------------- /source/c_gpio.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2015 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "c_gpio.h" 31 | #include "common.h" 32 | #include "wiringTB.h" 33 | 34 | void short_wait(void) 35 | { 36 | int i; 37 | 38 | for (i=0; i<150; i++) // wait 150 cycles 39 | { 40 | asm volatile("nop"); 41 | } 42 | } 43 | 44 | int setup(void) 45 | { 46 | return tinker_board_setup(0); 47 | } 48 | 49 | void set_pullupdn(int gpio, int pud) 50 | { 51 | asus_pullUpDnControl(gpio, pud); 52 | } 53 | 54 | int setup_gpio(int gpio, int direction, int pud) 55 | { 56 | asus_pullUpDnControl(gpio, pud); 57 | asus_set_pin_mode(gpio, direction); 58 | return 1; 59 | } 60 | 61 | 62 | int gpio_function(int gpio) 63 | { 64 | return asus_get_pin_mode(gpio); 65 | } 66 | 67 | void output_gpio(int gpio, int value) 68 | { 69 | asus_digitalWrite(gpio, value); 70 | } 71 | 72 | int input_gpio(int gpio) 73 | { 74 | return asus_digitalRead(gpio); 75 | } 76 | 77 | void cleanup(void) 78 | { 79 | asus_cleanup(); 80 | } 81 | 82 | /* tinkerboard function*/ 83 | 84 | void hard_pwmWrite(int gpio, int value) 85 | { 86 | asus_pwm_write(gpio, value); 87 | } 88 | void hard_pwmToneWrite(int gpio, int freq) 89 | { 90 | asus_pwmToneWrite(gpio, freq); 91 | } 92 | void hard_pwm_set_Frequency(int gpio, int divisor) 93 | { 94 | asus_set_pwmFrequency(gpio, divisor); 95 | } 96 | void hard_pwm_set_Period(int gpio, unsigned int period) 97 | { 98 | asus_set_pwmPeriod(gpio, period); 99 | } 100 | 101 | void gpio_set_drive(int gpio, int drv_type) 102 | { 103 | asus_set_GpioDriveStrength(gpio, drv_type); 104 | 105 | } 106 | int gpio_get_drive(int gpio) 107 | { 108 | return asus_get_GpioDriveStrength(gpio); 109 | } 110 | -------------------------------------------------------------------------------- /source/c_gpio.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2013 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | int setup (void); 24 | int setup_gpio (int gpio, int direction, int pud); 25 | int gpio_function (int gpio); 26 | void output_gpio (int gpio, int value); 27 | int input_gpio (int gpio); 28 | void set_rising_event (int gpio, int enable); 29 | void set_falling_event (int gpio, int enable); 30 | void set_high_event (int gpio, int enable); 31 | void set_low_event (int gpio, int enable); 32 | int eventdetected (int gpio); 33 | void cleanup (void); 34 | 35 | /* tinkerboard */ 36 | void hard_pwmWrite (int gpio, int value); 37 | void hard_pwmToneWrite (int gpio, int freq); 38 | void hard_pwm_set_Frequency (int gpio, int divisor); 39 | void hard_pwm_set_Period (int gpio, unsigned int period); 40 | void gpio_set_drive (int gpio, int drv_type); 41 | int gpio_get_drive (int gpio); 42 | 43 | #define SETUP_OK 0 44 | #define SETUP_DEVMEM_FAIL 1 45 | #define SETUP_MALLOC_FAIL 2 46 | #define SETUP_MMAP_FAIL 3 47 | // Pin modes 48 | 49 | #define INPUT 0 50 | #define OUTPUT 1 51 | #define PWM_OUTPUT 2 52 | #define GPIO_CLOCK 3 53 | #define SOFT_PWM_OUTPUT 4 54 | #define SOFT_TONE_OUTPUT 5 55 | #define PWM_TONE_OUTPUT 6 56 | 57 | #define LOW 0 58 | #define HIGH 1 59 | 60 | // Pull up/down/none 61 | 62 | #define PUD_OFF 0 63 | #define PUD_DOWN 1 64 | #define PUD_UP 2 65 | 66 | // Drive Strength 2mA, 4mA, 8mA, 12mA 67 | #define E_2MA 0 68 | #define E_4MA 1 69 | #define E_8MA 2 70 | #define E_12MA 3 71 | 72 | #define RK3288 73 | -------------------------------------------------------------------------------- /source/common.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013-2014 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "Python.h" 24 | #include "c_gpio.h" 25 | #include "common.h" 26 | 27 | int gpio_mode = MODE_UNKNOWN; 28 | #ifdef RK3288 29 | 30 | #define GPIO0_C1 17 //7----->17 31 | 32 | #define GPIO5_B0 (8+152) //7----->160 33 | #define GPIO5_B1 (9+152) //7----->161 34 | #define GPIO5_B2 (10+152) //7----->162 35 | #define GPIO5_B3 (11+152) //7----->163 36 | #define GPIO5_B4 (12+152) //7----->164 37 | #define GPIO5_B5 (13+152) //7----->165 38 | #define GPIO5_B6 (14+152) //7----->166 39 | #define GPIO5_B7 (15+152) //7----->167 40 | #define GPIO5_C0 (16+152) //7----->168 41 | #define GPIO5_C1 (17+152) //7----->169 42 | #define GPIO5_C2 (18+152) //7----->170 43 | #define GPIO5_C3 (19+152) //7----->171 44 | 45 | #define GPIO6_A0 (184) //7----->184 46 | #define GPIO6_A1 (1+184) //7----->185 47 | #define GPIO6_A3 (3+184) //7----->187 48 | #define GPIO6_A4 (4+184) //7----->188 49 | 50 | #define GPIO7_A7 (7+216) //7----->223 51 | #define GPIO7_B0 (8+216) //7----->224 52 | #define GPIO7_B1 (9+216) //7----->225 53 | #define GPIO7_B2 (10+216) //7----->226 54 | #define GPIO7_C1 (17+216) //7----->233 55 | #define GPIO7_C2 (18+216) //7----->234 56 | #define GPIO7_C6 (22+216) //7----->238 57 | #define GPIO7_C7 (23+216) //7----->239 58 | 59 | #define GPIO8_A3 (3+248) //7----->251 60 | #define GPIO8_A4 (4+248) //7----->252 61 | #define GPIO8_A5 (5+248) //7----->253 62 | #define GPIO8_A6 (6+248) //7----->254 63 | #define GPIO8_A7 (7+248) //7----->255 64 | #define GPIO8_B0 (8+248) //7----->256 65 | #define GPIO8_B1 (9+248) //7----->257 66 | 67 | const int pin_to_gpio_rev[41]={-1,-1,-1,GPIO8_A4,-1,GPIO8_A5,-1,GPIO0_C1,GPIO5_B1, 68 | -1,GPIO5_B0,GPIO5_B4,GPIO6_A0,GPIO5_B6,-1,GPIO5_B7,GPIO5_B2,-1,GPIO5_B3, 69 | GPIO8_B1,-1,GPIO8_B0,GPIO5_C3,GPIO8_A6,GPIO8_A7,-1,GPIO8_A3,GPIO7_C1,GPIO7_C2, 70 | GPIO5_B5,-1,GPIO5_C0,GPIO7_C7,GPIO7_C6,-1,GPIO6_A1,GPIO7_A7,GPIO7_B0,GPIO6_A3, 71 | -1,GPIO6_A4}; 72 | #else 73 | const int pin_to_gpio_rev[41] = {-1, -1, -1, 2, -1, 3, -1, 4, 14, -1, 15, 17, 18, 27, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, 5, -1, 6, 12, 13, -1, 19, 16, 26, 20, -1, 21 };//it depend on ee 74 | #endif 75 | const int bcm_gpio_to_pin[28]={ 76 | 27,28, 3, 5, 7, //GPIO0-4 77 | 29,31,26,24,21, //GPIO5-9 78 | 19,23,32,33, 8, //GPIO10-14 79 | 10,36,11,12,35, //GPIO15-19 80 | 38,40,15,16,18, //GPIO20-24 81 | 22,37,13 //GPIO25-27 82 | }; 83 | int setup_error = 0; 84 | int module_setup = 0; 85 | 86 | int check_gpio_priv(void) 87 | { 88 | // check module has been imported cleanly 89 | 90 | if (setup_error) 91 | { 92 | PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!"); 93 | return 1; 94 | } 95 | 96 | // check mmap setup has worked 97 | if (!module_setup) 98 | { 99 | PyErr_SetString(PyExc_RuntimeError, "No access to /dev/mem. Try running as root!"); 100 | return 2; 101 | } 102 | return 0; 103 | } 104 | 105 | int get_gpio_number(int channel, unsigned int *gpio) 106 | { 107 | // check setmode() has been run 108 | 109 | if (gpio_mode != BOARD && gpio_mode != RK && gpio_mode != ASUS && gpio_mode != BCM) 110 | { 111 | PyErr_SetString(PyExc_RuntimeError, "Please set pin numbering mode using GPIO.setmode(GPIO.BOARD), GPIO.setmode(GPIO.ASUS), GPIO.setmode(GPIO.BCM) or GPIO.setmode(GPIO.RK)"); 112 | return 3; 113 | } 114 | 115 | // check channel number is in range 116 | if ( (gpio_mode == RK && (channel < 0 || channel > 300)) 117 | || (gpio_mode == ASUS && (channel < 0 || channel > 300)) 118 | || (gpio_mode == BCM && (channel < 0 || channel > 27)) 119 | || (gpio_mode == BOARD && (channel < 1 || channel > 40) ) ) 120 | { 121 | PyErr_SetString(PyExc_ValueError, "The channel sent is invalid on a ASUS"); 122 | return 4; 123 | } 124 | 125 | // convert channel to gpio 126 | if (gpio_mode == BOARD) 127 | { 128 | if (*(*pin_to_gpio+channel) == -1) 129 | { 130 | PyErr_SetString(PyExc_ValueError, "The channel sent is invalid on a ASUS"); 131 | return 5; 132 | } 133 | else 134 | { 135 | *gpio = *(*pin_to_gpio+channel); 136 | } 137 | } 138 | else if(gpio_mode == BCM) 139 | { 140 | *gpio = *(*pin_to_gpio+bcm_gpio_to_pin[channel]); 141 | } 142 | else // gpio_mode == RK or gpio_mode == ASUS 143 | { 144 | *gpio = channel; 145 | } 146 | 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /source/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013-2015 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "cpuinfo.h" 24 | 25 | #define MODE_UNKNOWN -1 26 | #define BOARD 10 27 | #define BCM 11 28 | #define RK 12 29 | #define ASUS 13 30 | 31 | #define SERIAL 40 32 | #define SPI 41 33 | #define I2C 42 34 | #define PWM 43 35 | #define GPIO 44 36 | #define TS_XXXX 45 37 | #define RESERVED 46 38 | #define I2S 47 39 | #define GPS_MAG 48 40 | #define HSADCT 49 41 | #define USB 50 42 | #define HDMI 51 43 | #define SC_XXX 52 44 | #define GPIOIN 53 45 | #define GPIOOUT 54 46 | #define CLKOUT 55 47 | #define CLK1_27M 56 48 | #define VOP0_PWM 57 49 | #define VOP1_PWM 58 50 | 51 | 52 | 53 | int gpio_mode; 54 | const int pin_to_gpio_rev[41]; 55 | const int (*pin_to_gpio)[41]; 56 | int gpio_direction[300]; 57 | asuspi_info asuspiinfo; 58 | int setup_error; 59 | int module_setup; 60 | int check_gpio_priv(void); 61 | int get_gpio_number(int channel, unsigned int *gpio); 62 | -------------------------------------------------------------------------------- /source/constants.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013-2015 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "Python.h" 24 | #include "constants.h" 25 | #include "common.h" 26 | #include "c_gpio.h" 27 | #include "event_gpio.h" 28 | 29 | void define_constants(PyObject *module) 30 | { 31 | high = Py_BuildValue("i", HIGH); 32 | PyModule_AddObject(module, "HIGH", high); 33 | 34 | low = Py_BuildValue("i", LOW); 35 | PyModule_AddObject(module, "LOW", low); 36 | 37 | output = Py_BuildValue("i", OUTPUT); 38 | PyModule_AddObject(module, "OUT", output); 39 | 40 | input = Py_BuildValue("i", INPUT); 41 | PyModule_AddObject(module, "IN", input); 42 | 43 | pwm_output = Py_BuildValue("i", PWM_OUTPUT); 44 | PyModule_AddObject(module, "PWM_OUTPUT", pwm_output); 45 | 46 | pwm = Py_BuildValue("i", PWM); 47 | PyModule_AddObject(module, "HARD_PWM", pwm); 48 | 49 | serial = Py_BuildValue("i", SERIAL); 50 | PyModule_AddObject(module, "SERIAL", serial); 51 | 52 | i2c = Py_BuildValue("i", I2C); 53 | PyModule_AddObject(module, "I2C", i2c); 54 | 55 | spi = Py_BuildValue("i", SPI); 56 | PyModule_AddObject(module, "SPI", spi); 57 | 58 | unknown = Py_BuildValue("i", MODE_UNKNOWN); 59 | PyModule_AddObject(module, "UNKNOWN", unknown); 60 | 61 | board = Py_BuildValue("i", BOARD); 62 | PyModule_AddObject(module, "BOARD", board); 63 | 64 | bcm = Py_BuildValue("i", BCM); 65 | PyModule_AddObject(module, "BCM", bcm); 66 | 67 | rk = Py_BuildValue("i", RK); 68 | PyModule_AddObject(module, "RK", rk); 69 | 70 | asus = Py_BuildValue("i", ASUS); 71 | PyModule_AddObject(module, "ASUS", asus); 72 | 73 | pud_off = Py_BuildValue("i", PUD_OFF + PY_PUD_CONST_OFFSET); 74 | PyModule_AddObject(module, "PUD_OFF", pud_off); 75 | 76 | pud_up = Py_BuildValue("i", PUD_UP + PY_PUD_CONST_OFFSET); 77 | PyModule_AddObject(module, "PUD_UP", pud_up); 78 | 79 | pud_down = Py_BuildValue("i", PUD_DOWN + PY_PUD_CONST_OFFSET); 80 | PyModule_AddObject(module, "PUD_DOWN", pud_down); 81 | 82 | rising_edge = Py_BuildValue("i", RISING_EDGE + PY_EVENT_CONST_OFFSET); 83 | PyModule_AddObject(module, "RISING", rising_edge); 84 | 85 | falling_edge = Py_BuildValue("i", FALLING_EDGE + PY_EVENT_CONST_OFFSET); 86 | PyModule_AddObject(module, "FALLING", falling_edge); 87 | 88 | both_edge = Py_BuildValue("i", BOTH_EDGE + PY_EVENT_CONST_OFFSET); 89 | PyModule_AddObject(module, "BOTH", both_edge); 90 | 91 | version = Py_BuildValue("s", "0.1"); 92 | PyModule_AddObject(module, "VERSION", version); 93 | 94 | drv_2ma = Py_BuildValue("i", E_2MA); 95 | PyModule_AddObject(module, "E_2MA", drv_2ma); 96 | 97 | drv_4ma = Py_BuildValue("i", E_4MA); 98 | PyModule_AddObject(module, "E_4MA", drv_4ma); 99 | 100 | drv_8ma = Py_BuildValue("i", E_8MA); 101 | PyModule_AddObject(module, "E_8MA", drv_8ma); 102 | 103 | drv_12ma = Py_BuildValue("i", E_12MA); 104 | PyModule_AddObject(module, "E_12MA", drv_12ma); 105 | } 106 | -------------------------------------------------------------------------------- /source/constants.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #define PY_PUD_CONST_OFFSET 20 24 | #define PY_EVENT_CONST_OFFSET 30 25 | 26 | PyObject *high; 27 | PyObject *low; 28 | PyObject *input; 29 | PyObject *output; 30 | PyObject *pwm_output; 31 | PyObject *pwm; 32 | PyObject *serial; 33 | PyObject *i2c; 34 | PyObject *spi; 35 | PyObject *unknown; 36 | PyObject *board; 37 | PyObject *rk; 38 | PyObject *asus; 39 | PyObject *bcm; 40 | PyObject *pud_off; 41 | PyObject *pud_up; 42 | PyObject *pud_down; 43 | PyObject *rising_edge; 44 | PyObject *falling_edge; 45 | PyObject *both_edge; 46 | PyObject *version; 47 | PyObject *drv_2ma; 48 | PyObject *drv_4ma; 49 | PyObject *drv_8ma; 50 | PyObject *drv_12ma; 51 | 52 | void define_constants(PyObject *module); 53 | -------------------------------------------------------------------------------- /source/cpuinfo.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2015 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "cpuinfo.h" 27 | 28 | int get_asuspi_info(asuspi_info *info) 29 | { 30 | FILE *fp; 31 | char buffer[1024]; 32 | char hardware[1024]; 33 | int found = 0; 34 | char revision[1024]; 35 | if ((fp = fopen("/proc/cpuinfo", "r")) == NULL) 36 | return -1; 37 | while(!feof(fp)) 38 | { 39 | if(fgets(buffer, sizeof(buffer) , fp) != NULL); 40 | sscanf(buffer, "Hardware : %s", hardware); 41 | if (strcmp(hardware, "Rockchip") == 0) 42 | { 43 | found = 1; 44 | } 45 | sscanf(buffer, "Revision : %s", revision); 46 | 47 | } 48 | fclose(fp); 49 | 50 | if (!found) 51 | return -1; 52 | info->p1_revision = 3; 53 | strcpy(info->revision, revision); 54 | info->type = "Tinker Board"; 55 | info->processor = "ROCKCHIP3288"; 56 | info->manufacturer = "ASUS"; 57 | info->ram = "1024M"; 58 | 59 | return 0; 60 | } 61 | 62 | -------------------------------------------------------------------------------- /source/cpuinfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2015 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef CPUINFO_H 24 | #define CPUINFO_H 25 | typedef struct 26 | { 27 | int p1_revision; 28 | char *ram; 29 | char *manufacturer; 30 | char *processor; 31 | char *type; 32 | char revision[1024]; 33 | } asuspi_info; 34 | #endif /* CPUINFO_H */ 35 | 36 | int get_asuspi_info(asuspi_info *info); 37 | -------------------------------------------------------------------------------- /source/event_gpio.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013-2014 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "event_gpio.h" 33 | 34 | const char *stredge[4] = {"none", "rising", "falling", "both"}; 35 | 36 | struct gpios 37 | { 38 | unsigned int gpio; 39 | int value_fd; 40 | int exported; 41 | int edge; 42 | int initial_thread; 43 | int initial_wait; 44 | int thread_added; 45 | int bouncetime; 46 | unsigned long long lastcall; 47 | struct gpios *next; 48 | }; 49 | struct gpios *gpio_list = NULL; 50 | 51 | // event callbacks 52 | struct callback 53 | { 54 | unsigned int gpio; 55 | void (*func)(unsigned int gpio); 56 | struct callback *next; 57 | }; 58 | struct callback *callbacks = NULL; 59 | 60 | pthread_t threads; 61 | int event_occurred[54] = { 0 }; 62 | int thread_running = 0; 63 | int epfd_thread = -1; 64 | int epfd_blocking = -1; 65 | 66 | /************* /sys/class/gpio functions ************/ 67 | int gpio_export(unsigned int gpio) 68 | { 69 | int fd, len; 70 | char str_gpio[10]; //max value of unsigned int = 2^32-1(4294967295,4 * (1024)^3, 4*10^9), max length=10 71 | if ((fd = open("/sys/class/gpio/export", O_WRONLY)) < 0) 72 | return -1; 73 | len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio); 74 | if(write(fd, str_gpio, len + 1) < 0) 75 | { 76 | } 77 | close(fd); 78 | return 0; 79 | } 80 | 81 | int gpio_unexport(unsigned int gpio) 82 | { 83 | int fd, len; 84 | char str_gpio[10]; //max value of unsigned int = 2^32-1(4294967295,4 * (1024)^3, 4*10^9), max length=10 85 | if ((fd = open("/sys/class/gpio/unexport", O_WRONLY)) < 0) 86 | return -1; 87 | len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio); 88 | if(write(fd, str_gpio, len + 1) < 0) 89 | { 90 | } 91 | close(fd); 92 | return 0; 93 | } 94 | 95 | int gpio_set_direction(unsigned int gpio, unsigned int in_flag) 96 | { 97 | int fd; 98 | char filename[45]; //command length=30 gpio max length=10 '\0' length=1 flexible length=10%(4) 99 | snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio); 100 | 101 | usleep(500000); 102 | 103 | if ((fd = open(filename, O_WRONLY)) < 0) 104 | { 105 | return -1; 106 | } 107 | if (in_flag) 108 | { 109 | if (write(fd, "in", 3) < 0) 110 | { 111 | } 112 | } 113 | else 114 | { 115 | if (write(fd, "out", 4) < 0) 116 | { 117 | } 118 | } 119 | close(fd); 120 | return 0; 121 | } 122 | 123 | int gpio_set_edge(unsigned int gpio, unsigned int edge) 124 | { 125 | int fd; 126 | char filename[40]; //command length=25 gpio max length=10 '\0' length=1 flexible length=10%(4) 127 | snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/edge", gpio); 128 | 129 | if ((fd = open(filename, O_WRONLY)) < 0) 130 | { 131 | return -1; 132 | } 133 | 134 | if(write(fd, stredge[edge], strlen(stredge[edge]) + 1) < 0) 135 | { 136 | } 137 | close(fd); 138 | return 0; 139 | } 140 | 141 | int open_value_file(unsigned int gpio) 142 | { 143 | int fd; 144 | char filename[41]; //command length=26 gpio max length=10 '\0' length=1 flexible length=10%(4) 145 | 146 | // create file descriptor of value file 147 | snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio); 148 | 149 | if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0) 150 | { 151 | return -1; 152 | } 153 | return fd; 154 | } 155 | 156 | /********* gpio list functions **********/ 157 | struct gpios *get_gpio(unsigned int gpio) 158 | { 159 | struct gpios *g = gpio_list; 160 | while (g != NULL) 161 | { 162 | if (g->gpio == gpio) 163 | return g; 164 | g = g->next; 165 | } 166 | return NULL; 167 | } 168 | 169 | struct gpios *get_gpio_from_value_fd(int fd) 170 | { 171 | struct gpios *g = gpio_list; 172 | while (g != NULL) 173 | { 174 | if (g->value_fd == fd) 175 | return g; 176 | g = g->next; 177 | } 178 | return NULL; 179 | } 180 | 181 | struct gpios *new_gpio(unsigned int gpio) 182 | { 183 | struct gpios *new_gpio; 184 | printf("new gpio = %d\n",gpio); 185 | new_gpio = malloc(sizeof(struct gpios)); 186 | if (new_gpio == 0) 187 | return NULL; // out of memory 188 | 189 | new_gpio->gpio = gpio; 190 | if (gpio_export(gpio) != 0) 191 | { 192 | free(new_gpio); 193 | return NULL; 194 | } 195 | new_gpio->exported = 1; 196 | if (gpio_set_direction(gpio,1) != 0) // 1==input 197 | { 198 | free(new_gpio); 199 | return NULL; 200 | } 201 | 202 | if ((new_gpio->value_fd = open_value_file(gpio)) == -1) 203 | { 204 | gpio_unexport(gpio); 205 | free(new_gpio); 206 | return NULL; 207 | } 208 | 209 | new_gpio->initial_thread = 1; 210 | new_gpio->initial_wait = 1; 211 | new_gpio->bouncetime = -666; 212 | new_gpio->lastcall = 0; 213 | new_gpio->thread_added = 0; 214 | 215 | if (gpio_list == NULL) 216 | { 217 | new_gpio->next = NULL; 218 | } 219 | else 220 | { 221 | new_gpio->next = gpio_list; 222 | } 223 | gpio_list = new_gpio; 224 | return new_gpio; 225 | } 226 | 227 | void delete_gpio(unsigned int gpio) 228 | { 229 | struct gpios *g = gpio_list; 230 | struct gpios *temp; 231 | struct gpios *prev = NULL; 232 | 233 | while (g != NULL) 234 | { 235 | if (g->gpio == gpio) 236 | { 237 | if (prev == NULL) 238 | gpio_list = g->next; 239 | else 240 | prev->next = g->next; 241 | temp = g; 242 | g = g->next; 243 | free(temp); 244 | return; 245 | } 246 | else 247 | { 248 | prev = g; 249 | g = g->next; 250 | } 251 | } 252 | } 253 | 254 | int gpio_event_added(unsigned int gpio) 255 | { 256 | struct gpios *g = gpio_list; 257 | while (g != NULL) 258 | { 259 | if (g->gpio == gpio) 260 | return g->edge; 261 | g = g->next; 262 | } 263 | return 0; 264 | } 265 | 266 | /******* callback list functions ********/ 267 | int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio)) 268 | { 269 | struct callback *cb = callbacks; 270 | struct callback *new_cb; 271 | 272 | new_cb = malloc(sizeof(struct callback)); 273 | if (new_cb == 0) 274 | return -1; // out of memory 275 | 276 | new_cb->gpio = gpio; 277 | new_cb->func = func; 278 | new_cb->next = NULL; 279 | 280 | if (callbacks == NULL) 281 | { 282 | // start new list 283 | callbacks = new_cb; 284 | } 285 | else 286 | { 287 | // add to end of list 288 | while (cb->next != NULL) 289 | cb = cb->next; 290 | cb->next = new_cb; 291 | } 292 | return 0; 293 | } 294 | 295 | int callback_exists(unsigned int gpio) 296 | { 297 | struct callback *cb = callbacks; 298 | while (cb != NULL) 299 | { 300 | if (cb->gpio == gpio) 301 | return 1; 302 | cb = cb->next; 303 | } 304 | return 0; 305 | } 306 | 307 | void run_callbacks(unsigned int gpio) 308 | { 309 | struct callback *cb = callbacks; 310 | while (cb != NULL) 311 | { 312 | if (cb->gpio == gpio) 313 | cb->func(cb->gpio); 314 | cb = cb->next; 315 | } 316 | } 317 | 318 | void remove_callbacks(unsigned int gpio) 319 | { 320 | struct callback *cb = callbacks; 321 | struct callback *temp; 322 | struct callback *prev = NULL; 323 | 324 | while (cb != NULL) 325 | { 326 | if (cb->gpio == gpio) 327 | { 328 | if (prev == NULL) 329 | callbacks = cb->next; 330 | else 331 | prev->next = cb->next; 332 | temp = cb; 333 | cb = cb->next; 334 | free(temp); 335 | } 336 | else 337 | { 338 | prev = cb; 339 | cb = cb->next; 340 | } 341 | } 342 | } 343 | 344 | void *poll_thread(void *threadarg) 345 | { 346 | struct epoll_event events; 347 | char buf; 348 | struct timeval tv_timenow; 349 | unsigned long long timenow; 350 | struct gpios *g; 351 | int n; 352 | 353 | thread_running = 1; 354 | while (thread_running) 355 | { 356 | if ((n = epoll_wait(epfd_thread, &events, 1, -1)) == -1) 357 | { 358 | thread_running = 0; 359 | pthread_exit(NULL); 360 | } 361 | if (n > 0) 362 | { 363 | lseek(events.data.fd, 0, SEEK_SET); 364 | if (read(events.data.fd, &buf, 1) != 1) 365 | { 366 | thread_running = 0; 367 | pthread_exit(NULL); 368 | } 369 | g = get_gpio_from_value_fd(events.data.fd); 370 | if (g->initial_thread) 371 | { // ignore first epoll trigger 372 | g->initial_thread = 0; 373 | } 374 | else 375 | { 376 | gettimeofday(&tv_timenow, NULL); 377 | timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec; 378 | if (g->bouncetime == -666 || timenow - g->lastcall > g->bouncetime*1000 || g->lastcall == 0 || g->lastcall > timenow) 379 | { 380 | g->lastcall = timenow; 381 | event_occurred[g->gpio] = 1; 382 | run_callbacks(g->gpio); 383 | } 384 | } 385 | } 386 | } 387 | thread_running = 0; 388 | pthread_exit(NULL); 389 | } 390 | 391 | void remove_edge_detect(unsigned int gpio) 392 | { 393 | struct epoll_event ev; 394 | struct gpios *g = get_gpio(gpio); 395 | 396 | if (g == NULL) 397 | return; 398 | 399 | // delete epoll of fd 400 | 401 | ev.events = EPOLLIN | EPOLLET | EPOLLPRI; 402 | ev.data.fd = g->value_fd; 403 | epoll_ctl(epfd_thread, EPOLL_CTL_DEL, g->value_fd, &ev); 404 | 405 | // delete callbacks for gpio 406 | remove_callbacks(gpio); 407 | 408 | // btc fixme - check return result?? 409 | gpio_set_edge(gpio, NO_EDGE); 410 | g->edge = NO_EDGE; 411 | 412 | if (g->value_fd != -1) 413 | close(g->value_fd); 414 | 415 | // btc fixme - check return result?? 416 | gpio_unexport(gpio); 417 | event_occurred[gpio] = 0; 418 | 419 | delete_gpio(gpio); 420 | } 421 | 422 | int event_detected(unsigned int gpio) 423 | { 424 | if (event_occurred[gpio]) 425 | { 426 | event_occurred[gpio] = 0; 427 | return 1; 428 | } 429 | else 430 | { 431 | return 0; 432 | } 433 | } 434 | 435 | void event_cleanup(unsigned int gpio) 436 | // gpio of -666 means clean every channel used 437 | // It is ridiculous. 438 | { 439 | struct gpios *g = gpio_list; 440 | struct gpios *temp = NULL; 441 | 442 | while (g != NULL) 443 | { 444 | if ((gpio == -666) || (g->gpio == gpio)) 445 | { 446 | temp = g->next; 447 | } 448 | remove_edge_detect(g->gpio); 449 | g = temp; 450 | } 451 | if (gpio_list == NULL) 452 | { 453 | if (epfd_blocking != -1) 454 | { 455 | close(epfd_blocking); 456 | } 457 | } 458 | epfd_blocking = -1; 459 | if (epfd_thread != -1) 460 | { 461 | close(epfd_thread); 462 | } 463 | epfd_thread = -1; 464 | thread_running = 0; 465 | } 466 | 467 | void event_cleanup_all(void) 468 | { 469 | event_cleanup(-666); 470 | } 471 | 472 | int add_edge_detect(unsigned int gpio, unsigned int edge, int bouncetime) 473 | // return values: 474 | // 0 - Success 475 | // 1 - Edge detection already added 476 | // 2 - Other error 477 | { 478 | pthread_t threads; 479 | struct epoll_event ev; 480 | long t = 0; 481 | struct gpios *g; 482 | int i = -1; 483 | 484 | i = gpio_event_added(gpio); 485 | if (i == 0) // event not already added 486 | { 487 | if ((g = new_gpio(gpio)) == NULL) 488 | return 2; 489 | 490 | gpio_set_edge(gpio, edge); 491 | g->edge = edge; 492 | g->bouncetime = bouncetime; 493 | } 494 | else if (i == edge) // get existing event 495 | { 496 | g = get_gpio(gpio); 497 | if ((bouncetime != -666 && g->bouncetime != bouncetime) || // different event bouncetime used 498 | (g->thread_added)) // event already added 499 | return 1; 500 | } 501 | else 502 | { 503 | return 1; 504 | } 505 | 506 | // create epfd_thread if not already open 507 | if ((epfd_thread == -1) && ((epfd_thread = epoll_create(1)) == -1)) 508 | return 2; 509 | 510 | // add to epoll fd 511 | ev.events = EPOLLIN | EPOLLET | EPOLLPRI; 512 | ev.data.fd = g->value_fd; 513 | if (epoll_ctl(epfd_thread, EPOLL_CTL_ADD, g->value_fd, &ev) == -1) 514 | { 515 | remove_edge_detect(gpio); 516 | return 2; 517 | } 518 | g->thread_added = 1; 519 | 520 | // start poll thread if it is not already running 521 | if (!thread_running) 522 | { 523 | if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0) 524 | { 525 | remove_edge_detect(gpio); 526 | return 2; 527 | } 528 | } 529 | return 0; 530 | } 531 | 532 | int blocking_wait_for_edge(unsigned int gpio, unsigned int edge, int bouncetime) 533 | { 534 | int n, ed; 535 | struct epoll_event events, ev; 536 | char buf; 537 | struct gpios *g = NULL; 538 | struct timeval tv_timenow; 539 | unsigned long long timenow; 540 | int finished = 0; 541 | int initial_edge = 1; 542 | 543 | if (callback_exists(gpio)) 544 | return 1; 545 | 546 | // add gpio if it has not been added already 547 | ed = gpio_event_added(gpio); 548 | if (ed == edge) // get existing record 549 | { 550 | g = get_gpio(gpio); 551 | if (g->bouncetime != -666 && g->bouncetime != bouncetime) 552 | { 553 | return 1; 554 | } 555 | } 556 | else if (ed == NO_EDGE)// not found so add event 557 | { 558 | if ((g = new_gpio(gpio)) == NULL) 559 | return 2; 560 | gpio_set_edge(gpio, edge); 561 | g->edge = edge; 562 | g->bouncetime = bouncetime; 563 | } 564 | else // ed != edge - event for a different edge 565 | { 566 | g = get_gpio(gpio); 567 | gpio_set_edge(gpio, edge); 568 | g->edge = edge; 569 | g->bouncetime = bouncetime; 570 | g->initial_wait = 1; 571 | } 572 | 573 | // create epfd_blocking if not already open 574 | if ((epfd_blocking == -1) && ((epfd_blocking = epoll_create(1)) == -1)) 575 | { 576 | return 2; 577 | } 578 | 579 | // add to epoll fd 580 | ev.events = EPOLLIN | EPOLLET | EPOLLPRI; 581 | ev.data.fd = g->value_fd; 582 | if (epoll_ctl(epfd_blocking, EPOLL_CTL_ADD, g->value_fd, &ev) == -1) 583 | { 584 | return 2; 585 | } 586 | 587 | // wait for edge 588 | while (!finished) 589 | { 590 | if ((n = epoll_wait(epfd_blocking, &events, 1, -1)) == -1) 591 | { 592 | epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev); 593 | return 2; 594 | } 595 | if (initial_edge)// first time triggers with current state, so ignore 596 | { 597 | initial_edge = 0; 598 | } 599 | else 600 | { 601 | gettimeofday(&tv_timenow, NULL); 602 | timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec; 603 | if (g->bouncetime == -666 || timenow - g->lastcall > g->bouncetime*1000 || g->lastcall == 0 || g->lastcall > timenow) 604 | { 605 | g->lastcall = timenow; 606 | finished = 1; 607 | } 608 | } 609 | } 610 | 611 | // check event was valid 612 | if (n > 0) 613 | { 614 | lseek(events.data.fd, 0, SEEK_SET); 615 | if ((read(events.data.fd, &buf, 1) != 1) || (events.data.fd != g->value_fd)) 616 | { 617 | epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev); 618 | return 2; 619 | } 620 | } 621 | 622 | epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev); 623 | return 0; 624 | } 625 | -------------------------------------------------------------------------------- /source/event_gpio.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013-2014 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #define NO_EDGE 0 24 | #define RISING_EDGE 1 25 | #define FALLING_EDGE 2 26 | #define BOTH_EDGE 3 27 | 28 | int add_edge_detect(unsigned int gpio, unsigned int edge, int bouncetime); 29 | void remove_edge_detect(unsigned int gpio); 30 | int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio)); 31 | int event_detected(unsigned int gpio); 32 | int gpio_event_added(unsigned int gpio); 33 | int event_initialise(void); 34 | void event_cleanup(unsigned int gpio); 35 | void event_cleanup_all(void); 36 | int blocking_wait_for_edge(unsigned int gpio, unsigned int edge, int bouncetime); 37 | -------------------------------------------------------------------------------- /source/py_gpio_RPi.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012-2015 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "Python.h" 24 | #include "c_gpio.h" 25 | #include "event_gpio.h" 26 | #include "py_pwm.h" 27 | #include "cpuinfo.h" 28 | #include "constants.h" 29 | #include "common.h" 30 | 31 | static PyObject *asuspi_revision; // deprecated 32 | static PyObject *board_info; 33 | static int gpio_warnings = 1; 34 | 35 | struct py_callback 36 | { 37 | unsigned int gpio; 38 | PyObject *py_cb; 39 | struct py_callback *next; 40 | }; 41 | static struct py_callback *py_callbacks = NULL; 42 | 43 | static int mmap_gpio_mem(void) 44 | { 45 | int result; 46 | 47 | if (module_setup) 48 | return 0; 49 | 50 | result = setup(); 51 | if (result == SETUP_DEVMEM_FAIL) 52 | { 53 | PyErr_SetString(PyExc_RuntimeError, "No access to /dev/mem. Try running as root!"); 54 | return 1; 55 | } 56 | else if (result == SETUP_MALLOC_FAIL) 57 | { 58 | PyErr_NoMemory(); 59 | return 2; 60 | } 61 | else if (result == SETUP_MMAP_FAIL) 62 | { 63 | PyErr_SetString(PyExc_RuntimeError, "Mmap of GPIO registers failed"); 64 | return 3; 65 | } 66 | else 67 | { // result == SETUP_OK 68 | module_setup = 1; 69 | return 0; 70 | } 71 | } 72 | 73 | // python function cleanup(channel=None) 74 | static PyObject *py_cleanup(PyObject *self, PyObject *args, PyObject *kwargs) 75 | { 76 | int i; 77 | int chancount = -666; 78 | int found = 0; 79 | int channel = -666; 80 | unsigned int gpio; 81 | PyObject *chanlist = NULL; 82 | PyObject *chantuple = NULL; 83 | PyObject *tempobj; 84 | static char *kwlist[] = {"channel", NULL}; 85 | 86 | void cleanup_one(void) 87 | { 88 | // clean up any /sys/class exports 89 | event_cleanup(gpio); 90 | 91 | // set everything back to input 92 | if (gpio_direction[gpio] != -1) 93 | { 94 | setup_gpio(gpio, INPUT, PUD_OFF); 95 | gpio_direction[gpio] = -1; 96 | found = 1; 97 | } 98 | } 99 | 100 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &chanlist)) 101 | return NULL; 102 | 103 | if (chanlist == NULL) // channel kwarg not set 104 | { 105 | // do nothing 106 | #if PY_MAJOR_VERSION > 2 107 | } 108 | else if (PyLong_Check(chanlist)) 109 | { 110 | channel = (int)PyLong_AsLong(chanlist); 111 | #else 112 | } 113 | else if (PyInt_Check(chanlist)) 114 | { 115 | channel = (int)PyInt_AsLong(chanlist); 116 | #endif 117 | if (PyErr_Occurred()) 118 | return NULL; 119 | chanlist = NULL; 120 | } 121 | else if (PyList_Check(chanlist)) 122 | { 123 | chancount = PyList_Size(chanlist); 124 | } 125 | else if (PyTuple_Check(chanlist)) 126 | { 127 | chantuple = chanlist; 128 | chanlist = NULL; 129 | chancount = PyTuple_Size(chantuple); 130 | } 131 | else 132 | { 133 | // raise exception 134 | PyErr_SetString(PyExc_ValueError, "Channel must be an integer or list/tuple of integers"); 135 | return NULL; 136 | } 137 | 138 | if (module_setup && !setup_error) 139 | { 140 | if (channel == -666 && chancount == -666) // channel not set - cleanup everything 141 | { 142 | // clean up any /sys/class exports 143 | event_cleanup_all(); 144 | 145 | // set everything back to input 146 | for (i=0; i<54; i++) 147 | { 148 | if (gpio_direction[i] != -1) 149 | { 150 | setup_gpio(i, INPUT, PUD_OFF); 151 | gpio_direction[i] = -1; 152 | found = 1; 153 | } 154 | } 155 | gpio_mode = MODE_UNKNOWN; 156 | } 157 | else if (channel != -666)// channel was an int indicating single channel 158 | { 159 | if (get_gpio_number(channel, &gpio)) 160 | return NULL; 161 | cleanup_one(); 162 | } 163 | else // channel was a list/tuple 164 | { 165 | for (i=0; i 2 183 | if (PyLong_Check(tempobj)) 184 | { 185 | channel = (int)PyLong_AsLong(tempobj); 186 | #else 187 | if (PyInt_Check(tempobj)) 188 | { 189 | channel = (int)PyInt_AsLong(tempobj); 190 | #endif 191 | if (PyErr_Occurred()) 192 | return NULL; 193 | } 194 | else 195 | { 196 | PyErr_SetString(PyExc_ValueError, "Channel must be an integer"); 197 | return NULL; 198 | } 199 | 200 | if (get_gpio_number(channel, &gpio)) 201 | return NULL; 202 | cleanup_one(); 203 | } 204 | } 205 | } 206 | 207 | // check if any channels set up - if not warn about misuse of GPIO.cleanup() 208 | if (!found && gpio_warnings) 209 | { 210 | PyErr_WarnEx(NULL, "No channels have been set up yet - nothing to clean up! Try cleaning up at the end of your program instead!", 1); 211 | } 212 | Py_RETURN_NONE; 213 | } 214 | 215 | // python function setup(channel(s), direction, pull_up_down=PUD_OFF, initial=None) 216 | static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwargs) 217 | { 218 | unsigned int gpio; 219 | int channel = -1; 220 | int direction; 221 | int i, chancount,setupflag; 222 | PyObject *chanlist = NULL; 223 | PyObject *chantuple = NULL; 224 | PyObject *tempobj; 225 | int pud = PUD_OFF + PY_PUD_CONST_OFFSET; 226 | int initial = -1; 227 | static char *kwlist[] = {"channel", "direction", "pull_up_down", "initial", NULL}; 228 | int func; 229 | 230 | int setup_one(void) 231 | { 232 | 233 | if (get_gpio_number(channel, &gpio)) 234 | return 0; 235 | 236 | func = gpio_function(gpio); 237 | if (gpio_warnings && // warnings enabled and 238 | ((func != GPIO) || // (already one of the alt functions or 239 | (gpio_direction[gpio] == -1))) // already an output not set from this program) 240 | { 241 | printf("This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings."); 242 | } 243 | 244 | if (direction == OUTPUT && (initial == LOW || initial == HIGH)) 245 | { 246 | printf("direction == OUTPUT"); 247 | output_gpio(gpio, initial); 248 | } 249 | 250 | setupflag=setup_gpio(gpio, direction, pud); 251 | if(setupflag==0) 252 | { 253 | PyErr_SetString(PyExc_RuntimeError, "This gpio is set to other function!"); 254 | return (int)NULL; 255 | } 256 | gpio_direction[gpio] = direction; 257 | return 1; 258 | } 259 | 260 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii", kwlist, &chanlist, &direction, &pud, &initial)) 261 | return NULL; 262 | 263 | #if PY_MAJOR_VERSION > 2 264 | if (PyLong_Check(chanlist)) 265 | { 266 | channel = (int)PyLong_AsLong(chanlist); 267 | #else 268 | if (PyInt_Check(chanlist)) 269 | { 270 | channel = (int)PyInt_AsLong(chanlist); 271 | #endif 272 | if (PyErr_Occurred()) 273 | return NULL; 274 | chanlist = NULL; 275 | } 276 | else if PyList_Check(chanlist) 277 | { 278 | // do nothing 279 | } 280 | else if PyTuple_Check(chanlist) 281 | { 282 | chantuple = chanlist; 283 | chanlist = NULL; 284 | } 285 | else 286 | { 287 | // raise exception 288 | PyErr_SetString(PyExc_ValueError, "Channel must be an integer or list/tuple of integers"); 289 | return NULL; 290 | } 291 | 292 | // check module has been imported cleanly 293 | if (setup_error) 294 | { 295 | PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!"); 296 | return NULL; 297 | } 298 | 299 | if (mmap_gpio_mem()) 300 | return NULL; 301 | 302 | if (direction != INPUT && direction != OUTPUT) 303 | { 304 | PyErr_SetString(PyExc_ValueError, "An invalid direction was passed to setup()"); 305 | return 0; 306 | } 307 | 308 | if (direction == OUTPUT) 309 | pud = PUD_OFF + PY_PUD_CONST_OFFSET; 310 | 311 | pud -= PY_PUD_CONST_OFFSET; 312 | if (pud != PUD_OFF && pud != PUD_DOWN && pud != PUD_UP) 313 | { 314 | PyErr_SetString(PyExc_ValueError, "Invalid value for pull_up_down - should be either PUD_OFF, PUD_UP or PUD_DOWN"); 315 | return NULL; 316 | } 317 | 318 | if (chanlist) 319 | { 320 | chancount = PyList_Size(chanlist); 321 | } 322 | else if (chantuple) 323 | { 324 | chancount = PyTuple_Size(chantuple); 325 | } 326 | else 327 | { 328 | if (!setup_one()) 329 | return NULL; 330 | Py_RETURN_NONE; 331 | } 332 | 333 | for (i=0; i 2 351 | if (PyLong_Check(tempobj)) 352 | { 353 | channel = (int)PyLong_AsLong(tempobj); 354 | #else 355 | if (PyInt_Check(tempobj)) 356 | { 357 | channel = (int)PyInt_AsLong(tempobj); 358 | #endif 359 | if (PyErr_Occurred()) 360 | return NULL; 361 | } 362 | else 363 | { 364 | PyErr_SetString(PyExc_ValueError, "Channel must be an integer"); 365 | return NULL; 366 | } 367 | 368 | if (!setup_one()) 369 | return NULL; 370 | } 371 | 372 | Py_RETURN_NONE; 373 | } 374 | 375 | // python function output(channel(s), value(s)) 376 | static PyObject *py_output_gpio(PyObject *self, PyObject *args) 377 | { 378 | unsigned int gpio; 379 | int channel = -1; 380 | int value = -1; 381 | int i; 382 | PyObject *chanlist = NULL; 383 | PyObject *valuelist = NULL; 384 | PyObject *chantuple = NULL; 385 | PyObject *valuetuple = NULL; 386 | PyObject *tempobj = NULL; 387 | int chancount = -1; 388 | int valuecount = -1; 389 | 390 | int output(void) 391 | { 392 | if (get_gpio_number(channel, &gpio)) 393 | return 0; 394 | 395 | if (gpio_direction[gpio] != OUTPUT) 396 | { 397 | PyErr_SetString(PyExc_RuntimeError, "The GPIO channel has not been set up as an OUTPUT"); 398 | return 0; 399 | } 400 | 401 | if (check_gpio_priv()) 402 | return 0; 403 | output_gpio(gpio, value); 404 | return 1; 405 | } 406 | 407 | if (!PyArg_ParseTuple(args, "OO", &chanlist, &valuelist)) 408 | return NULL; 409 | 410 | #if PY_MAJOR_VERSION >= 3 411 | if (PyLong_Check(chanlist)) 412 | { 413 | channel = (int)PyLong_AsLong(chanlist); 414 | #else 415 | if (PyInt_Check(chanlist)) 416 | { 417 | channel = (int)PyInt_AsLong(chanlist); 418 | #endif 419 | if (PyErr_Occurred()) 420 | return NULL; 421 | chanlist = NULL; 422 | } 423 | else if (PyList_Check(chanlist)) 424 | { 425 | // do nothing 426 | } 427 | else if (PyTuple_Check(chanlist)) 428 | { 429 | chantuple = chanlist; 430 | chanlist = NULL; 431 | } 432 | else 433 | { 434 | PyErr_SetString(PyExc_ValueError, "Channel must be an integer or list/tuple of integers"); 435 | return NULL; 436 | } 437 | 438 | #if PY_MAJOR_VERSION >= 3 439 | if (PyLong_Check(valuelist)) 440 | { 441 | value = (int)PyLong_AsLong(valuelist); 442 | #else 443 | if (PyInt_Check(valuelist)) 444 | { 445 | value = (int)PyInt_AsLong(valuelist); 446 | #endif 447 | if (PyErr_Occurred()) 448 | return NULL; 449 | valuelist = NULL; 450 | } 451 | else if (PyList_Check(valuelist)) 452 | { 453 | // do nothing 454 | } 455 | else if (PyTuple_Check(valuelist)) 456 | { 457 | valuetuple = valuelist; 458 | valuelist = NULL; 459 | } 460 | else 461 | { 462 | PyErr_SetString(PyExc_ValueError, "Value must be an integer/boolean or a list/tuple of integers/booleans"); 463 | return NULL; 464 | } 465 | 466 | if (chanlist) 467 | chancount = PyList_Size(chanlist); 468 | if (chantuple) 469 | chancount = PyTuple_Size(chantuple); 470 | if (valuelist) 471 | valuecount = PyList_Size(valuelist); 472 | if (valuetuple) 473 | valuecount = PyTuple_Size(valuetuple); 474 | if ((chancount != -1 && chancount != valuecount && valuecount != -1) || (chancount == -1 && valuecount != -1)) 475 | { 476 | PyErr_SetString(PyExc_RuntimeError, "Number of channels != number of values"); 477 | return NULL; 478 | } 479 | 480 | if (chancount == -1) 481 | { 482 | if (!output()) 483 | return NULL; 484 | Py_RETURN_NONE; 485 | } 486 | 487 | for (i=0; i= 3 506 | if (PyLong_Check(tempobj)) 507 | { 508 | channel = (int)PyLong_AsLong(tempobj); 509 | #else 510 | if (PyInt_Check(tempobj)) 511 | { 512 | channel = (int)PyInt_AsLong(tempobj); 513 | #endif 514 | if (PyErr_Occurred()) 515 | return NULL; 516 | } 517 | else 518 | { 519 | PyErr_SetString(PyExc_ValueError, "Channel must be an integer"); 520 | return NULL; 521 | } 522 | 523 | // get value 524 | if (valuecount > 0) 525 | { 526 | if (valuelist) 527 | { 528 | if ((tempobj = PyList_GetItem(valuelist, i)) == NULL) 529 | { 530 | return NULL; 531 | } 532 | } 533 | else 534 | { // assume valuetuple 535 | if ((tempobj = PyTuple_GetItem(valuetuple, i)) == NULL) 536 | { 537 | return NULL; 538 | } 539 | } 540 | #if PY_MAJOR_VERSION >= 3 541 | if (PyLong_Check(tempobj)) 542 | { 543 | value = (int)PyLong_AsLong(tempobj); 544 | #else 545 | if (PyInt_Check(tempobj)) 546 | { 547 | value = (int)PyInt_AsLong(tempobj); 548 | #endif 549 | if (PyErr_Occurred()) 550 | return NULL; 551 | } 552 | else 553 | { 554 | PyErr_SetString(PyExc_ValueError, "Value must be an integer or boolean"); 555 | return NULL; 556 | } 557 | } 558 | if (!output()) 559 | return NULL; 560 | } 561 | 562 | Py_RETURN_NONE; 563 | } 564 | 565 | // python function value = input(channel) 566 | static PyObject *py_input_gpio(PyObject *self, PyObject *args) 567 | { 568 | unsigned int gpio; 569 | int channel; 570 | PyObject *value; 571 | 572 | if (!PyArg_ParseTuple(args, "i", &channel)) 573 | return NULL; 574 | 575 | if (get_gpio_number(channel, &gpio)) 576 | return NULL; 577 | 578 | // check channel is set up as an input or output 579 | if (gpio_direction[gpio] != INPUT && gpio_direction[gpio] != OUTPUT) 580 | { 581 | PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel first"); 582 | return NULL; 583 | } 584 | 585 | if (check_gpio_priv()) 586 | return NULL; 587 | 588 | if (input_gpio(gpio)) 589 | { 590 | value = Py_BuildValue("i", HIGH); 591 | } 592 | else 593 | { 594 | value = Py_BuildValue("i", LOW); 595 | } 596 | return value; 597 | } 598 | 599 | // python function setmode(mode) 600 | static PyObject *py_setmode(PyObject *self, PyObject *args) 601 | { 602 | int new_mode; 603 | 604 | if (!PyArg_ParseTuple(args, "i", &new_mode)) 605 | return NULL; 606 | 607 | if (gpio_mode != MODE_UNKNOWN && new_mode != gpio_mode) 608 | { 609 | PyErr_SetString(PyExc_ValueError, "A different mode has already been set!"); 610 | return NULL; 611 | } 612 | 613 | if (setup_error) 614 | { 615 | PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!"); 616 | return NULL; 617 | } 618 | 619 | gpio_mode = new_mode; 620 | 621 | if (gpio_mode != BOARD && gpio_mode != RK && gpio_mode != ASUS && gpio_mode != BCM) 622 | { 623 | PyErr_SetString(PyExc_ValueError, "An invalid mode was passed to setmode()"); 624 | return NULL; 625 | } 626 | Py_RETURN_NONE; 627 | } 628 | 629 | // python function getmode() 630 | static PyObject *py_getmode(PyObject *self, PyObject *args) 631 | { 632 | PyObject *value; 633 | 634 | if (setup_error) 635 | { 636 | PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!"); 637 | return NULL; 638 | } 639 | 640 | value = Py_BuildValue("i", gpio_mode); 641 | return value; 642 | } 643 | 644 | static unsigned int chan_from_gpio(unsigned int gpio) 645 | { 646 | int chan; 647 | int chans; 648 | 649 | if (gpio_mode == RK || gpio_mode == ASUS) 650 | return gpio; 651 | if (asuspiinfo.p1_revision == 0) // not applicable for compute module 652 | return -1; 653 | else if (asuspiinfo.p1_revision == 1 || asuspiinfo.p1_revision == 2) 654 | chans = 26; 655 | else 656 | chans = 40; 657 | for (chan=1; chan<=chans; chan++) 658 | if (*(*pin_to_gpio+chan) == gpio) 659 | return chan; 660 | return -1; 661 | } 662 | 663 | static void run_py_callbacks(unsigned int gpio) 664 | { 665 | PyObject *result; 666 | PyGILState_STATE gstate; 667 | struct py_callback *cb = py_callbacks; 668 | 669 | while (cb != NULL) 670 | { 671 | if (cb->gpio == gpio) 672 | { 673 | // run callback 674 | gstate = PyGILState_Ensure(); 675 | result = PyObject_CallFunction(cb->py_cb, "i", chan_from_gpio(gpio)); 676 | if (result == NULL && PyErr_Occurred()) 677 | { 678 | PyErr_Print(); 679 | PyErr_Clear(); 680 | } 681 | Py_XDECREF(result); 682 | PyGILState_Release(gstate); 683 | } 684 | cb = cb->next; 685 | } 686 | } 687 | 688 | static int add_py_callback(unsigned int gpio, PyObject *cb_func) 689 | { 690 | struct py_callback *new_py_cb; 691 | struct py_callback *cb = py_callbacks; 692 | 693 | // add callback to py_callbacks list 694 | new_py_cb = malloc(sizeof(struct py_callback)); 695 | if (new_py_cb == 0) 696 | { 697 | PyErr_NoMemory(); 698 | return -1; 699 | } 700 | new_py_cb->py_cb = cb_func; 701 | Py_XINCREF(cb_func); // Add a reference to new callback 702 | new_py_cb->gpio = gpio; 703 | new_py_cb->next = NULL; 704 | if (py_callbacks == NULL) 705 | { 706 | py_callbacks = new_py_cb; 707 | } 708 | else 709 | { 710 | // add to end of list 711 | while (cb->next != NULL) 712 | cb = cb->next; 713 | cb->next = new_py_cb; 714 | } 715 | add_edge_callback(gpio, run_py_callbacks); 716 | return 0; 717 | } 718 | 719 | // python function add_event_callback(gpio, callback) 720 | static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject *kwargs) 721 | { 722 | unsigned int gpio; 723 | int channel; 724 | PyObject *cb_func; 725 | char *kwlist[] = {"gpio", "callback", NULL}; 726 | 727 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iO|i", kwlist, &channel, &cb_func)) 728 | return NULL; 729 | 730 | if (!PyCallable_Check(cb_func)) 731 | { 732 | PyErr_SetString(PyExc_TypeError, "Parameter must be callable"); 733 | return NULL; 734 | } 735 | 736 | if (get_gpio_number(channel, &gpio)) 737 | return NULL; 738 | 739 | // check channel is set up as an input 740 | if (gpio_direction[gpio] != INPUT) 741 | { 742 | PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first"); 743 | return NULL; 744 | } 745 | 746 | if (!gpio_event_added(gpio)) 747 | { 748 | PyErr_SetString(PyExc_RuntimeError, "Add event detection using add_event_detect first before adding a callback"); 749 | return NULL; 750 | } 751 | 752 | if (add_py_callback(gpio, cb_func) != 0) 753 | return NULL; 754 | 755 | Py_RETURN_NONE; 756 | } 757 | 758 | // python function add_event_detect(gpio, edge, callback=None, bouncetime=None) 759 | static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *kwargs) 760 | { 761 | unsigned int gpio; 762 | int channel, edge, result; 763 | int bouncetime = -666; 764 | PyObject *cb_func = NULL; 765 | char *kwlist[] = {"gpio", "edge", "callback", "bouncetime", NULL}; 766 | 767 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|Oi", kwlist, &channel, &edge, &cb_func, &bouncetime)) 768 | return NULL; 769 | 770 | if (cb_func != NULL && !PyCallable_Check(cb_func)) 771 | { 772 | PyErr_SetString(PyExc_TypeError, "Parameter must be callable"); 773 | return NULL; 774 | } 775 | 776 | if (get_gpio_number(channel, &gpio)) 777 | return NULL; 778 | 779 | // check channel is set up as an input 780 | if (gpio_direction[gpio] != INPUT) 781 | { 782 | PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first"); 783 | return NULL; 784 | } 785 | 786 | // is edge valid value 787 | edge -= PY_EVENT_CONST_OFFSET; 788 | if (edge != RISING_EDGE && edge != FALLING_EDGE && edge != BOTH_EDGE) 789 | { 790 | PyErr_SetString(PyExc_ValueError, "The edge must be set to RISING, FALLING or BOTH"); 791 | return NULL; 792 | } 793 | 794 | if (bouncetime <= 0 && bouncetime != -666) 795 | { 796 | PyErr_SetString(PyExc_ValueError, "Bouncetime must be greater than 0"); 797 | return NULL; 798 | } 799 | 800 | if (check_gpio_priv()) 801 | return NULL; 802 | 803 | if ((result = add_edge_detect(gpio, edge, bouncetime)) != 0) // starts a thread 804 | { 805 | if (result == 1) 806 | { 807 | PyErr_SetString(PyExc_RuntimeError, "Conflicting edge detection already enabled for this GPIO channel"); 808 | return NULL; 809 | } 810 | else 811 | { 812 | PyErr_SetString(PyExc_RuntimeError, "Failed to add edge detection"); 813 | return NULL; 814 | } 815 | } 816 | 817 | if (cb_func != NULL) 818 | if (add_py_callback(gpio, cb_func) != 0) 819 | return NULL; 820 | 821 | Py_RETURN_NONE; 822 | } 823 | 824 | // python function remove_event_detect(gpio) 825 | static PyObject *py_remove_event_detect(PyObject *self, PyObject *args) 826 | { 827 | unsigned int gpio; 828 | int channel; 829 | struct py_callback *cb = py_callbacks; 830 | struct py_callback *temp; 831 | struct py_callback *prev = NULL; 832 | 833 | if (!PyArg_ParseTuple(args, "i", &channel)) 834 | return NULL; 835 | 836 | if (get_gpio_number(channel, &gpio)) 837 | return NULL; 838 | 839 | // remove all python callbacks for gpio 840 | while (cb != NULL) 841 | { 842 | if (cb->gpio == gpio) 843 | { 844 | Py_XDECREF(cb->py_cb); 845 | if (prev == NULL) 846 | py_callbacks = cb->next; 847 | else 848 | prev->next = cb->next; 849 | temp = cb; 850 | cb = cb->next; 851 | free(temp); 852 | } 853 | else 854 | { 855 | prev = cb; 856 | cb = cb->next; 857 | } 858 | } 859 | 860 | if (check_gpio_priv()) 861 | return NULL; 862 | 863 | remove_edge_detect(gpio); 864 | 865 | Py_RETURN_NONE; 866 | } 867 | 868 | // python function value = event_detected(channel) 869 | static PyObject *py_event_detected(PyObject *self, PyObject *args) 870 | { 871 | unsigned int gpio; 872 | int channel; 873 | 874 | if (!PyArg_ParseTuple(args, "i", &channel)) 875 | return NULL; 876 | 877 | if (get_gpio_number(channel, &gpio)) 878 | return NULL; 879 | 880 | if (event_detected(gpio)) 881 | Py_RETURN_TRUE; 882 | else 883 | Py_RETURN_FALSE; 884 | } 885 | 886 | // python function wait_for_edge(channel, edge, bouncetime=None) 887 | static PyObject *py_wait_for_edge(PyObject *self, PyObject *args, PyObject *kwargs) 888 | { 889 | unsigned int gpio; 890 | int channel, edge, result; 891 | int bouncetime = -666; // None 892 | 893 | static char *kwlist[] = {"channel", "edge", "bouncetime", NULL}; 894 | 895 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|i", kwlist, &channel, &edge, &bouncetime)) 896 | return NULL; 897 | 898 | if (get_gpio_number(channel, &gpio)) 899 | return NULL; 900 | 901 | // check channel is setup as an input 902 | if (gpio_direction[gpio] != INPUT) 903 | { 904 | PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first"); 905 | return NULL; 906 | } 907 | 908 | // is edge a valid value? 909 | edge -= PY_EVENT_CONST_OFFSET; 910 | if (edge != RISING_EDGE && edge != FALLING_EDGE && edge != BOTH_EDGE) 911 | { 912 | PyErr_SetString(PyExc_ValueError, "The edge must be set to RISING, FALLING or BOTH"); 913 | return NULL; 914 | } 915 | 916 | if (bouncetime <= 0 && bouncetime != -666) 917 | { 918 | PyErr_SetString(PyExc_ValueError, "Bouncetime must be greater than 0"); 919 | return NULL; 920 | } 921 | 922 | if (check_gpio_priv()) 923 | return NULL; 924 | 925 | Py_BEGIN_ALLOW_THREADS // disable GIL 926 | result = blocking_wait_for_edge(gpio, edge, bouncetime); 927 | Py_END_ALLOW_THREADS // enable GIL 928 | 929 | if (result == 0) 930 | { 931 | Py_INCREF(Py_None); 932 | return Py_None; 933 | } 934 | else if (result == 1) 935 | { 936 | PyErr_SetString(PyExc_RuntimeError, "Conflicting edge detection events already exist for this GPIO channel"); 937 | return NULL; 938 | } 939 | else 940 | { 941 | PyErr_SetString(PyExc_RuntimeError, "Error waiting for edge"); 942 | return NULL; 943 | } 944 | Py_RETURN_NONE; 945 | } 946 | 947 | // python function value = gpio_function(channel) 948 | static PyObject *py_gpio_function(PyObject *self, PyObject *args) 949 | { 950 | unsigned int gpio; 951 | int channel; 952 | int f; 953 | PyObject *func; 954 | 955 | if (!PyArg_ParseTuple(args, "i", &channel)) 956 | return NULL; 957 | 958 | if (get_gpio_number(channel, &gpio)) 959 | return NULL; 960 | 961 | if (mmap_gpio_mem()) 962 | return NULL; 963 | 964 | f = gpio_function(gpio); 965 | func = Py_BuildValue("i", f); 966 | return func; 967 | } 968 | 969 | // python function setwarnings(state) 970 | static PyObject *py_setwarnings(PyObject *self, PyObject *args) 971 | { 972 | if (!PyArg_ParseTuple(args, "i", &gpio_warnings)) 973 | return NULL; 974 | 975 | if (setup_error) 976 | { 977 | PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!"); 978 | return NULL; 979 | } 980 | 981 | Py_RETURN_NONE; 982 | } 983 | 984 | static const char moduledocstring[] = "GPIO functionality of a ASUS Pi using Python"; 985 | 986 | PyMethodDef asuspi_gpio_methods[] = { 987 | {"setup", (PyCFunction)py_setup_channel, METH_VARARGS | METH_KEYWORDS, "Set up a GPIO channel or list of channels with a direction and (optional) pull/up down control\nchannel - either board pin number ,RK number or ASUS number depending on which mode is set.\ndirection - IN or OUT\n[pull_up_down] - PUD_OFF (default), PUD_UP or PUD_DOWN\n[initial] - Initial value for an output channel"}, 988 | {"cleanup", (PyCFunction)py_cleanup, METH_VARARGS | METH_KEYWORDS, "Clean up by resetting all GPIO channels that have been used by this program to INPUT with no pullup/pulldown and no event detection\n[channel] - individual channel or list/tuple of channels to clean up. Default - clean every channel that has been used."}, 989 | {"output", py_output_gpio, METH_VARARGS, "Output to a GPIO channel or list of channels\nchannel - either board pin number ,RK number or ASUS number depending on which mode is set.\nvalue - 0/1 or False/True or LOW/HIGH"}, 990 | {"input", py_input_gpio, METH_VARARGS, "Input from a GPIO channel. Returns HIGH=1=True or LOW=0=False\nchannel - either board pin number ,RK number or ASUS number depending on which mode is set."}, 991 | {"setmode", py_setmode, METH_VARARGS, "Set up numbering mode to use for channels.\nBOARD - Use ASUS Pi board numbers\nRK - Use Broadcom GPIO 00..nn numbers"}, 992 | {"getmode", py_getmode, METH_VARARGS, "Get numbering mode used for channel numbers.\nReturns BOARD, RK, ASUS or UNKNOWN"}, 993 | {"add_event_detect", (PyCFunction)py_add_event_detect, METH_VARARGS | METH_KEYWORDS, "Enable edge detection events for a particular GPIO channel.\nchannel - either board pin number ,RK number or ASUS number depending on which mode is set.\nedge - RISING, FALLING or BOTH\n[callback] - A callback function for the event (optional)\n[bouncetime] - Switch bounce timeout in ms for callback"}, 994 | {"remove_event_detect", py_remove_event_detect, METH_VARARGS, "Remove edge detection for a particular GPIO channel\nchannel - either board pin number ,RK number or ASUS number depending on which mode is set."}, 995 | {"event_detected", py_event_detected, METH_VARARGS, "Returns True if an edge has occured on a given GPIO. You need to enable edge detection using add_event_detect() first.\nchannel - either board pin number ,RK number and ASUS number depending on which mode is set."}, 996 | {"add_event_callback", (PyCFunction)py_add_event_callback, METH_VARARGS | METH_KEYWORDS, "Add a callback for an event already defined using add_event_detect()\nchannel - either board pin number ,RK number or ASUS number depending on which mode is set.\ncallback - a callback function"}, 997 | {"wait_for_edge", (PyCFunction)py_wait_for_edge, METH_VARARGS | METH_KEYWORDS, "Wait for an edge.\nchannel - either board pin number ,RK number or ASUS number depending on which mode is set.\nedge - RISING, FALLING or BOTH\n[bouncetime] - time allowed between calls to allow for switchbounce"}, 998 | {"gpio_function", py_gpio_function, METH_VARARGS, "Return the current GPIO function (IN, OUT, PWM, SERIAL, I2C, SPI)\nchannel - either board pin number ,RK number or ASUS number depending on which mode is set."}, 999 | {"setwarnings", py_setwarnings, METH_VARARGS, "Enable or disable warning messages"}, 1000 | {NULL, NULL, 0, NULL} 1001 | }; 1002 | 1003 | #if PY_MAJOR_VERSION > 2 1004 | static struct PyModuleDef asuspigpiomodule = { 1005 | PyModuleDef_HEAD_INIT, 1006 | "RPi.GPIO", // name of module 1007 | moduledocstring, // module documentation, may be NULL 1008 | -1, // size of per-interpreter state of the module, or -1 if the module keeps state in global variables. 1009 | asuspi_gpio_methods 1010 | }; 1011 | #endif 1012 | 1013 | #if PY_MAJOR_VERSION > 2 1014 | PyMODINIT_FUNC PyInit_GPIO(void) 1015 | #else 1016 | PyMODINIT_FUNC initGPIO(void) 1017 | #endif 1018 | { 1019 | int i; 1020 | PyObject *module = NULL; 1021 | 1022 | #if PY_MAJOR_VERSION > 2 1023 | if ((module = PyModule_Create(&asuspigpiomodule)) == NULL) 1024 | return NULL; 1025 | #else 1026 | if ((module = Py_InitModule3("RPi.GPIO", asuspi_gpio_methods, moduledocstring)) == NULL) 1027 | return; 1028 | #endif 1029 | 1030 | define_constants(module); 1031 | 1032 | for (i=0; i<200; i++) 1033 | gpio_direction[i] = -1; 1034 | 1035 | // detect board revision and set up accordingly 1036 | 1037 | if (get_asuspi_info(&asuspiinfo)) 1038 | { 1039 | PyErr_SetString(PyExc_RuntimeError, "This module can only be run on a ASUS Pi!"); 1040 | setup_error = 1; 1041 | #if PY_MAJOR_VERSION > 2 1042 | return NULL; 1043 | #else 1044 | return; 1045 | #endif 1046 | } 1047 | /**/ 1048 | board_info = Py_BuildValue("{sissssssssss}", 1049 | "P1_REVISION",asuspiinfo.p1_revision, 1050 | "REVISION",&asuspiinfo.revision, 1051 | "TYPE",asuspiinfo.type, 1052 | "MANUFACTURER",asuspiinfo.manufacturer, 1053 | "PROCESSOR",asuspiinfo.processor, 1054 | "RAM",asuspiinfo.ram); 1055 | PyModule_AddObject(module, "RPI_INFO", board_info); 1056 | 1057 | 1058 | pin_to_gpio = &pin_to_gpio_rev; 1059 | 1060 | 1061 | asuspi_revision = Py_BuildValue("i", asuspiinfo.p1_revision); // deprecated 1062 | PyModule_AddObject(module, "RPI_REVISION", asuspi_revision); // deprecated 1063 | 1064 | // Add PWM class 1065 | if (PWM_init_PWMType() == NULL) 1066 | #if PY_MAJOR_VERSION > 2 1067 | return NULL; 1068 | #else 1069 | return; 1070 | #endif 1071 | Py_INCREF(&PWMType); 1072 | PyModule_AddObject(module, "PWM", (PyObject*)&PWMType); 1073 | if (!PyEval_ThreadsInitialized()) 1074 | PyEval_InitThreads(); 1075 | // register exit functions - last declared is called first 1076 | if (Py_AtExit(cleanup) != 0) 1077 | { 1078 | printf("exit 1\n"); 1079 | setup_error = 1; 1080 | 1081 | cleanup(); 1082 | #if PY_MAJOR_VERSION > 2 1083 | return NULL; 1084 | #else 1085 | return; 1086 | #endif 1087 | } 1088 | 1089 | if (Py_AtExit(event_cleanup_all) != 0) 1090 | { 1091 | printf("exit 2\n"); 1092 | setup_error = 1; 1093 | 1094 | cleanup(); 1095 | #if PY_MAJOR_VERSION > 2 1096 | return NULL; 1097 | #else 1098 | return; 1099 | #endif 1100 | } 1101 | #if PY_MAJOR_VERSION > 2 1102 | return module; 1103 | #else 1104 | return; 1105 | #endif 1106 | } 1107 | -------------------------------------------------------------------------------- /source/py_pwm.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "Python.h" 24 | #include "soft_pwm.h" 25 | #include "py_pwm.h" 26 | #include "common.h" 27 | #include "c_gpio.h" 28 | 29 | typedef struct 30 | { 31 | PyObject_HEAD 32 | unsigned int gpio; 33 | float freq; 34 | float dutycycle; 35 | } PWMObject; 36 | 37 | // python method PWM.__init__(self, channel, frequency) 38 | static int PWM_init(PWMObject *self, PyObject *args, PyObject *kwds) 39 | { 40 | int channel; 41 | float frequency; 42 | 43 | if (!PyArg_ParseTuple(args, "if", &channel, &frequency)) 44 | return -1; 45 | 46 | // convert channel to gpio 47 | if (get_gpio_number(channel, &(self->gpio))) 48 | return -1; 49 | 50 | // ensure channel set as output 51 | if (gpio_direction[self->gpio] != OUTPUT) 52 | { 53 | PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an output first"); 54 | return -1; 55 | } 56 | 57 | if (frequency <= 0.0) 58 | { 59 | PyErr_SetString(PyExc_ValueError, "frequency must be greater than 0.0"); 60 | return -1; 61 | } 62 | 63 | self->freq = frequency; 64 | 65 | pwm_set_frequency(self->gpio, self->freq); 66 | return 0; 67 | } 68 | 69 | // python method PWM.start(self, dutycycle) 70 | static PyObject *PWM_start(PWMObject *self, PyObject *args) 71 | { 72 | float dutycycle; 73 | 74 | if (!PyArg_ParseTuple(args, "f", &dutycycle)) 75 | return NULL; 76 | 77 | if (dutycycle < 0.0 || dutycycle > 100.0) 78 | { 79 | PyErr_SetString(PyExc_ValueError, "dutycycle must have a value from 0.0 to 100.0"); 80 | return NULL; 81 | } 82 | 83 | self->dutycycle = dutycycle; 84 | pwm_set_duty_cycle(self->gpio, self->dutycycle); 85 | pwm_start(self->gpio); 86 | Py_RETURN_NONE; 87 | } 88 | 89 | // python method PWM.ChangeDutyCycle(self, dutycycle) 90 | static PyObject *PWM_ChangeDutyCycle(PWMObject *self, PyObject *args) 91 | { 92 | float dutycycle = 0.0; 93 | if (!PyArg_ParseTuple(args, "f", &dutycycle)) 94 | return NULL; 95 | 96 | if (dutycycle < 0.0 || dutycycle > 100.0) 97 | { 98 | PyErr_SetString(PyExc_ValueError, "dutycycle must have a value from 0.0 to 100.0"); 99 | return NULL; 100 | } 101 | 102 | self->dutycycle = dutycycle; 103 | pwm_set_duty_cycle(self->gpio, self->dutycycle); 104 | Py_RETURN_NONE; 105 | } 106 | 107 | // python method PWM. ChangeFrequency(self, frequency) 108 | static PyObject *PWM_ChangeFrequency(PWMObject *self, PyObject *args) 109 | { 110 | float frequency = 1.0; 111 | 112 | if (!PyArg_ParseTuple(args, "f", &frequency)) 113 | return NULL; 114 | 115 | if (frequency <= 0.0) 116 | { 117 | PyErr_SetString(PyExc_ValueError, "frequency must be greater than 0.0"); 118 | return NULL; 119 | } 120 | 121 | self->freq = frequency; 122 | 123 | pwm_set_frequency(self->gpio, self->freq); 124 | Py_RETURN_NONE; 125 | } 126 | 127 | // python function PWM.stop(self) 128 | static PyObject *PWM_stop(PWMObject *self, PyObject *args) 129 | { 130 | pwm_stop(self->gpio); 131 | Py_RETURN_NONE; 132 | } 133 | 134 | // deallocation method 135 | static void PWM_dealloc(PWMObject *self) 136 | { 137 | pwm_stop(self->gpio); 138 | Py_TYPE(self)->tp_free((PyObject*)self); 139 | } 140 | 141 | static PyMethodDef 142 | PWM_methods[] = 143 | { 144 | { "start", (PyCFunction)PWM_start, METH_VARARGS, "Start software PWM\ndutycycle - the duty cycle (0.0 to 100.0)" }, 145 | { "ChangeDutyCycle", (PyCFunction)PWM_ChangeDutyCycle, METH_VARARGS, "Change the duty cycle\ndutycycle - between 0.0 and 100.0" }, 146 | { "ChangeFrequency", (PyCFunction)PWM_ChangeFrequency, METH_VARARGS, "Change the frequency\nfrequency - frequency in Hz (freq > 1.0)" }, 147 | { "stop", (PyCFunction)PWM_stop, METH_VARARGS, "Stop software PWM" }, 148 | { NULL } 149 | }; 150 | 151 | PyTypeObject PWMType = 152 | { 153 | PyVarObject_HEAD_INIT(NULL,0) 154 | "RPi.GPIO.PWM", // tp_name 155 | sizeof(PWMObject), // tp_basicsize 156 | 0, // tp_itemsize 157 | (destructor)PWM_dealloc, // tp_dealloc 158 | 0, // tp_print 159 | 0, // tp_getattr 160 | 0, // tp_setattr 161 | 0, // tp_compare 162 | 0, // tp_repr 163 | 0, // tp_as_number 164 | 0, // tp_as_sequence 165 | 0, // tp_as_mapping 166 | 0, // tp_hash 167 | 0, // tp_call 168 | 0, // tp_str 169 | 0, // tp_getattro 170 | 0, // tp_setattro 171 | 0, // tp_as_buffer 172 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flag 173 | "Pulse Width Modulation class", // tp_doc 174 | 0, // tp_traverse 175 | 0, // tp_clear 176 | 0, // tp_richcompare 177 | 0, // tp_weaklistoffset 178 | 0, // tp_iter 179 | 0, // tp_iternext 180 | PWM_methods, // tp_methods 181 | 0, // tp_members 182 | 0, // tp_getset 183 | 0, // tp_base 184 | 0, // tp_dict 185 | 0, // tp_descr_get 186 | 0, // tp_descr_set 187 | 0, // tp_dictoffset 188 | (initproc)PWM_init, // tp_init 189 | 0, // tp_alloc 190 | 0, // tp_new 191 | }; 192 | 193 | PyTypeObject *PWM_init_PWMType(void) 194 | { 195 | // Fill in some slots in the type, and make it ready 196 | PWMType.tp_new = PyType_GenericNew; 197 | if (PyType_Ready(&PWMType) < 0) 198 | return NULL; 199 | 200 | return &PWMType; 201 | } 202 | -------------------------------------------------------------------------------- /source/py_pwm.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | PyTypeObject PWMType; 24 | PyTypeObject *PWM_init_PWMType(void); 25 | -------------------------------------------------------------------------------- /source/soft_pwm.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "c_gpio.h" 27 | #include "soft_pwm.h" 28 | pthread_t threads; 29 | 30 | struct pwm 31 | { 32 | unsigned int gpio; 33 | float freq; 34 | float dutycycle; 35 | float basetime; 36 | float slicetime; 37 | struct timespec req_on, req_off; 38 | int running; 39 | struct pwm *next; 40 | }; 41 | struct pwm *pwm_list = NULL; 42 | 43 | void remove_pwm(unsigned int gpio) 44 | { 45 | struct pwm *p = pwm_list; 46 | struct pwm *prev = NULL; 47 | struct pwm *temp; 48 | 49 | while (p != NULL) 50 | { 51 | if (p->gpio == gpio) 52 | { 53 | if (prev == NULL) 54 | pwm_list = p->next; 55 | else 56 | prev->next = p->next; 57 | temp = p; 58 | p = p->next; 59 | free(temp); 60 | } 61 | else 62 | { 63 | prev = p; 64 | p = p->next; 65 | } 66 | } 67 | } 68 | 69 | void calculate_times(struct pwm *p) 70 | { 71 | long long usec; 72 | 73 | usec = (long long)(p->dutycycle * p->slicetime * 1000.0); 74 | p->req_on.tv_sec = (int)(usec / 1000000LL); 75 | usec -= (long long)p->req_on.tv_sec * 1000000LL; 76 | p->req_on.tv_nsec = (long)usec * 1000L; 77 | 78 | usec = (long long)((100.0-p->dutycycle) * p->slicetime * 1000.0); 79 | p->req_off.tv_sec = (int)(usec / 1000000LL); 80 | usec -= (long long)p->req_off.tv_sec * 1000000LL; 81 | p->req_off.tv_nsec = (long)usec * 1000L; 82 | } 83 | 84 | void full_sleep(struct timespec *req) 85 | { 86 | struct timespec rem = {0}; 87 | 88 | if (nanosleep(req,&rem) == -1) 89 | full_sleep(&rem); 90 | } 91 | 92 | void *pwm_thread(void *threadarg) 93 | { 94 | struct pwm *p = (struct pwm *)threadarg; 95 | 96 | while (p->running) 97 | { 98 | 99 | if (p->dutycycle > 0.0) 100 | { 101 | output_gpio(p->gpio, 1); 102 | full_sleep(&p->req_on); 103 | } 104 | 105 | if (p->dutycycle < 100.0) 106 | { 107 | output_gpio(p->gpio, 0); 108 | full_sleep(&p->req_off); 109 | } 110 | } 111 | 112 | // clean up 113 | output_gpio(p->gpio, 0); 114 | remove_pwm(p->gpio); 115 | pthread_exit(NULL); 116 | } 117 | 118 | struct pwm *add_new_pwm(unsigned int gpio) 119 | { 120 | struct pwm *new_pwm; 121 | 122 | new_pwm = malloc(sizeof(struct pwm)); 123 | new_pwm->gpio = gpio; 124 | new_pwm->running = 0; 125 | new_pwm->next = NULL; 126 | // default to 1 kHz frequency, dutycycle 0.0 127 | new_pwm->freq = 1000.0; 128 | new_pwm->dutycycle = 0.0; 129 | new_pwm->basetime = 1.0; // 1 ms 130 | new_pwm->slicetime = 0.01; // 0.01 ms 131 | calculate_times(new_pwm); 132 | return new_pwm; 133 | } 134 | 135 | struct pwm *find_pwm(unsigned int gpio) 136 | { 137 | struct pwm *p = pwm_list; 138 | 139 | if (pwm_list == NULL) 140 | { 141 | pwm_list = add_new_pwm(gpio); 142 | return pwm_list; 143 | } 144 | 145 | while (p != NULL) 146 | { 147 | if (p->gpio == gpio) 148 | return p; 149 | if (p->next == NULL) 150 | { 151 | p->next = add_new_pwm(gpio); 152 | return p->next; 153 | } 154 | p = p->next; 155 | } 156 | return NULL; 157 | } 158 | 159 | void pwm_set_duty_cycle(unsigned int gpio, float dutycycle) 160 | { 161 | struct pwm *p; 162 | 163 | if (dutycycle < 0.0 || dutycycle > 100.0) 164 | { 165 | // btc fixme - error 166 | return; 167 | } 168 | 169 | if ((p = find_pwm(gpio)) != NULL) 170 | { 171 | p->dutycycle = dutycycle; 172 | calculate_times(p); 173 | } 174 | } 175 | 176 | void pwm_set_frequency(unsigned int gpio, float freq) 177 | { 178 | struct pwm *p; 179 | 180 | if (freq <= 0.0) // to avoid divide by zero 181 | { 182 | // btc fixme - error 183 | return; 184 | } 185 | 186 | if ((p = find_pwm(gpio)) != NULL) 187 | { 188 | p->basetime = 1000.0 / freq; // calculated in ms 189 | p->slicetime = p->basetime / 100.0; 190 | calculate_times(p); 191 | } 192 | } 193 | 194 | void pwm_start(unsigned int gpio) 195 | { 196 | struct pwm *p; 197 | 198 | if (((p = find_pwm(gpio)) == NULL) || p->running) 199 | return; 200 | 201 | p->running = 1; 202 | if (pthread_create(&threads, NULL, pwm_thread, (void *)p) != 0) 203 | { 204 | // btc fixme - error 205 | p->running = 0; 206 | return; 207 | } 208 | } 209 | 210 | void pwm_stop(unsigned int gpio) 211 | { 212 | struct pwm *p; 213 | 214 | if ((p = find_pwm(gpio)) != NULL) 215 | p->running = 0; 216 | } 217 | -------------------------------------------------------------------------------- /source/soft_pwm.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013 Ben Croston 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | /* Software PWM using threads */ 24 | 25 | void pwm_set_duty_cycle(unsigned int gpio, float dutycycle); 26 | void pwm_set_frequency(unsigned int gpio, float freq); 27 | void pwm_start(unsigned int gpio); 28 | void pwm_stop(unsigned int gpio); 29 | -------------------------------------------------------------------------------- /source/wiringTB.h: -------------------------------------------------------------------------------- 1 | #ifndef __WIRING_TB_H__ 2 | #define __WIRING_TB_H__ 3 | 4 | #include "RKIO.h" 5 | 6 | int* asus_get_physToGpio(int rev); 7 | int* asus_get_pinToGpio(int rev); 8 | int tinker_board_setup(int rev); 9 | int asus_get_pin_mode(int pin); 10 | void asus_set_pinmode_as_gpio(int pin); 11 | void asus_set_pin_mode(int pin, int mode); 12 | void asus_digitalWrite(int pin, int value); 13 | int asus_digitalRead(int pin); 14 | void asus_pullUpDnControl (int pin, int pud); 15 | void asus_set_pwmPeriod(int pin, unsigned int period); 16 | void asus_set_pwmRange(unsigned int range); 17 | void asus_set_pwmFrequency(int pin, int divisor); 18 | void asus_set_pwmClock(int divisor); 19 | void asus_pwm_write(int pin, int value); 20 | void asus_pwmToneWrite(int pin, int freq); 21 | void asus_set_gpioClockFreq(int pin, int freq); 22 | int asus_get_pinAlt(int pin); 23 | void asus_set_pinAlt(int pin, int alt); 24 | void asus_set_GpioDriveStrength(int pin, int drv_type); 25 | int asus_get_GpioDriveStrength(int pin); 26 | void asus_cleanup(void); 27 | #endif 28 | -------------------------------------------------------------------------------- /test/.btc.py.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TinkerBoard/gpio_lib_python/31fb5d7971fa57d6ef5b6206b287826a7e5597e2/test/.btc.py.swp -------------------------------------------------------------------------------- /test/GPIO_IN_OUT_test.py: -------------------------------------------------------------------------------- 1 | #Testing for GPIO 2 | import ASUS.GPIO as GPIO 3 | 4 | GPIO.setwarnings(False) 5 | 6 | #Pin Table [Begin] 7 | pinTable = [] 8 | pinTable += [{'phys': 1, 'wPi': -1, 'TB': -1, 'BCM': -1}, {'phys': 2, 'wPi': -1, 'TB': -1, 'BCM': -1}] #[1]3.3V | [2]5V 9 | pinTable += [{'phys': 3, 'wPi': 8, 'TB': 252, 'BCM': 2}, {'phys': 4, 'wPi': -1, 'TB': -1, 'BCM': -1}] #[3]GP8A4_I2C1_SDA | [4]5V 10 | pinTable += [{'phys': 5, 'wPi': 9, 'TB': 253, 'BCM': 3}, {'phys': 6, 'wPi': -1, 'TB': -1, 'BCM': -1}] #[5]GP8A5_I2C1_SCL | [6]GND 11 | pinTable += [{'phys': 7, 'wPi': 7, 'TB': 17, 'BCM': 4}, {'phys': 8, 'wPi': 15, 'TB': 161, 'BCM': 14}] #[7]GP0C1_CLKOUT | [8]GP5B1_UART1TX 12 | pinTable += [{'phys': 9, 'wPi': -1, 'TB': -1, 'BCM': -1}, {'phys': 10, 'wPi': 16, 'TB': 160, 'BCM': 15}] #[9]GND | [10]GP5B0_UART1RX 13 | pinTable += [{'phys': 11, 'wPi': 0, 'TB': 164, 'BCM': 17}, {'phys': 12, 'wPi': 1, 'TB': 184, 'BCM': 18}] #[11]GP5B4_SPI0CLK_UART4CTSN | [12]GP6A0_PCM/I2S_CLK 14 | pinTable += [{'phys': 13, 'wPi': 2, 'TB': 166, 'BCM': 27}, {'phys': 14, 'wPi': -1, 'TB': -1, 'BCM': -1}] #[13]GP5B6_SPI0_TXD_UART4TX | [14]GND 15 | pinTable += [{'phys': 15, 'wPi': 3, 'TB': 167, 'BCM': 22}, {'phys': 16, 'wPi': 4, 'TB': 162, 'BCM': 23}] #[15]GP5B7_SPI0_RXD_UART4RX | [16]GP5B2_UART1CTSN 16 | pinTable += [{'phys': 17, 'wPi': -1, 'TB': -1, 'BCM': -1}, {'phys': 18, 'wPi': 5, 'TB': 163, 'BCM': 24}] #[17]3.3V | [18]GP5B3_UART1RTSN 17 | pinTable += [{'phys': 19, 'wPi': 12, 'TB': 257, 'BCM': 10}, {'phys': 20, 'wPi': -1, 'TB': -1, 'BCM': -1}] #[19]GP8B1_SPI2TXD | [20]GND 18 | pinTable += [{'phys': 21, 'wPi': 13, 'TB': 256, 'BCM': 9}, {'phys': 22, 'wPi': 6, 'TB': 171, 'BCM': 25}] #[21]GP8B0_SPI2RXD | [22]GP5C3 19 | pinTable += [{'phys': 23, 'wPi': 14, 'TB': 254, 'BCM': 11}, {'phys': 24, 'wPi': 10, 'TB': 255, 'BCM': 8}] #[23]GP8A6_SPI2CLK | [24]GP8A7_SPI2CSN0 20 | pinTable += [{'phys': 25, 'wPi': -1, 'TB': -1, 'BCM': -1}, {'phys': 26, 'wPi': 11, 'TB': 251, 'BCM': 7}] #[25]GND | [26]GP8A3_SPI2CSN1 21 | pinTable += [{'phys': 27, 'wPi': 30, 'TB': 233, 'BCM': 0}, {'phys': 28, 'wPi': 31, 'TB': 234, 'BCM': 1}] #[27]GP7C1_I2C4_SDA | [28]GP7C2_I2C4_SCL 22 | pinTable += [{'phys': 29, 'wPi': 21, 'TB': 165, 'BCM': 5}, {'phys': 30, 'wPi': -1, 'TB': -1, 'BCM': -1}] #[29]GP5B5_SPI0CSN0_UART4RTSN | [30]GND 23 | pinTable += [{'phys': 31, 'wPi': 22, 'TB': 168, 'BCM': 6}, {'phys': 32, 'wPi': 26, 'TB': 239, 'BCM': 12}] #[31]GP5C0_SPI0CSN1 | [32]GP7C7_UART2TX_PWM3 24 | pinTable += [{'phys': 33, 'wPi': 23, 'TB': 238, 'BCM': 13}, {'phys': 34, 'wPi': -1, 'TB': -1, 'BCM': -1}] #[33]GP7C6_UART2RX_PWM2 | [34]GND 25 | pinTable += [{'phys': 35, 'wPi': 24, 'TB': 185, 'BCM': 19}, {'phys': 36, 'wPi': 27, 'TB': 223, 'BCM': 16}] #[35]GP6A1_PCM/I2S_FS | [36]GP7A7_UART3RX 26 | pinTable += [{'phys': 37, 'wPi': 25, 'TB': 224, 'BCM': 26}, {'phys': 38, 'wPi': 28, 'TB': 187, 'BCM': 20}] #[37]GP7B0_UART3TX | [38]GP6A3_PCM/I2S_SDI 27 | pinTable += [{'phys': 39, 'wPi': -1, 'TB': -1, 'BCM': -1}, {'phys': 40, 'wPi': 29, 'TB': 188, 'BCM': 21}] #[39]GND | [40]GP6A4_PCM/I2S_SDO 28 | 29 | pairPins = [( 3, 8), 30 | ( 5, 10), 31 | ( 7, 12), 32 | (11, 13), 33 | (15, 16), 34 | (19, 18), 35 | (21, 22), 36 | (23, 24), 37 | (27, 26), 38 | (29, 28), 39 | (31, 32), 40 | (33, 36), 41 | (35, 38), 42 | (37, 40)] 43 | gpioUsedPins = [3, 5, 7, 8, 10, 11, 12, 13, 15, 16, 18, 19, 21, 22, 23, 24, 26, 27, 28, 29, 31, 32, 33, 35, 36, 37, 38, 40] 44 | PullUpDnPins = {3: GPIO.PUD_UP, 5: GPIO.PUD_UP, 27: GPIO.PUD_UP, 28: GPIO.PUD_UP} 45 | modeMap = {'phys': GPIO.BOARD, 'TB': GPIO.ASUS, 'BCM': GPIO.BCM} 46 | modeNameMap = {'phys': 'GPIO.BOARD', 'TB': 'GPIO.ASUS', 'BCM': 'GPIO.BCM'} 47 | InternalPullUpDnValue = {GPIO.PUD_UP: GPIO.HIGH, GPIO.PUD_DOWN: GPIO.LOW} 48 | #Pin Table [End] 49 | 50 | def GPIO_IO_TESTING(): 51 | print('== Testing GPIO INPUT/OUTPUT ==') 52 | for mode in ['phys', 'TB', 'BCM']: 53 | GPIO.setmode(modeMap[mode]) 54 | LPin = [pinTable[pins[0] - 1][mode] for pins in pairPins] 55 | RPin = [pinTable[pins[1] - 1][mode] for pins in pairPins] 56 | if(-1 in LPin or -1 in RPin): 57 | print('Some pins use the 3.3V or GND pin.') 58 | exit() 59 | for IPin, OPin in [(LPin, RPin), (RPin, LPin)]: 60 | GPIO.setup( IPin, GPIO.IN) 61 | GPIO.setup( OPin, GPIO.OUT) 62 | if(False in [GPIO.gpio_function(pin) == GPIO.IN for pin in IPin] or 63 | False in [GPIO.gpio_function(pin) == GPIO.OUT for pin in OPin]): 64 | print('Check GPIO.gpio_function or GPIO.setup.') 65 | exit() 66 | for volt in [GPIO.HIGH, GPIO.LOW]: 67 | GPIO.output(OPin, volt) 68 | OResult = [GPIO.input(pin) == volt for pin in OPin] 69 | IResult = [GPIO.input(IPin[i]) == GPIO.input(OPin[i]) for i in range(len(IPin))] 70 | if(False in OResult): 71 | print('Check Pin[%d].' % (OPin[OResult.index(False)])) 72 | exit() 73 | if(False in IResult): 74 | print('Check Pin[%d].' % (IPin[IResult.index(False)])) 75 | exit() 76 | print("[PASS] GPIO.setmode(%s)" % (modeNameMap[mode])) 77 | GPIO.cleanup() 78 | print('===============================') 79 | 80 | def GPIO_PULL_UPDW_TESTING(): 81 | checkPins = [] 82 | print('== Testing GPIO PULL_UP_DOWN ==') 83 | testPin = gpioUsedPins 84 | print("Check that nothing connects to those pins: %s" % (','.join([str(x) for x in testPin]))) 85 | GPIO.setmode(GPIO.BOARD) 86 | GPIO.setup(testPin , GPIO.IN, pull_up_down=GPIO.PUD_UP) 87 | for pin in testPin: 88 | if (GPIO.input(pin) != InternalPullUpDnValue[PullUpDnPins[pin] if pin in PullUpDnPins else GPIO.PUD_UP]): 89 | checkPins.append(pin) 90 | GPIO.setup(testPin , GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 91 | for pin in testPin: 92 | if (GPIO.input(pin) != InternalPullUpDnValue[PullUpDnPins[pin] if pin in PullUpDnPins else GPIO.PUD_DOWN]): 93 | checkPins.append(pin) 94 | print("[%s] Pull Up and Down" % ('PASS' if len(checkPins) <= 0 else 'FAILED')) 95 | if(len(checkPins) > 0 ): 96 | print('Please check those pins: %s' % (','.join([str(x) for x in checkPins]))) 97 | GPIO.cleanup() 98 | print('===============================') 99 | 100 | GPIO_IO_TESTING() 101 | GPIO_PULL_UPDW_TESTING() 102 | -------------------------------------------------------------------------------- /test/add_event_callback.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2.7 2 | # demo of "BOTH" bi-directional edge detection 3 | # script by Alex Eames http://RasPi.tv 4 | # http://raspi.tv/?p=6791 5 | 6 | import ASUS.GPIO as GPIO 7 | from time import sleep # this lets us have a time delay (see line 12) 8 | 9 | GPIO.setmode(GPIO.BOARD) # set up BCM GPIO numbering 10 | GPIO.setup(3, GPIO.IN) # set GPIO25 as input (button) 11 | 12 | # Define a threaded callback function to run in another thread when events are detected 13 | def my_callback(channel): 14 | if GPIO.input(3): # if port 25 == 1 15 | print "Rising edge detected on 25" 16 | else: # if port 25 != 1 17 | print "Falling edge detected on 25" 18 | 19 | # when a changing edge is detected on port 25, regardless of whatever 20 | # else is happening in the program, the function my_callback will be run 21 | GPIO.add_event_detect(3, GPIO.BOTH, callback=my_callback) 22 | 23 | print "Program will finish after 30 seconds or if you press CTRL+C\n" 24 | print "Make sure you have a button connected, pulled down through 10k resistor" 25 | print "to GND and wired so that when pressed it connects" 26 | print "GPIO port 25 (pin 22) to GND (pin 6) through a ~1k resistor\n" 27 | 28 | print "Also put a 100 nF capacitor across your switch for hardware debouncing" 29 | print "This is necessary to see the effect we're looking for" 30 | raw_input("Press Enter when ready\n>") 31 | 32 | try: 33 | print "When pressed, you'll see: Rising Edge detected on 252" 34 | print "When released, you'll see: Falling Edge detected on 252" 35 | sleep(30) # wait 30 seconds 36 | print "Time's up. Finished!" 37 | 38 | finally: # this block will run no matter how the try block exits 39 | GPIO.cleanup() # clean up after yourself 40 | -------------------------------------------------------------------------------- /test/btc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2.7 2 | import unittest 3 | from threading import Timer,activeCount 4 | import time 5 | import ASUS.GPIO as GPIO 6 | 7 | LOOP_IN = 16 8 | LOOP_OUT = 22 9 | 10 | class TestEdgeDetection(unittest.TestCase): 11 | def setUp(self): 12 | GPIO.setmode(GPIO.BOARD) 13 | GPIO.setup(LOOP_IN, GPIO.IN) 14 | GPIO.setup(LOOP_OUT, GPIO.OUT) 15 | 16 | def testWaitForEdgeInLoop(self): 17 | def makelow(): 18 | GPIO.output(LOOP_OUT, GPIO.LOW) 19 | 20 | count = 0 21 | timestart = time.time() 22 | GPIO.output(LOOP_OUT, GPIO.HIGH) 23 | while True: 24 | t = Timer(0.1, makelow) 25 | t.start() 26 | GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING) 27 | GPIO.output(LOOP_OUT, GPIO.HIGH) 28 | count += 1 29 | if time.time() - timestart > 5 or count > 150: 30 | break 31 | 32 | def testWaitForEdgeWithCallback(self): 33 | def cb(): 34 | raise Exception("Callback should not be called") 35 | def makehigh(): 36 | GPIO.output(LOOP_OUT, GPIO.HIGH) 37 | 38 | GPIO.output(LOOP_OUT, GPIO.LOW) 39 | t = Timer(0.1, makehigh) 40 | 41 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING) 42 | t.start() 43 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) 44 | 45 | GPIO.output(LOOP_OUT, GPIO.LOW) 46 | GPIO.add_event_callback(LOOP_IN, callback=cb) 47 | with self.assertRaises(RuntimeError): # conflicting edge exception 48 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) 49 | 50 | GPIO.remove_event_detect(LOOP_IN) 51 | 52 | def testWaitForEventSwitchbounce(self): 53 | self.finished = False 54 | def bounce(): 55 | GPIO.output(LOOP_OUT, GPIO.HIGH) 56 | time.sleep(0.01) 57 | GPIO.output(LOOP_OUT, GPIO.LOW) 58 | time.sleep(0.01) 59 | GPIO.output(LOOP_OUT, GPIO.HIGH) 60 | time.sleep(0.01) 61 | GPIO.output(LOOP_OUT, GPIO.LOW) 62 | time.sleep(0.2) 63 | GPIO.output(LOOP_OUT, GPIO.HIGH) 64 | time.sleep(0.01) 65 | GPIO.output(LOOP_OUT, GPIO.LOW) 66 | time.sleep(0.01) 67 | GPIO.output(LOOP_OUT, GPIO.HIGH) 68 | time.sleep(0.01) 69 | GPIO.output(LOOP_OUT, GPIO.LOW) 70 | self.finished = True 71 | 72 | GPIO.output(LOOP_OUT, GPIO.LOW) 73 | t1 = Timer(0.1, bounce) 74 | t1.start() 75 | 76 | starttime = time.time() 77 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=100) 78 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=100) 79 | finishtime = time.time() 80 | self.assertGreater(finishtime-starttime, 0.2) 81 | while not self.finished: 82 | time.sleep(0.1) 83 | 84 | def testInvalidBouncetime(self): 85 | with self.assertRaises(ValueError): 86 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING, bouncetime=-1) 87 | with self.assertRaises(ValueError): 88 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=-1) 89 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING, bouncetime=123) 90 | with self.assertRaises(RuntimeError): 91 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=321) 92 | GPIO.remove_event_detect(LOOP_IN) 93 | 94 | def testAlreadyAdded(self): 95 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING) 96 | with self.assertRaises(RuntimeError): 97 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING) 98 | GPIO.remove_event_detect(LOOP_IN) 99 | 100 | def testHighLowEvent(self): 101 | with self.assertRaises(ValueError): 102 | GPIO.add_event_detect(LOOP_IN, GPIO.LOW) 103 | with self.assertRaises(ValueError): 104 | GPIO.add_event_detect(LOOP_IN, GPIO.HIGH) 105 | 106 | def testFallingEventDetected(self): 107 | GPIO.output(LOOP_OUT, GPIO.HIGH) 108 | GPIO.add_event_detect(LOOP_IN, GPIO.FALLING) 109 | time.sleep(0.01) 110 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 111 | GPIO.output(LOOP_OUT, GPIO.LOW) 112 | time.sleep(0.01) 113 | self.assertEqual(GPIO.event_detected(LOOP_IN), True) 114 | GPIO.output(LOOP_OUT, GPIO.HIGH) 115 | time.sleep(0.01) 116 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 117 | GPIO.remove_event_detect(LOOP_IN) 118 | 119 | def testRisingEventDetected(self): 120 | GPIO.output(LOOP_OUT, GPIO.LOW) 121 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING) 122 | time.sleep(0.01) 123 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 124 | GPIO.output(LOOP_OUT, GPIO.HIGH) 125 | time.sleep(0.01) 126 | self.assertEqual(GPIO.event_detected(LOOP_IN), True) 127 | GPIO.output(LOOP_OUT, GPIO.LOW) 128 | time.sleep(0.01) 129 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 130 | GPIO.remove_event_detect(LOOP_IN) 131 | 132 | def testBothEventDetected(self): 133 | GPIO.output(LOOP_OUT, GPIO.LOW) 134 | GPIO.add_event_detect(LOOP_IN, GPIO.BOTH) 135 | time.sleep(0.01) 136 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 137 | GPIO.output(LOOP_OUT, GPIO.HIGH) 138 | time.sleep(0.01) 139 | self.assertEqual(GPIO.event_detected(LOOP_IN), True) 140 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 141 | GPIO.output(LOOP_OUT, GPIO.LOW) 142 | time.sleep(0.01) 143 | self.assertEqual(GPIO.event_detected(LOOP_IN), True) 144 | GPIO.remove_event_detect(LOOP_IN) 145 | 146 | def testWaitForRising(self): 147 | def makehigh(): 148 | GPIO.output(LOOP_OUT, GPIO.HIGH) 149 | GPIO.output(LOOP_OUT, GPIO.LOW) 150 | t = Timer(0.1, makehigh) 151 | t.start() 152 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) 153 | 154 | def testWaitForFalling(self): 155 | def makelow(): 156 | GPIO.output(LOOP_OUT, GPIO.LOW) 157 | GPIO.output(LOOP_OUT, GPIO.HIGH) 158 | t = Timer(0.1, makelow) 159 | t.start() 160 | GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING) 161 | 162 | def testExceptionInCallback(self): 163 | self.run_cb = False 164 | def cb(channel): 165 | with self.assertRaises(ZeroDivisionError): 166 | self.run_cb = True 167 | a = 1/0 168 | GPIO.output(LOOP_OUT, GPIO.LOW) 169 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING, callback=cb) 170 | time.sleep(0.01) 171 | GPIO.output(LOOP_OUT, GPIO.HIGH) 172 | time.sleep(0.01) 173 | self.assertEqual(self.run_cb, True) 174 | GPIO.remove_event_detect(LOOP_IN) 175 | 176 | def testAddEventCallback(self): 177 | def cb(channel): 178 | self.callback_count += 1 179 | 180 | # falling test 181 | self.callback_count = 0 182 | GPIO.output(LOOP_OUT, GPIO.HIGH) 183 | GPIO.add_event_detect(LOOP_IN, GPIO.FALLING) 184 | GPIO.add_event_callback(LOOP_IN, cb) 185 | time.sleep(0.01) 186 | for i in range(2048): 187 | GPIO.output(LOOP_OUT, GPIO.LOW) 188 | time.sleep(0.001) 189 | GPIO.output(LOOP_OUT, GPIO.HIGH) 190 | time.sleep(0.001) 191 | GPIO.remove_event_detect(LOOP_IN) 192 | self.assertEqual(self.callback_count, 2048) 193 | 194 | # rising test 195 | self.callback_count = 0 196 | GPIO.output(LOOP_OUT, GPIO.LOW) 197 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING, callback=cb) 198 | time.sleep(0.01) 199 | for i in range(2048): 200 | GPIO.output(LOOP_OUT, GPIO.HIGH) 201 | time.sleep(0.001) 202 | GPIO.output(LOOP_OUT, GPIO.LOW) 203 | time.sleep(0.001) 204 | GPIO.remove_event_detect(LOOP_IN) 205 | self.assertEqual(self.callback_count, 2048) 206 | 207 | # both test 208 | self.callback_count = 0 209 | GPIO.output(LOOP_OUT, GPIO.LOW) 210 | GPIO.add_event_detect(LOOP_IN, GPIO.BOTH, callback=cb) 211 | time.sleep(0.01) 212 | for i in range(2048): 213 | GPIO.output(LOOP_OUT, GPIO.HIGH) 214 | time.sleep(0.001) 215 | GPIO.output(LOOP_OUT, GPIO.LOW) 216 | time.sleep(0.001) 217 | GPIO.remove_event_detect(LOOP_IN) 218 | self.assertEqual(self.callback_count, 4096) 219 | 220 | def testEventOnOutput(self): 221 | with self.assertRaises(RuntimeError): 222 | GPIO.add_event_detect(LOOP_OUT, GPIO.FALLING) 223 | 224 | def testAlternateWaitForEdge(self): 225 | def makehigh(): 226 | GPIO.output(LOOP_OUT, GPIO.HIGH) 227 | def makelow(): 228 | GPIO.output(LOOP_OUT, GPIO.LOW) 229 | GPIO.output(LOOP_OUT, GPIO.LOW) 230 | t = Timer(2.0, makehigh) 231 | t2 = Timer(2.0, makelow) 232 | t.start() 233 | t2.start() 234 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) 235 | GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING) 236 | 237 | def tearDown(self): 238 | GPIO.cleanup() 239 | 240 | if __name__ == '__main__': 241 | unittest.main() 242 | -------------------------------------------------------------------------------- /test/forloop.py: -------------------------------------------------------------------------------- 1 | import ASUS.GPIO as GPIO 2 | import unittest 3 | import time 4 | # to use ASUS tinker board pin numbers 5 | GPIO.setmode(GPIO.BOARD) 6 | 7 | # set up GPIO output channel, we set GPIO4 (Pin 7) to OUTPUT 8 | 9 | n = 40 10 | 11 | for counter in range (1, n+1): 12 | if counter == 1 or \ 13 | counter == 2 or \ 14 | counter == 4 or \ 15 | counter == 6 or \ 16 | counter == 9 or \ 17 | counter == 14 or \ 18 | counter == 17 or \ 19 | counter == 20 or \ 20 | counter == 25 or \ 21 | counter == 30 or \ 22 | counter == 34 or \ 23 | counter == 39 : 24 | continue 25 | GPIO.setup(counter, GPIO.OUT) 26 | GPIO.output(counter,GPIO.HIGH) 27 | time.sleep(1) 28 | 29 | 30 | for counter in range (1, n+1): 31 | if counter == 1 or \ 32 | counter == 2 or \ 33 | counter == 4 or \ 34 | counter == 6 or \ 35 | counter == 9 or \ 36 | counter == 14 or \ 37 | counter == 17 or \ 38 | counter == 20 or \ 39 | counter == 25 or \ 40 | counter == 30 or \ 41 | counter == 34 or \ 42 | counter == 39 : 43 | continue 44 | GPIO.output(counter,GPIO.LOW) 45 | time.sleep(1) 46 | 47 | -------------------------------------------------------------------------------- /test/gpio_backup.py: -------------------------------------------------------------------------------- 1 | import ASUS.GPIO as GPIO 2 | import unittest 3 | import time 4 | # to use Raspberry Pi board pin numbers 5 | GPIO.setmode(GPIO.RK) 6 | 7 | # set up GPIO output channel, we set GPIO4 (Pin 7) to OUTPUT 8 | 9 | 10 | GPIO.setup(187, GPIO.IN, pull_up_down=GPIO.PUD_UP) 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | #GPIO.setup(8, GPIO.OUT) 20 | #GPIO.setup(1, GPIO.OUT) 21 | #GPIO.setup(9, GPIO.OUT) 22 | #GPIO.setup(8, GPIO.IN) 23 | #GPIO.input(8) 24 | 25 | #GPIO.output(9,GPIO.HIGH) 26 | #GPIO.input(8) 27 | #GPIO.output(9,GPIO.LOW) 28 | #GPIO.input(8) 29 | #GPIO.output(9,GPIO.HIGH) 30 | #GPIO.input(8) 31 | #GPIO.output(9,GPIO.LOW) 32 | #GPIO.input(8) 33 | 34 | 35 | -------------------------------------------------------------------------------- /test/pwm.py: -------------------------------------------------------------------------------- 1 | #Testing for software PWM 2 | import ASUS.GPIO as GPIO 3 | import unittest 4 | import time 5 | 6 | GPIO.setmode(GPIO.ASUS) 7 | GPIO.setup(252, GPIO.OUT) 8 | pwm = GPIO.PWM(252, 50) 9 | pwm.start(100) 10 | 11 | while True: 12 | for i in range(0,3): 13 | for x in range(0,101,5): 14 | pwm.ChangeDutyCycle(x) 15 | time.sleep(0.1) 16 | for x in range(100,-1,-5): 17 | pwm.ChangeDutyCycle(x) 18 | time.sleep(0.1) 19 | -------------------------------------------------------------------------------- /test/pwm_input.py: -------------------------------------------------------------------------------- 1 | #Testing for software PWM 2 | import ASUS.GPIO as GPIO 3 | import unittest 4 | import time 5 | 6 | GPIO.setmode(GPIO.ASUS) 7 | 8 | while True: 9 | gpiovalue = int(input("Enter the gpio number:")) 10 | freqvalue = int(input("Enter the frequency value:")) 11 | GPIO.setup(gpiovalue, GPIO.OUT) 12 | pwm = GPIO.PWM(gpiovalue, freqvalue) 13 | pwm.start(50) 14 | 15 | -------------------------------------------------------------------------------- /test/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | """ 3 | Copyright (c) 2013-2015 Ben Croston 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | """ 23 | 24 | """This test suite assumes the following circuit is connected: 25 | GND_PIN = 6 26 | LED_PIN = 12 (with resistor to 0v) 27 | SWITCH_PIN = 18 (with 0.1 uF capacitor around switch) to 0v 28 | LOOP_IN = 16 connected with 1K resistor to LOOP_OUT 29 | LOOP_OUT = 22 30 | """ 31 | 32 | import sys 33 | import warnings 34 | import time 35 | from threading import Timer 36 | import RPi.GPIO as GPIO 37 | if sys.version[:3] == '2.6': 38 | import unittest2 as unittest 39 | else: 40 | import unittest 41 | 42 | GND_PIN = 6 43 | LED_PIN = 12 44 | LED_PIN_BCM = 18 45 | SWITCH_PIN = 18 46 | LOOP_IN = 16 47 | LOOP_OUT = 22 48 | 49 | non_interactive = False 50 | for i,val in enumerate(sys.argv): 51 | if val == '--non_interactive': 52 | non_interactive = True 53 | sys.argv.pop(i) 54 | 55 | # Test starts with 'AAA' so that it is run first 56 | class TestAAASetup(unittest.TestCase): 57 | def runTest(self): 58 | # Test mode not set (BOARD or BCM) exception 59 | with self.assertRaises(RuntimeError) as e: 60 | GPIO.setup(LED_PIN, GPIO.OUT) 61 | self.assertEqual(str(e.exception), 'Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)') 62 | 63 | # Test trying to change mode after it has been set 64 | GPIO.setmode(GPIO.BCM) 65 | with self.assertRaises(ValueError) as e: 66 | GPIO.setmode(GPIO.BOARD) 67 | GPIO.setup(LED_PIN_BCM, GPIO.IN) 68 | GPIO.cleanup() 69 | 70 | # Test getmode() 71 | self.assertEqual(GPIO.getmode(), GPIO.UNKNOWN) 72 | GPIO.setmode(GPIO.BCM) 73 | self.assertEqual(GPIO.getmode(), GPIO.BCM) 74 | GPIO.setup(LED_PIN_BCM, GPIO.IN) 75 | GPIO.cleanup() 76 | GPIO.setmode(GPIO.BOARD) 77 | self.assertEqual(GPIO.getmode(), GPIO.BOARD) 78 | 79 | # Test not set as OUTPUT message 80 | GPIO.setmode(GPIO.BOARD) 81 | with self.assertRaises(RuntimeError) as e: 82 | GPIO.output(LED_PIN, GPIO.HIGH) 83 | self.assertEqual(str(e.exception), 'The GPIO channel has not been set up as an OUTPUT') 84 | 85 | # Test setup(..., pull_up_down=GPIO.HIGH) raises exception 86 | GPIO.setmode(GPIO.BOARD) 87 | with self.assertRaises(ValueError): 88 | GPIO.setup(LED_PIN, GPIO.IN, pull_up_down=GPIO.HIGH) 89 | 90 | # Test not valid on a raspi exception 91 | GPIO.setmode(GPIO.BOARD) 92 | with self.assertRaises(ValueError) as e: 93 | GPIO.setup(GND_PIN, GPIO.OUT) 94 | self.assertEqual(str(e.exception), 'The channel sent is invalid on a Raspberry Pi') 95 | 96 | # Test 'already in use' warning 97 | GPIO.setmode(GPIO.BOARD) 98 | with open('/sys/class/gpio/export','wb') as f: 99 | f.write(str(LED_PIN_BCM).encode()) 100 | with open('/sys/class/gpio/gpio%s/direction'%LED_PIN_BCM,'wb') as f: 101 | f.write(b'out') 102 | with open('/sys/class/gpio/gpio%s/value'%LED_PIN_BCM,'wb') as f: 103 | f.write(b'1') 104 | time.sleep(0.2) 105 | with warnings.catch_warnings(record=True) as w: 106 | GPIO.setup(LED_PIN, GPIO.OUT) # generate 'already in use' warning 107 | self.assertEqual(w[0].category, RuntimeWarning) 108 | with open('/sys/class/gpio/unexport','wb') as f: 109 | f.write(str(LED_PIN_BCM).encode()) 110 | GPIO.cleanup() 111 | 112 | # test initial value of high reads back as high 113 | GPIO.setmode(GPIO.BOARD) 114 | GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.HIGH) 115 | self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) 116 | GPIO.cleanup() 117 | 118 | # test initial value of low reads back as low 119 | GPIO.setmode(GPIO.BOARD) 120 | GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.LOW) 121 | self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) 122 | GPIO.cleanup() 123 | 124 | # test setup of a list of channels 125 | GPIO.setmode(GPIO.BOARD) 126 | GPIO.setup( [LED_PIN, LOOP_OUT], GPIO.OUT) 127 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 128 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) 129 | GPIO.cleanup() 130 | GPIO.setmode(GPIO.BOARD) 131 | with self.assertRaises(ValueError) as e: 132 | GPIO.setup( [LED_PIN, GND_PIN], GPIO.OUT) 133 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 134 | self.assertEqual(str(e.exception), 'The channel sent is invalid on a Raspberry Pi') 135 | GPIO.cleanup() 136 | 137 | # test setup of a tuple of channels 138 | GPIO.setmode(GPIO.BOARD) 139 | GPIO.setup( (LED_PIN, LOOP_OUT), GPIO.OUT) 140 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 141 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) 142 | GPIO.cleanup() 143 | 144 | # test warning when using pull up/down on i2c channels 145 | GPIO.setmode(GPIO.BOARD) 146 | if GPIO.RPI_INFO['P1_REVISION'] == 0: # compute module 147 | pass # test not vailid 148 | else: # revision 1, 2 or A+/B+ 149 | with warnings.catch_warnings(record=True) as w: 150 | GPIO.setup(3, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 151 | self.assertEqual(w[0].category, RuntimeWarning) 152 | with warnings.catch_warnings(record=True) as w: 153 | GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 154 | self.assertEqual(w[0].category, RuntimeWarning) 155 | GPIO.cleanup() 156 | 157 | # test non integer channel 158 | GPIO.setmode(GPIO.BOARD) 159 | with self.assertRaises(ValueError): 160 | GPIO.setup('d', GPIO.OUT) 161 | with self.assertRaises(ValueError): 162 | GPIO.setup(('d',LED_PIN), GPIO.OUT) 163 | 164 | class TestInputOutput(unittest.TestCase): 165 | def setUp(self): 166 | GPIO.setmode(GPIO.BOARD) 167 | 168 | def test_outputread(self): 169 | """Test that an output() can be input()""" 170 | GPIO.setup(LED_PIN, GPIO.OUT) 171 | GPIO.output(LED_PIN, GPIO.HIGH) 172 | self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) 173 | GPIO.output(LED_PIN, GPIO.LOW) 174 | self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) 175 | 176 | def test_loopback(self): 177 | """Test output loops back to another input""" 178 | GPIO.setup(LOOP_IN, GPIO.IN, pull_up_down=GPIO.PUD_OFF) 179 | GPIO.setup(LOOP_OUT, GPIO.OUT, initial=GPIO.LOW) 180 | self.assertEqual(GPIO.input(LOOP_IN), GPIO.LOW) 181 | GPIO.output(LOOP_OUT, GPIO.HIGH) 182 | self.assertEqual(GPIO.input(LOOP_IN), GPIO.HIGH) 183 | 184 | def test_output_on_input(self): 185 | """Test output() can not be done on input""" 186 | GPIO.setup(SWITCH_PIN, GPIO.IN) 187 | with self.assertRaises(RuntimeError): 188 | GPIO.output(SWITCH_PIN, GPIO.LOW) 189 | 190 | def test_output_list(self): 191 | """Test output() using lists""" 192 | GPIO.setup(LOOP_OUT, GPIO.OUT) 193 | GPIO.setup(LED_PIN, GPIO.OUT) 194 | 195 | GPIO.output( [LOOP_OUT, LED_PIN], GPIO.HIGH) 196 | self.assertEqual(GPIO.input(LOOP_OUT), GPIO.HIGH) 197 | self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) 198 | 199 | GPIO.output( (LOOP_OUT, LED_PIN), GPIO.LOW) 200 | self.assertEqual(GPIO.input(LOOP_OUT), GPIO.LOW) 201 | self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) 202 | 203 | GPIO.output( [LOOP_OUT, LED_PIN], [GPIO.HIGH, GPIO.LOW] ) 204 | self.assertEqual(GPIO.input(LOOP_OUT), GPIO.HIGH) 205 | self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) 206 | 207 | GPIO.output( (LOOP_OUT, LED_PIN), (GPIO.LOW, GPIO.HIGH) ) 208 | self.assertEqual(GPIO.input(LOOP_OUT), GPIO.LOW) 209 | self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) 210 | 211 | with self.assertRaises(RuntimeError): 212 | GPIO.output( [LOOP_OUT, LED_PIN], [0,0,0] ) 213 | 214 | with self.assertRaises(RuntimeError): 215 | GPIO.output( [LOOP_OUT, LED_PIN], (0,) ) 216 | 217 | with self.assertRaises(RuntimeError): 218 | GPIO.output(LOOP_OUT, (0,0)) 219 | 220 | with self.assertRaises(ValueError): 221 | GPIO.output( [LOOP_OUT, 'x'], (0,0) ) 222 | 223 | with self.assertRaises(ValueError): 224 | GPIO.output( [LOOP_OUT, LED_PIN], (0,'x') ) 225 | 226 | with self.assertRaises(ValueError): 227 | GPIO.output( [LOOP_OUT, GND_PIN], (0,0) ) 228 | 229 | with self.assertRaises(RuntimeError): 230 | GPIO.output( [LOOP_OUT, LOOP_IN], (0,0) ) 231 | 232 | def tearDown(self): 233 | GPIO.cleanup() 234 | 235 | class TestSoftPWM(unittest.TestCase): 236 | @unittest.skipIf(non_interactive, 'Non interactive mode') 237 | def runTest(self): 238 | GPIO.setmode(GPIO.BOARD) 239 | GPIO.setup(LED_PIN, GPIO.OUT) 240 | pwm = GPIO.PWM(LED_PIN, 50) 241 | pwm.start(100) 242 | print "\nPWM tests" 243 | response = raw_input('Is the LED on (y/n) ? ').upper() 244 | self.assertEqual(response,'Y') 245 | pwm.start(0) 246 | response = raw_input('Is the LED off (y/n) ? ').upper() 247 | self.assertEqual(response,'Y') 248 | print "LED Brighten/fade test..." 249 | for i in range(0,3): 250 | for x in range(0,101,5): 251 | pwm.ChangeDutyCycle(x) 252 | time.sleep(0.1) 253 | for x in range(100,-1,-5): 254 | pwm.ChangeDutyCycle(x) 255 | time.sleep(0.1) 256 | pwm.stop() 257 | response = raw_input('Did it work (y/n) ? ').upper() 258 | self.assertEqual(response,'Y') 259 | GPIO.cleanup() 260 | 261 | class TestSetWarnings(unittest.TestCase): 262 | def test_alreadyinuse(self): 263 | """Test 'already in use' warning""" 264 | GPIO.setmode(GPIO.BOARD) 265 | GPIO.setwarnings(False) 266 | with open('/sys/class/gpio/export','wb') as f: 267 | f.write(str(LED_PIN_BCM).encode()) 268 | with open('/sys/class/gpio/gpio%s/direction'%LED_PIN_BCM,'wb') as f: 269 | f.write(b'out') 270 | with open('/sys/class/gpio/gpio%s/value'%LED_PIN_BCM,'wb') as f: 271 | f.write(b'1') 272 | with warnings.catch_warnings(record=True) as w: 273 | GPIO.setup(LED_PIN, GPIO.OUT) # generate 'already in use' warning 274 | self.assertEqual(len(w),0) # should be no warnings 275 | with open('/sys/class/gpio/unexport','wb') as f: 276 | f.write(str(LED_PIN_BCM).encode()) 277 | GPIO.cleanup() 278 | 279 | GPIO.setmode(GPIO.BOARD) 280 | GPIO.setwarnings(True) 281 | with open('/sys/class/gpio/export','wb') as f: 282 | f.write(str(LED_PIN_BCM).encode()) 283 | with open('/sys/class/gpio/gpio%s/direction'%LED_PIN_BCM,'wb') as f: 284 | f.write(b'out') 285 | with open('/sys/class/gpio/gpio%s/value'%LED_PIN_BCM,'wb') as f: 286 | f.write(b'1') 287 | with warnings.catch_warnings(record=True) as w: 288 | GPIO.setup(LED_PIN, GPIO.OUT) # generate 'already in use' warning 289 | self.assertEqual(w[0].category, RuntimeWarning) 290 | with open('/sys/class/gpio/unexport','wb') as f: 291 | f.write(str(LED_PIN_BCM).encode()) 292 | GPIO.cleanup() 293 | 294 | def test_cleanupwarning(self): 295 | """Test initial GPIO.cleanup() produces warning""" 296 | GPIO.setwarnings(False) 297 | GPIO.setmode(GPIO.BOARD) 298 | GPIO.setup(SWITCH_PIN, GPIO.IN) 299 | with warnings.catch_warnings(record=True) as w: 300 | GPIO.cleanup() 301 | self.assertEqual(len(w),0) # no warnings 302 | GPIO.cleanup() 303 | self.assertEqual(len(w),0) # no warnings 304 | 305 | GPIO.setwarnings(True) 306 | GPIO.setmode(GPIO.BOARD) 307 | GPIO.setup(SWITCH_PIN, GPIO.IN) 308 | with warnings.catch_warnings(record=True) as w: 309 | GPIO.cleanup() 310 | self.assertEqual(len(w),0) # no warnings 311 | GPIO.cleanup() 312 | self.assertEqual(w[0].category, RuntimeWarning) # a warning 313 | 314 | class TestVersions(unittest.TestCase): 315 | def test_rpi_info(self): 316 | print 'RPi Board Information' 317 | print '---------------------' 318 | for key,val in GPIO.RPI_INFO.items(): 319 | print '%s => %s'%(key,val) 320 | response = raw_input('\nIs this board info correct (y/n) ? ').upper() 321 | self.assertEqual(response, 'Y') 322 | 323 | def test_gpio_version(self): 324 | response = raw_input('\nRPi.GPIO version %s - is this correct (y/n) ? '%GPIO.VERSION).upper() 325 | self.assertEqual(response, 'Y') 326 | 327 | class TestGPIOFunction(unittest.TestCase): 328 | def runTest(self): 329 | GPIO.setmode(GPIO.BCM) 330 | GPIO.setup(LED_PIN_BCM, GPIO.IN) 331 | self.assertEqual(GPIO.gpio_function(LED_PIN_BCM), GPIO.IN) 332 | GPIO.setup(LED_PIN_BCM, GPIO.OUT) 333 | self.assertEqual(GPIO.gpio_function(LED_PIN_BCM), GPIO.OUT) 334 | GPIO.cleanup() 335 | 336 | GPIO.setmode(GPIO.BOARD) 337 | GPIO.setup(LED_PIN, GPIO.IN) 338 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) 339 | GPIO.setup(LED_PIN, GPIO.OUT) 340 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 341 | 342 | def tearDown(self): 343 | GPIO.cleanup() 344 | 345 | class TestSwitchBounce(unittest.TestCase): 346 | def __init__(self, *a, **k): 347 | unittest.TestCase.__init__(self, *a, **k) 348 | self.switchcount = 0 349 | 350 | def cb(self,chan): 351 | self.switchcount += 1 352 | print 'Button press',self.switchcount 353 | 354 | def setUp(self): 355 | GPIO.setmode(GPIO.BOARD) 356 | GPIO.setup(SWITCH_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) 357 | 358 | @unittest.skipIf(non_interactive, 'Non interactive mode') 359 | def test_switchbounce(self): 360 | self.switchcount = 0 361 | print "\nSwitch bounce test. Press switch at least 10 times and count..." 362 | GPIO.add_event_detect(SWITCH_PIN, GPIO.FALLING, callback=self.cb, bouncetime=200) 363 | while self.switchcount < 10: 364 | time.sleep(1) 365 | GPIO.remove_event_detect(SWITCH_PIN) 366 | 367 | @unittest.skipIf(non_interactive, 'Non interactive mode') 368 | def test_event_detected(self): 369 | self.switchcount = 0 370 | print "\nGPIO.event_detected() switch bounce test. Press switch at least 10 times and count..." 371 | GPIO.add_event_detect(SWITCH_PIN, GPIO.FALLING, bouncetime=200) 372 | while self.switchcount < 10: 373 | if GPIO.event_detected(SWITCH_PIN): 374 | self.switchcount += 1 375 | print 'Button press',self.switchcount 376 | GPIO.remove_event_detect(SWITCH_PIN) 377 | 378 | def tearDown(self): 379 | GPIO.cleanup() 380 | 381 | class TestEdgeDetection(unittest.TestCase): 382 | def setUp(self): 383 | GPIO.setmode(GPIO.BOARD) 384 | GPIO.setup(LOOP_IN, GPIO.IN) 385 | GPIO.setup(LOOP_OUT, GPIO.OUT) 386 | 387 | def testWaitForEdgeInLoop(self): 388 | def makelow(): 389 | GPIO.output(LOOP_OUT, GPIO.LOW) 390 | 391 | count = 0 392 | timestart = time.time() 393 | GPIO.output(LOOP_OUT, GPIO.HIGH) 394 | while True: 395 | t = Timer(0.1, makelow) 396 | t.start() 397 | GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING) 398 | GPIO.output(LOOP_OUT, GPIO.HIGH) 399 | count += 1 400 | if time.time() - timestart > 5 or count > 150: 401 | break 402 | 403 | def testWaitForEdgeWithCallback(self): 404 | def cb(): 405 | raise Exception("Callback should not be called") 406 | def makehigh(): 407 | GPIO.output(LOOP_OUT, GPIO.HIGH) 408 | 409 | GPIO.output(LOOP_OUT, GPIO.LOW) 410 | t = Timer(0.1, makehigh) 411 | 412 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING) 413 | t.start() 414 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) 415 | 416 | GPIO.output(LOOP_OUT, GPIO.LOW) 417 | GPIO.add_event_callback(LOOP_IN, callback=cb) 418 | with self.assertRaises(RuntimeError): # conflicting edge exception 419 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) 420 | 421 | GPIO.remove_event_detect(LOOP_IN) 422 | 423 | def testWaitForEventSwitchbounce(self): 424 | self.finished = False 425 | def bounce(): 426 | GPIO.output(LOOP_OUT, GPIO.HIGH) 427 | time.sleep(0.01) 428 | GPIO.output(LOOP_OUT, GPIO.LOW) 429 | time.sleep(0.01) 430 | GPIO.output(LOOP_OUT, GPIO.HIGH) 431 | time.sleep(0.01) 432 | GPIO.output(LOOP_OUT, GPIO.LOW) 433 | time.sleep(0.2) 434 | GPIO.output(LOOP_OUT, GPIO.HIGH) 435 | time.sleep(0.01) 436 | GPIO.output(LOOP_OUT, GPIO.LOW) 437 | time.sleep(0.01) 438 | GPIO.output(LOOP_OUT, GPIO.HIGH) 439 | time.sleep(0.01) 440 | GPIO.output(LOOP_OUT, GPIO.LOW) 441 | self.finished = True 442 | 443 | GPIO.output(LOOP_OUT, GPIO.LOW) 444 | t1 = Timer(0.1, bounce) 445 | t1.start() 446 | 447 | starttime = time.time() 448 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=100) 449 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=100) 450 | finishtime = time.time() 451 | self.assertGreater(finishtime-starttime, 0.2) 452 | while not self.finished: 453 | time.sleep(0.1) 454 | 455 | def testInvalidBouncetime(self): 456 | with self.assertRaises(ValueError): 457 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING, bouncetime=-1) 458 | with self.assertRaises(ValueError): 459 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=-1) 460 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING, bouncetime=123) 461 | with self.assertRaises(RuntimeError): 462 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=321) 463 | GPIO.remove_event_detect(LOOP_IN) 464 | 465 | def testAlreadyAdded(self): 466 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING) 467 | with self.assertRaises(RuntimeError): 468 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING) 469 | GPIO.remove_event_detect(LOOP_IN) 470 | 471 | def testHighLowEvent(self): 472 | with self.assertRaises(ValueError): 473 | GPIO.add_event_detect(LOOP_IN, GPIO.LOW) 474 | with self.assertRaises(ValueError): 475 | GPIO.add_event_detect(LOOP_IN, GPIO.HIGH) 476 | 477 | def testFallingEventDetected(self): 478 | GPIO.output(LOOP_OUT, GPIO.HIGH) 479 | GPIO.add_event_detect(LOOP_IN, GPIO.FALLING) 480 | time.sleep(0.01) 481 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 482 | GPIO.output(LOOP_OUT, GPIO.LOW) 483 | time.sleep(0.01) 484 | self.assertEqual(GPIO.event_detected(LOOP_IN), True) 485 | GPIO.output(LOOP_OUT, GPIO.HIGH) 486 | time.sleep(0.01) 487 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 488 | GPIO.remove_event_detect(LOOP_IN) 489 | 490 | def testRisingEventDetected(self): 491 | GPIO.output(LOOP_OUT, GPIO.LOW) 492 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING) 493 | time.sleep(0.01) 494 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 495 | GPIO.output(LOOP_OUT, GPIO.HIGH) 496 | time.sleep(0.01) 497 | self.assertEqual(GPIO.event_detected(LOOP_IN), True) 498 | GPIO.output(LOOP_OUT, GPIO.LOW) 499 | time.sleep(0.01) 500 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 501 | GPIO.remove_event_detect(LOOP_IN) 502 | 503 | def testBothEventDetected(self): 504 | GPIO.output(LOOP_OUT, GPIO.LOW) 505 | GPIO.add_event_detect(LOOP_IN, GPIO.BOTH) 506 | time.sleep(0.01) 507 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 508 | GPIO.output(LOOP_OUT, GPIO.HIGH) 509 | time.sleep(0.01) 510 | self.assertEqual(GPIO.event_detected(LOOP_IN), True) 511 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 512 | GPIO.output(LOOP_OUT, GPIO.LOW) 513 | time.sleep(0.01) 514 | self.assertEqual(GPIO.event_detected(LOOP_IN), True) 515 | GPIO.remove_event_detect(LOOP_IN) 516 | 517 | def testWaitForRising(self): 518 | def makehigh(): 519 | GPIO.output(LOOP_OUT, GPIO.HIGH) 520 | GPIO.output(LOOP_OUT, GPIO.LOW) 521 | t = Timer(0.1, makehigh) 522 | t.start() 523 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) 524 | 525 | def testWaitForFalling(self): 526 | def makelow(): 527 | GPIO.output(LOOP_OUT, GPIO.LOW) 528 | GPIO.output(LOOP_OUT, GPIO.HIGH) 529 | t = Timer(0.1, makelow) 530 | t.start() 531 | GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING) 532 | 533 | def testExceptionInCallback(self): 534 | self.run_cb = False 535 | def cb(channel): 536 | with self.assertRaises(ZeroDivisionError): 537 | self.run_cb = True 538 | a = 1/0 539 | GPIO.output(LOOP_OUT, GPIO.LOW) 540 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING, callback=cb) 541 | time.sleep(0.01) 542 | GPIO.output(LOOP_OUT, GPIO.HIGH) 543 | time.sleep(0.01) 544 | self.assertEqual(self.run_cb, True) 545 | GPIO.remove_event_detect(LOOP_IN) 546 | 547 | def testAddEventCallback(self): 548 | def cb(channel): 549 | self.callback_count += 1 550 | 551 | # falling test 552 | self.callback_count = 0 553 | GPIO.output(LOOP_OUT, GPIO.HIGH) 554 | GPIO.add_event_detect(LOOP_IN, GPIO.FALLING) 555 | GPIO.add_event_callback(LOOP_IN, cb) 556 | time.sleep(0.01) 557 | for i in range(2048): 558 | GPIO.output(LOOP_OUT, GPIO.LOW) 559 | time.sleep(0.001) 560 | GPIO.output(LOOP_OUT, GPIO.HIGH) 561 | time.sleep(0.001) 562 | GPIO.remove_event_detect(LOOP_IN) 563 | self.assertEqual(self.callback_count, 2048) 564 | 565 | # rising test 566 | self.callback_count = 0 567 | GPIO.output(LOOP_OUT, GPIO.LOW) 568 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING, callback=cb) 569 | time.sleep(0.01) 570 | for i in range(2048): 571 | GPIO.output(LOOP_OUT, GPIO.HIGH) 572 | time.sleep(0.001) 573 | GPIO.output(LOOP_OUT, GPIO.LOW) 574 | time.sleep(0.001) 575 | GPIO.remove_event_detect(LOOP_IN) 576 | self.assertEqual(self.callback_count, 2048) 577 | 578 | # both test 579 | self.callback_count = 0 580 | GPIO.output(LOOP_OUT, GPIO.LOW) 581 | GPIO.add_event_detect(LOOP_IN, GPIO.BOTH, callback=cb) 582 | time.sleep(0.01) 583 | for i in range(2048): 584 | GPIO.output(LOOP_OUT, GPIO.HIGH) 585 | time.sleep(0.001) 586 | GPIO.output(LOOP_OUT, GPIO.LOW) 587 | time.sleep(0.001) 588 | GPIO.remove_event_detect(LOOP_IN) 589 | self.assertEqual(self.callback_count, 4096) 590 | 591 | def testEventOnOutput(self): 592 | with self.assertRaises(RuntimeError): 593 | GPIO.add_event_detect(LOOP_OUT, GPIO.FALLING) 594 | 595 | def testAlternateWaitForEdge(self): 596 | def makehigh(): 597 | GPIO.output(LOOP_OUT, GPIO.HIGH) 598 | def makelow(): 599 | GPIO.output(LOOP_OUT, GPIO.LOW) 600 | GPIO.output(LOOP_OUT, GPIO.LOW) 601 | t = Timer(0.1, makehigh) 602 | t2 = Timer(0.15, makelow) 603 | t.start() 604 | t2.start() 605 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) 606 | GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING) 607 | 608 | def tearDown(self): 609 | GPIO.cleanup() 610 | 611 | class TestCleanup(unittest.TestCase): 612 | def setUp(self): 613 | GPIO.setmode(GPIO.BOARD) 614 | 615 | def test_cleanall(self): 616 | GPIO.setup(LOOP_OUT, GPIO.OUT) 617 | GPIO.setup(LED_PIN, GPIO.OUT) 618 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) 619 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 620 | GPIO.cleanup() 621 | GPIO.setmode(GPIO.BOARD) 622 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 623 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) 624 | 625 | def test_cleanone(self): 626 | GPIO.setup(LOOP_OUT, GPIO.OUT) 627 | GPIO.setup(LED_PIN, GPIO.OUT) 628 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) 629 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 630 | GPIO.cleanup(LOOP_OUT) 631 | GPIO.setmode(GPIO.BOARD) 632 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 633 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 634 | GPIO.cleanup(LED_PIN) 635 | GPIO.setmode(GPIO.BOARD) 636 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 637 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) 638 | 639 | def test_cleantuple(self): 640 | GPIO.setup(LOOP_OUT, GPIO.OUT) 641 | GPIO.setup(LED_PIN, GPIO.OUT) 642 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) 643 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 644 | GPIO.cleanup((LOOP_OUT,)) 645 | GPIO.setmode(GPIO.BOARD) 646 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 647 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 648 | GPIO.cleanup((LED_PIN,)) 649 | GPIO.setmode(GPIO.BOARD) 650 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 651 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) 652 | GPIO.setup(LOOP_OUT, GPIO.OUT) 653 | GPIO.setup(LED_PIN, GPIO.OUT) 654 | GPIO.cleanup((LOOP_OUT,LED_PIN)) 655 | GPIO.setmode(GPIO.BOARD) 656 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 657 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) 658 | 659 | def test_cleanlist(self): 660 | GPIO.setup(LOOP_OUT, GPIO.OUT) 661 | GPIO.setup(LED_PIN, GPIO.OUT) 662 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) 663 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 664 | GPIO.cleanup([LOOP_OUT]) 665 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 666 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 667 | GPIO.cleanup([LED_PIN]) 668 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 669 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) 670 | GPIO.setup(LOOP_OUT, GPIO.OUT) 671 | GPIO.setup(LED_PIN, GPIO.OUT) 672 | GPIO.cleanup([LOOP_OUT,LED_PIN]) 673 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 674 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) 675 | 676 | if __name__ == '__main__': 677 | unittest.main() 678 | -------------------------------------------------------------------------------- /test/test3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | """ 3 | Copyright (c) 2013-2015 Ben Croston 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | """ 23 | 24 | """This test suite assumes the following circuit is connected: 25 | GND_PIN = 6 26 | LED_PIN = 12 (with resistor to 0v) 27 | SWITCH_PIN = 18 (with 0.1 uF capacitor around switch) to 0v 28 | LOOP_IN = 16 connected with 1K resistor to LOOP_OUT 29 | LOOP_OUT = 22 30 | """ 31 | 32 | import sys 33 | import warnings 34 | import time 35 | from threading import Timer 36 | import RPi.GPIO as GPIO 37 | if sys.version[:3] == '2.6': 38 | import unittest2 as unittest 39 | else: 40 | import unittest 41 | 42 | GND_PIN = 6 43 | LED_PIN = 12 44 | LED_PIN_BCM = 18 45 | SWITCH_PIN = 18 46 | LOOP_IN = 16 47 | LOOP_OUT = 22 48 | 49 | non_interactive = False 50 | for i,val in enumerate(sys.argv): 51 | if val == '--non_interactive': 52 | non_interactive = True 53 | sys.argv.pop(i) 54 | 55 | # Test starts with 'AAA' so that it is run first 56 | class TestAAASetup(unittest.TestCase): 57 | def runTest(self): 58 | # Test mode not set (BOARD or BCM) exception 59 | with self.assertRaises(RuntimeError) as e: 60 | GPIO.setup(LED_PIN, GPIO.OUT) 61 | self.assertEqual(str(e.exception), 'Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)') 62 | 63 | # Test trying to change mode after it has been set 64 | GPIO.setmode(GPIO.BCM) 65 | with self.assertRaises(ValueError) as e: 66 | GPIO.setmode(GPIO.BOARD) 67 | GPIO.setup(LED_PIN_BCM, GPIO.IN) 68 | GPIO.cleanup() 69 | 70 | # Test getmode() 71 | self.assertEqual(GPIO.getmode(), GPIO.UNKNOWN) 72 | GPIO.setmode(GPIO.BCM) 73 | self.assertEqual(GPIO.getmode(), GPIO.BCM) 74 | GPIO.setup(LED_PIN_BCM, GPIO.IN) 75 | GPIO.cleanup() 76 | GPIO.setmode(GPIO.BOARD) 77 | self.assertEqual(GPIO.getmode(), GPIO.BOARD) 78 | 79 | # Test not set as OUTPUT message 80 | GPIO.setmode(GPIO.BOARD) 81 | with self.assertRaises(RuntimeError) as e: 82 | GPIO.output(LED_PIN, GPIO.HIGH) 83 | self.assertEqual(str(e.exception), 'The GPIO channel has not been set up as an OUTPUT') 84 | 85 | # Test setup(..., pull_up_down=GPIO.HIGH) raises exception 86 | GPIO.setmode(GPIO.BOARD) 87 | with self.assertRaises(ValueError): 88 | GPIO.setup(LED_PIN, GPIO.IN, pull_up_down=GPIO.HIGH) 89 | 90 | # Test not valid on a raspi exception 91 | GPIO.setmode(GPIO.BOARD) 92 | with self.assertRaises(ValueError) as e: 93 | GPIO.setup(GND_PIN, GPIO.OUT) 94 | self.assertEqual(str(e.exception), 'The channel sent is invalid on a Raspberry Pi') 95 | 96 | # Test 'already in use' warning 97 | GPIO.setmode(GPIO.BOARD) 98 | with open('/sys/class/gpio/export','wb') as f: 99 | f.write(str(LED_PIN_BCM).encode()) 100 | with open('/sys/class/gpio/gpio%s/direction'%LED_PIN_BCM,'wb') as f: 101 | f.write(b'out') 102 | with open('/sys/class/gpio/gpio%s/value'%LED_PIN_BCM,'wb') as f: 103 | f.write(b'1') 104 | time.sleep(0.2) 105 | with warnings.catch_warnings(record=True) as w: 106 | GPIO.setup(LED_PIN, GPIO.OUT) # generate 'already in use' warning 107 | self.assertEqual(w[0].category, RuntimeWarning) 108 | with open('/sys/class/gpio/unexport','wb') as f: 109 | f.write(str(LED_PIN_BCM).encode()) 110 | GPIO.cleanup() 111 | 112 | # test initial value of high reads back as high 113 | GPIO.setmode(GPIO.BOARD) 114 | GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.HIGH) 115 | self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) 116 | GPIO.cleanup() 117 | 118 | # test initial value of low reads back as low 119 | GPIO.setmode(GPIO.BOARD) 120 | GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.LOW) 121 | self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) 122 | GPIO.cleanup() 123 | 124 | # test setup of a list of channels 125 | GPIO.setmode(GPIO.BOARD) 126 | GPIO.setup( [LED_PIN, LOOP_OUT], GPIO.OUT) 127 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 128 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) 129 | GPIO.cleanup() 130 | GPIO.setmode(GPIO.BOARD) 131 | with self.assertRaises(ValueError) as e: 132 | GPIO.setup( [LED_PIN, GND_PIN], GPIO.OUT) 133 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 134 | self.assertEqual(str(e.exception), 'The channel sent is invalid on a Raspberry Pi') 135 | GPIO.cleanup() 136 | 137 | # test setup of a tuple of channels 138 | GPIO.setmode(GPIO.BOARD) 139 | GPIO.setup( (LED_PIN, LOOP_OUT), GPIO.OUT) 140 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 141 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) 142 | GPIO.cleanup() 143 | 144 | # test warning when using pull up/down on i2c channels 145 | GPIO.setmode(GPIO.BOARD) 146 | if GPIO.RPI_INFO['P1_REVISION'] == 0: # compute module 147 | pass # test not vailid 148 | else: # revision 1, 2 or A+/B+ 149 | with warnings.catch_warnings(record=True) as w: 150 | GPIO.setup(3, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 151 | self.assertEqual(w[0].category, RuntimeWarning) 152 | with warnings.catch_warnings(record=True) as w: 153 | GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 154 | self.assertEqual(w[0].category, RuntimeWarning) 155 | GPIO.cleanup() 156 | 157 | # test non integer channel 158 | GPIO.setmode(GPIO.BOARD) 159 | with self.assertRaises(ValueError): 160 | GPIO.setup('d', GPIO.OUT) 161 | with self.assertRaises(ValueError): 162 | GPIO.setup(('d',LED_PIN), GPIO.OUT) 163 | 164 | class TestInputOutput(unittest.TestCase): 165 | def setUp(self): 166 | GPIO.setmode(GPIO.BOARD) 167 | 168 | def test_outputread(self): 169 | """Test that an output() can be input()""" 170 | GPIO.setup(LED_PIN, GPIO.OUT) 171 | GPIO.output(LED_PIN, GPIO.HIGH) 172 | self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) 173 | GPIO.output(LED_PIN, GPIO.LOW) 174 | self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) 175 | 176 | def test_loopback(self): 177 | """Test output loops back to another input""" 178 | GPIO.setup(LOOP_IN, GPIO.IN, pull_up_down=GPIO.PUD_OFF) 179 | GPIO.setup(LOOP_OUT, GPIO.OUT, initial=GPIO.LOW) 180 | self.assertEqual(GPIO.input(LOOP_IN), GPIO.LOW) 181 | GPIO.output(LOOP_OUT, GPIO.HIGH) 182 | self.assertEqual(GPIO.input(LOOP_IN), GPIO.HIGH) 183 | 184 | def test_output_on_input(self): 185 | """Test output() can not be done on input""" 186 | GPIO.setup(SWITCH_PIN, GPIO.IN) 187 | with self.assertRaises(RuntimeError): 188 | GPIO.output(SWITCH_PIN, GPIO.LOW) 189 | 190 | def test_output_list(self): 191 | """Test output() using lists""" 192 | GPIO.setup(LOOP_OUT, GPIO.OUT) 193 | GPIO.setup(LED_PIN, GPIO.OUT) 194 | 195 | GPIO.output( [LOOP_OUT, LED_PIN], GPIO.HIGH) 196 | self.assertEqual(GPIO.input(LOOP_OUT), GPIO.HIGH) 197 | self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) 198 | 199 | GPIO.output( (LOOP_OUT, LED_PIN), GPIO.LOW) 200 | self.assertEqual(GPIO.input(LOOP_OUT), GPIO.LOW) 201 | self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) 202 | 203 | GPIO.output( [LOOP_OUT, LED_PIN], [GPIO.HIGH, GPIO.LOW] ) 204 | self.assertEqual(GPIO.input(LOOP_OUT), GPIO.HIGH) 205 | self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) 206 | 207 | GPIO.output( (LOOP_OUT, LED_PIN), (GPIO.LOW, GPIO.HIGH) ) 208 | self.assertEqual(GPIO.input(LOOP_OUT), GPIO.LOW) 209 | self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) 210 | 211 | with self.assertRaises(RuntimeError): 212 | GPIO.output( [LOOP_OUT, LED_PIN], [0,0,0] ) 213 | 214 | with self.assertRaises(RuntimeError): 215 | GPIO.output( [LOOP_OUT, LED_PIN], (0,) ) 216 | 217 | with self.assertRaises(RuntimeError): 218 | GPIO.output(LOOP_OUT, (0,0)) 219 | 220 | with self.assertRaises(ValueError): 221 | GPIO.output( [LOOP_OUT, 'x'], (0,0) ) 222 | 223 | with self.assertRaises(ValueError): 224 | GPIO.output( [LOOP_OUT, LED_PIN], (0,'x') ) 225 | 226 | with self.assertRaises(ValueError): 227 | GPIO.output( [LOOP_OUT, GND_PIN], (0,0) ) 228 | 229 | with self.assertRaises(RuntimeError): 230 | GPIO.output( [LOOP_OUT, LOOP_IN], (0,0) ) 231 | 232 | def tearDown(self): 233 | GPIO.cleanup() 234 | 235 | class TestSoftPWM(unittest.TestCase): 236 | @unittest.skipIf(non_interactive, 'Non interactive mode') 237 | def runTest(self): 238 | GPIO.setmode(GPIO.BOARD) 239 | GPIO.setup(LED_PIN, GPIO.OUT) 240 | pwm = GPIO.PWM(LED_PIN, 50) 241 | pwm.start(100) 242 | print("\nPWM tests") 243 | response = input('Is the LED on (y/n) ? ').upper() 244 | self.assertEqual(response,'Y') 245 | pwm.start(0) 246 | response = input('Is the LED off (y/n) ? ').upper() 247 | self.assertEqual(response,'Y') 248 | print("LED Brighten/fade test...") 249 | for i in range(0,3): 250 | for x in range(0,101,5): 251 | pwm.ChangeDutyCycle(x) 252 | time.sleep(0.1) 253 | for x in range(100,-1,-5): 254 | pwm.ChangeDutyCycle(x) 255 | time.sleep(0.1) 256 | pwm.stop() 257 | response = input('Did it work (y/n) ? ').upper() 258 | self.assertEqual(response,'Y') 259 | GPIO.cleanup() 260 | 261 | class TestSetWarnings(unittest.TestCase): 262 | def test_alreadyinuse(self): 263 | """Test 'already in use' warning""" 264 | GPIO.setmode(GPIO.BOARD) 265 | GPIO.setwarnings(False) 266 | with open('/sys/class/gpio/export','wb') as f: 267 | f.write(str(LED_PIN_BCM).encode()) 268 | with open('/sys/class/gpio/gpio%s/direction'%LED_PIN_BCM,'wb') as f: 269 | f.write(b'out') 270 | with open('/sys/class/gpio/gpio%s/value'%LED_PIN_BCM,'wb') as f: 271 | f.write(b'1') 272 | with warnings.catch_warnings(record=True) as w: 273 | GPIO.setup(LED_PIN, GPIO.OUT) # generate 'already in use' warning 274 | self.assertEqual(len(w),0) # should be no warnings 275 | with open('/sys/class/gpio/unexport','wb') as f: 276 | f.write(str(LED_PIN_BCM).encode()) 277 | GPIO.cleanup() 278 | 279 | GPIO.setmode(GPIO.BOARD) 280 | GPIO.setwarnings(True) 281 | with open('/sys/class/gpio/export','wb') as f: 282 | f.write(str(LED_PIN_BCM).encode()) 283 | with open('/sys/class/gpio/gpio%s/direction'%LED_PIN_BCM,'wb') as f: 284 | f.write(b'out') 285 | with open('/sys/class/gpio/gpio%s/value'%LED_PIN_BCM,'wb') as f: 286 | f.write(b'1') 287 | with warnings.catch_warnings(record=True) as w: 288 | GPIO.setup(LED_PIN, GPIO.OUT) # generate 'already in use' warning 289 | self.assertEqual(w[0].category, RuntimeWarning) 290 | with open('/sys/class/gpio/unexport','wb') as f: 291 | f.write(str(LED_PIN_BCM).encode()) 292 | GPIO.cleanup() 293 | 294 | def test_cleanupwarning(self): 295 | """Test initial GPIO.cleanup() produces warning""" 296 | GPIO.setwarnings(False) 297 | GPIO.setmode(GPIO.BOARD) 298 | GPIO.setup(SWITCH_PIN, GPIO.IN) 299 | with warnings.catch_warnings(record=True) as w: 300 | GPIO.cleanup() 301 | self.assertEqual(len(w),0) # no warnings 302 | GPIO.cleanup() 303 | self.assertEqual(len(w),0) # no warnings 304 | 305 | GPIO.setwarnings(True) 306 | GPIO.setmode(GPIO.BOARD) 307 | GPIO.setup(SWITCH_PIN, GPIO.IN) 308 | with warnings.catch_warnings(record=True) as w: 309 | GPIO.cleanup() 310 | self.assertEqual(len(w),0) # no warnings 311 | GPIO.cleanup() 312 | self.assertEqual(w[0].category, RuntimeWarning) # a warning 313 | 314 | class TestVersions(unittest.TestCase): 315 | def test_rpi_info(self): 316 | print('RPi Board Information') 317 | print('---------------------') 318 | for key,val in list(GPIO.RPI_INFO.items()): 319 | print('%s => %s'%(key,val)) 320 | response = input('\nIs this board info correct (y/n) ? ').upper() 321 | self.assertEqual(response, 'Y') 322 | 323 | def test_gpio_version(self): 324 | response = input('\nRPi.GPIO version %s - is this correct (y/n) ? '%GPIO.VERSION).upper() 325 | self.assertEqual(response, 'Y') 326 | 327 | class TestGPIOFunction(unittest.TestCase): 328 | def runTest(self): 329 | GPIO.setmode(GPIO.BCM) 330 | GPIO.setup(LED_PIN_BCM, GPIO.IN) 331 | self.assertEqual(GPIO.gpio_function(LED_PIN_BCM), GPIO.IN) 332 | GPIO.setup(LED_PIN_BCM, GPIO.OUT) 333 | self.assertEqual(GPIO.gpio_function(LED_PIN_BCM), GPIO.OUT) 334 | GPIO.cleanup() 335 | 336 | GPIO.setmode(GPIO.BOARD) 337 | GPIO.setup(LED_PIN, GPIO.IN) 338 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) 339 | GPIO.setup(LED_PIN, GPIO.OUT) 340 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 341 | 342 | def tearDown(self): 343 | GPIO.cleanup() 344 | 345 | class TestSwitchBounce(unittest.TestCase): 346 | def __init__(self, *a, **k): 347 | unittest.TestCase.__init__(self, *a, **k) 348 | self.switchcount = 0 349 | 350 | def cb(self,chan): 351 | self.switchcount += 1 352 | print('Button press',self.switchcount) 353 | 354 | def setUp(self): 355 | GPIO.setmode(GPIO.BOARD) 356 | GPIO.setup(SWITCH_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) 357 | 358 | @unittest.skipIf(non_interactive, 'Non interactive mode') 359 | def test_switchbounce(self): 360 | self.switchcount = 0 361 | print("\nSwitch bounce test. Press switch at least 10 times and count...") 362 | GPIO.add_event_detect(SWITCH_PIN, GPIO.FALLING, callback=self.cb, bouncetime=200) 363 | while self.switchcount < 10: 364 | time.sleep(1) 365 | GPIO.remove_event_detect(SWITCH_PIN) 366 | 367 | @unittest.skipIf(non_interactive, 'Non interactive mode') 368 | def test_event_detected(self): 369 | self.switchcount = 0 370 | print("\nGPIO.event_detected() switch bounce test. Press switch at least 10 times and count...") 371 | GPIO.add_event_detect(SWITCH_PIN, GPIO.FALLING, bouncetime=200) 372 | while self.switchcount < 10: 373 | if GPIO.event_detected(SWITCH_PIN): 374 | self.switchcount += 1 375 | print('Button press',self.switchcount) 376 | GPIO.remove_event_detect(SWITCH_PIN) 377 | 378 | def tearDown(self): 379 | GPIO.cleanup() 380 | 381 | class TestEdgeDetection(unittest.TestCase): 382 | def setUp(self): 383 | GPIO.setmode(GPIO.BOARD) 384 | GPIO.setup(LOOP_IN, GPIO.IN) 385 | GPIO.setup(LOOP_OUT, GPIO.OUT) 386 | 387 | def testWaitForEdgeInLoop(self): 388 | def makelow(): 389 | GPIO.output(LOOP_OUT, GPIO.LOW) 390 | 391 | count = 0 392 | timestart = time.time() 393 | GPIO.output(LOOP_OUT, GPIO.HIGH) 394 | while True: 395 | t = Timer(0.1, makelow) 396 | t.start() 397 | GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING) 398 | GPIO.output(LOOP_OUT, GPIO.HIGH) 399 | count += 1 400 | if time.time() - timestart > 5 or count > 150: 401 | break 402 | 403 | def testWaitForEdgeWithCallback(self): 404 | def cb(): 405 | raise Exception("Callback should not be called") 406 | def makehigh(): 407 | GPIO.output(LOOP_OUT, GPIO.HIGH) 408 | 409 | GPIO.output(LOOP_OUT, GPIO.LOW) 410 | t = Timer(0.1, makehigh) 411 | 412 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING) 413 | t.start() 414 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) 415 | 416 | GPIO.output(LOOP_OUT, GPIO.LOW) 417 | GPIO.add_event_callback(LOOP_IN, callback=cb) 418 | with self.assertRaises(RuntimeError): # conflicting edge exception 419 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) 420 | 421 | GPIO.remove_event_detect(LOOP_IN) 422 | 423 | def testWaitForEventSwitchbounce(self): 424 | self.finished = False 425 | def bounce(): 426 | GPIO.output(LOOP_OUT, GPIO.HIGH) 427 | time.sleep(0.01) 428 | GPIO.output(LOOP_OUT, GPIO.LOW) 429 | time.sleep(0.01) 430 | GPIO.output(LOOP_OUT, GPIO.HIGH) 431 | time.sleep(0.01) 432 | GPIO.output(LOOP_OUT, GPIO.LOW) 433 | time.sleep(0.2) 434 | GPIO.output(LOOP_OUT, GPIO.HIGH) 435 | time.sleep(0.01) 436 | GPIO.output(LOOP_OUT, GPIO.LOW) 437 | time.sleep(0.01) 438 | GPIO.output(LOOP_OUT, GPIO.HIGH) 439 | time.sleep(0.01) 440 | GPIO.output(LOOP_OUT, GPIO.LOW) 441 | self.finished = True 442 | 443 | GPIO.output(LOOP_OUT, GPIO.LOW) 444 | t1 = Timer(0.1, bounce) 445 | t1.start() 446 | 447 | starttime = time.time() 448 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=100) 449 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=100) 450 | finishtime = time.time() 451 | self.assertGreater(finishtime-starttime, 0.2) 452 | while not self.finished: 453 | time.sleep(0.1) 454 | 455 | def testInvalidBouncetime(self): 456 | with self.assertRaises(ValueError): 457 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING, bouncetime=-1) 458 | with self.assertRaises(ValueError): 459 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=-1) 460 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING, bouncetime=123) 461 | with self.assertRaises(RuntimeError): 462 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=321) 463 | GPIO.remove_event_detect(LOOP_IN) 464 | 465 | def testAlreadyAdded(self): 466 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING) 467 | with self.assertRaises(RuntimeError): 468 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING) 469 | GPIO.remove_event_detect(LOOP_IN) 470 | 471 | def testHighLowEvent(self): 472 | with self.assertRaises(ValueError): 473 | GPIO.add_event_detect(LOOP_IN, GPIO.LOW) 474 | with self.assertRaises(ValueError): 475 | GPIO.add_event_detect(LOOP_IN, GPIO.HIGH) 476 | 477 | def testFallingEventDetected(self): 478 | GPIO.output(LOOP_OUT, GPIO.HIGH) 479 | GPIO.add_event_detect(LOOP_IN, GPIO.FALLING) 480 | time.sleep(0.01) 481 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 482 | GPIO.output(LOOP_OUT, GPIO.LOW) 483 | time.sleep(0.01) 484 | self.assertEqual(GPIO.event_detected(LOOP_IN), True) 485 | GPIO.output(LOOP_OUT, GPIO.HIGH) 486 | time.sleep(0.01) 487 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 488 | GPIO.remove_event_detect(LOOP_IN) 489 | 490 | def testRisingEventDetected(self): 491 | GPIO.output(LOOP_OUT, GPIO.LOW) 492 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING) 493 | time.sleep(0.01) 494 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 495 | GPIO.output(LOOP_OUT, GPIO.HIGH) 496 | time.sleep(0.01) 497 | self.assertEqual(GPIO.event_detected(LOOP_IN), True) 498 | GPIO.output(LOOP_OUT, GPIO.LOW) 499 | time.sleep(0.01) 500 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 501 | GPIO.remove_event_detect(LOOP_IN) 502 | 503 | def testBothEventDetected(self): 504 | GPIO.output(LOOP_OUT, GPIO.LOW) 505 | GPIO.add_event_detect(LOOP_IN, GPIO.BOTH) 506 | time.sleep(0.01) 507 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 508 | GPIO.output(LOOP_OUT, GPIO.HIGH) 509 | time.sleep(0.01) 510 | self.assertEqual(GPIO.event_detected(LOOP_IN), True) 511 | self.assertEqual(GPIO.event_detected(LOOP_IN), False) 512 | GPIO.output(LOOP_OUT, GPIO.LOW) 513 | time.sleep(0.01) 514 | self.assertEqual(GPIO.event_detected(LOOP_IN), True) 515 | GPIO.remove_event_detect(LOOP_IN) 516 | 517 | def testWaitForRising(self): 518 | def makehigh(): 519 | GPIO.output(LOOP_OUT, GPIO.HIGH) 520 | GPIO.output(LOOP_OUT, GPIO.LOW) 521 | t = Timer(0.1, makehigh) 522 | t.start() 523 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) 524 | 525 | def testWaitForFalling(self): 526 | def makelow(): 527 | GPIO.output(LOOP_OUT, GPIO.LOW) 528 | GPIO.output(LOOP_OUT, GPIO.HIGH) 529 | t = Timer(0.1, makelow) 530 | t.start() 531 | GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING) 532 | 533 | def testExceptionInCallback(self): 534 | self.run_cb = False 535 | def cb(channel): 536 | with self.assertRaises(ZeroDivisionError): 537 | self.run_cb = True 538 | a = 1/0 539 | GPIO.output(LOOP_OUT, GPIO.LOW) 540 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING, callback=cb) 541 | time.sleep(0.01) 542 | GPIO.output(LOOP_OUT, GPIO.HIGH) 543 | time.sleep(0.01) 544 | self.assertEqual(self.run_cb, True) 545 | GPIO.remove_event_detect(LOOP_IN) 546 | 547 | def testAddEventCallback(self): 548 | def cb(channel): 549 | self.callback_count += 1 550 | 551 | # falling test 552 | self.callback_count = 0 553 | GPIO.output(LOOP_OUT, GPIO.HIGH) 554 | GPIO.add_event_detect(LOOP_IN, GPIO.FALLING) 555 | GPIO.add_event_callback(LOOP_IN, cb) 556 | time.sleep(0.01) 557 | for i in range(2048): 558 | GPIO.output(LOOP_OUT, GPIO.LOW) 559 | time.sleep(0.001) 560 | GPIO.output(LOOP_OUT, GPIO.HIGH) 561 | time.sleep(0.001) 562 | GPIO.remove_event_detect(LOOP_IN) 563 | self.assertEqual(self.callback_count, 2048) 564 | 565 | # rising test 566 | self.callback_count = 0 567 | GPIO.output(LOOP_OUT, GPIO.LOW) 568 | GPIO.add_event_detect(LOOP_IN, GPIO.RISING, callback=cb) 569 | time.sleep(0.01) 570 | for i in range(2048): 571 | GPIO.output(LOOP_OUT, GPIO.HIGH) 572 | time.sleep(0.001) 573 | GPIO.output(LOOP_OUT, GPIO.LOW) 574 | time.sleep(0.001) 575 | GPIO.remove_event_detect(LOOP_IN) 576 | self.assertEqual(self.callback_count, 2048) 577 | 578 | # both test 579 | self.callback_count = 0 580 | GPIO.output(LOOP_OUT, GPIO.LOW) 581 | GPIO.add_event_detect(LOOP_IN, GPIO.BOTH, callback=cb) 582 | time.sleep(0.01) 583 | for i in range(2048): 584 | GPIO.output(LOOP_OUT, GPIO.HIGH) 585 | time.sleep(0.001) 586 | GPIO.output(LOOP_OUT, GPIO.LOW) 587 | time.sleep(0.001) 588 | GPIO.remove_event_detect(LOOP_IN) 589 | self.assertEqual(self.callback_count, 4096) 590 | 591 | def testEventOnOutput(self): 592 | with self.assertRaises(RuntimeError): 593 | GPIO.add_event_detect(LOOP_OUT, GPIO.FALLING) 594 | 595 | def testAlternateWaitForEdge(self): 596 | def makehigh(): 597 | GPIO.output(LOOP_OUT, GPIO.HIGH) 598 | def makelow(): 599 | GPIO.output(LOOP_OUT, GPIO.LOW) 600 | GPIO.output(LOOP_OUT, GPIO.LOW) 601 | t = Timer(0.1, makehigh) 602 | t2 = Timer(0.15, makelow) 603 | t.start() 604 | t2.start() 605 | GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) 606 | GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING) 607 | 608 | def tearDown(self): 609 | GPIO.cleanup() 610 | 611 | class TestCleanup(unittest.TestCase): 612 | def setUp(self): 613 | GPIO.setmode(GPIO.BOARD) 614 | 615 | def test_cleanall(self): 616 | GPIO.setup(LOOP_OUT, GPIO.OUT) 617 | GPIO.setup(LED_PIN, GPIO.OUT) 618 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) 619 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 620 | GPIO.cleanup() 621 | GPIO.setmode(GPIO.BOARD) 622 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 623 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) 624 | 625 | def test_cleanone(self): 626 | GPIO.setup(LOOP_OUT, GPIO.OUT) 627 | GPIO.setup(LED_PIN, GPIO.OUT) 628 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) 629 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 630 | GPIO.cleanup(LOOP_OUT) 631 | GPIO.setmode(GPIO.BOARD) 632 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 633 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 634 | GPIO.cleanup(LED_PIN) 635 | GPIO.setmode(GPIO.BOARD) 636 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 637 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) 638 | 639 | def test_cleantuple(self): 640 | GPIO.setup(LOOP_OUT, GPIO.OUT) 641 | GPIO.setup(LED_PIN, GPIO.OUT) 642 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) 643 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 644 | GPIO.cleanup((LOOP_OUT,)) 645 | GPIO.setmode(GPIO.BOARD) 646 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 647 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 648 | GPIO.cleanup((LED_PIN,)) 649 | GPIO.setmode(GPIO.BOARD) 650 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 651 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) 652 | GPIO.setup(LOOP_OUT, GPIO.OUT) 653 | GPIO.setup(LED_PIN, GPIO.OUT) 654 | GPIO.cleanup((LOOP_OUT,LED_PIN)) 655 | GPIO.setmode(GPIO.BOARD) 656 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 657 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) 658 | 659 | def test_cleanlist(self): 660 | GPIO.setup(LOOP_OUT, GPIO.OUT) 661 | GPIO.setup(LED_PIN, GPIO.OUT) 662 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) 663 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 664 | GPIO.cleanup([LOOP_OUT]) 665 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 666 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) 667 | GPIO.cleanup([LED_PIN]) 668 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 669 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) 670 | GPIO.setup(LOOP_OUT, GPIO.OUT) 671 | GPIO.setup(LED_PIN, GPIO.OUT) 672 | GPIO.cleanup([LOOP_OUT,LED_PIN]) 673 | self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) 674 | self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) 675 | 676 | if __name__ == '__main__': 677 | unittest.main() 678 | --------------------------------------------------------------------------------