RPi.GPIO-0.6.3/0000755000175000017500000000000013005465261012013 5ustar pipi00000000000000RPi.GPIO-0.6.3/INSTALL.txt0000644000175000017500000000112313005464447013664 0ustar pipi00000000000000If you are using Raspbian, all you need to do to install the latest release is: $ sudo apt-get update $ sudo apt-get install python-rpi.gpio python3-rpi.gpio ------------ If you are not using Raspbian, it is recommended that you install this module using pip: $ sudo pip install RPi.GPIO ------------ If you want to build your own version from this downloaded copy, make sure that you have the Python development source installed first! On Raspbian: $ sudo apt-get install python-dev python3-dev To install the module: $ sudo python setup.py install or $ sudo python3 setup.py install RPi.GPIO-0.6.3/setup.py0000644000175000017500000000446513005464601013533 0ustar pipi00000000000000""" Copyright (c) 2012-2016 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from distutils.core import setup, Extension classifiers = ['Development Status :: 5 - Production/Stable', 'Operating System :: POSIX :: Linux', 'License :: OSI Approved :: MIT License', 'Intended Audience :: Developers', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Topic :: Software Development', 'Topic :: Home Automation', 'Topic :: System :: Hardware'] setup(name = 'RPi.GPIO', version = '0.6.3', author = 'Ben Croston', author_email = 'ben@croston.org', description = 'A module to control Raspberry Pi GPIO channels', long_description = open('README.txt').read() + open('CHANGELOG.txt').read(), license = 'MIT', keywords = 'Raspberry Pi GPIO', url = 'http://sourceforge.net/projects/raspberry-gpio-python/', classifiers = classifiers, packages = ['RPi','RPi.GPIO'], ext_modules = [Extension('RPi._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'])]) RPi.GPIO-0.6.3/LICENCE.txt0000644000175000017500000000204513005464447013624 0ustar pipi00000000000000Copyright (c) 2012-2014 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. RPi.GPIO-0.6.3/PKG-INFO0000644000175000017500000002111513005465261013110 0ustar pipi00000000000000Metadata-Version: 1.1 Name: RPi.GPIO Version: 0.6.3 Summary: A module to control Raspberry Pi GPIO channels Home-page: http://sourceforge.net/projects/raspberry-gpio-python/ Author: Ben Croston Author-email: ben@croston.org License: MIT Description: This package provides a class to control the GPIO on a Raspberry Pi. Note that this module is unsuitable for real-time or timing critical applications. This is because you can not predict when Python will be busy garbage collecting. It also runs under the Linux kernel which is not suitable for real time applications - it is multitasking O/S and another process may be given priority over the CPU, causing jitter in your program. If you are after true real-time performance and predictability, buy yourself an Arduino http://www.arduino.cc ! Note that the current release does not support SPI, I2C, hardware PWM or serial functionality on the RPi yet. This is planned for the near future - watch this space! One-wire functionality is also planned. Although hardware PWM is not available yet, software PWM is available to use on all channels. For examples and documentation, visit http://sourceforge.net/p/raspberry-gpio-python/wiki/Home/ Change Log ========== 0.6.3 ------- - Fix code so it builds under PyPy (Gasper Zejn) - os.system breaks event detection - Matt Kimball (issue 127) 0.6.2 ----- - Rewrote Debian packaging mechanism - RPI_INFO reports Pi 3 - Changed module layout - moved C components to RPi._GPIO 0.6.1 ----- - Update RPI_INFO to detect more board types - Issue 118 - add_event_detect sometimes gives runtime error with unpriv user - Issue 120 - setmode() remembers invalid mode 0.6.0a3 ------- - Now uses /dev/gpiomem if available to avoid being run as root - Fix warnings with pull up/down on pins 3/5 - Correct base address on Pi 2 when devicetree is disabled - caddr_t error on compile (Issue 109) - Error on invalid parameters to setup() (issue 93) - Add timeout parameter to wait_for_edge() (issue 91) 0.5.11 ------ - Fix - pins > 26 missing when using BOARD mode - Add getmode() - Raise exception when a mix of modes is used - GPIO.cleanaup() unsets the current pin mode 0.5.10 ------ - Issue 95 - support RPi 2 boards - Introduce RPI_INFO - Deprecate RPI_REVISION - Issue 97 - fixed docstring for setup() 0.5.9 ----- - Issue 87 - warn about pull up/down on i2c pins - Issue 86/75 - wait_for_edge() bugfix - Issue 84 - recognise RPi properly when using a custom kernel - Issue 90 - cleanup() on a list/tuple of channels 0.5.8 ----- - Allow lists/tuples of channels in GPIO.setup() - GPIO.output() now allows lists/tuples of values - GPIO.wait_for_edge() bug fixes (issue 78) 0.5.7 ----- - Issue 67 - speed up repeated calls to GPIO.wait_for_event() - Added bouncetime keyword to GPIO.wait_for_event() - Added extra edge/interrupt unit tests - GPIO.wait_for_event() can now be mixed with GPIO.add_event_detect() - Improved cleanups of events - Issue 69 resolved 0.5.6 ----- - Issue 68 - support for RPi Model B+ - Fix gpio_function() 0.5.5 ----- - Issue 52 - 'unallocate' a channel - Issue 35 - use switchbounce with GPIO.event_detected() - Refactored events code - Rewrote tests to use unittest mechanism and new test board with loopbacks - Fixed adding events after a GPIO.cleanup() - Issue 64 - misleading /dev/mem permissions error - Issue 59 - name collision with PWM constant and class 0.5.4 ----- - Changed release status (from alpha to full release) - Warn when GPIO.cleanup() used with nothing to clean up (issue 44) - Avoid collisions in constants (e.g. HIGH / RISING / PUD_DOWN) - Accept BOARD numbers in gpio_function (issue 34) - More return values for gpio_function (INPUT, OUTPUT, SPI, I2C, PWM, SERIAL, UNKNOWN) - Tidy up docstrings - Fix /dev/mem access error with gpio_function 0.5.3a ------ - Allow pydoc for non-root users (issue 27) - Fix add_event_detect error when run as daemon (issue 32) - Simplified exception types - Changed from distribute to pip 0.5.2a ------ - Added software PWM (experimental) - Added switch bounce handling to event callbacks - Added channel number parameter to event callbacks (issue 31) - Internal refactoring and code tidy up 0.5.1a ------ - Fixed callbacks for multiple GPIOs (issue 28) 0.5.0a ------ - Added new edge detection events (interrupt handling) - Added add_event_detect() - Added remove_event_detect() - Added add_event_callback() - Added wait_for_edge() - Removed old experimental event functions - Removed set_rising_event() - Removed set_falling_event() - Removed set_high_event() - Removed set_low_event() - Changed event_detected() for new edge detection functionality - input() now returns 0/LOW == False or 1/HIGH == True (integers) instead of False or True (booleans). - Fix error on repeated import (issue 3) - Change SetupException to a RuntimeError so it can be caught on import (issue 25, Chris Hager ) - Improved docstrings of functions 0.4.2a ------ - Fix for installing on Arch Linux (Python 3.3) (issue 20) - Initial value when setting a channel as an output (issue 19) 0.4.1a ------ - Added VERSION - Permit input() of channels set as outputs (Eric Ptak ) 0.4.0a ------ - Added support for Revision 2 boards - Added RPI_REVISION - Added cleanup() function and removed automatic reset functionality on program exit - Added get_function() to read existing GPIO channel functionality (suggestion from Eric Ptak ) - Added set_rising_event() - Added set_falling_event() - Added set_high_event() - Added set_low_event() - Added event_detected() - Added test/test.py - Converted debian to armhf - Fixed C function short_wait() (thanks to Thibault Porteboeuf ) 0.3.1a ------ - Fixed critical bug with swapped high/low state on outputs - Added pull-up / pull-down setup functionality for inputs 0.3.0a ------ - Rewritten as a C extension - Now uses /dev/mem and SoC registers instead of /sys/class/gpio - Faster! - Make call to GPIO.setmode() mandatory - Added GPIO.HIGH and GPIO.LOW constants 0.2.0 ----- - Changed status from alpha to beta - Added setmode() to be able to use BCM GPIO 00.nn channel numbers - Renamed InvalidPinException to InvalidChannelException 0.1.0 ------ - Fixed direction bug - Added MANIFEST.in (to include missing file) - Changed GPIO channel number to pin number - Tested and working! 0.0.3a ------ - Added GPIO table - Refactored - Fixed a few critical bugs - Still completely untested! 0.0.2a ------ - Internal refactoring. Still completely untested! 0.0.1a ------ - First version. Completely untested until I can get hold of a Raspberry Pi! Keywords: Raspberry Pi GPIO Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Operating System :: POSIX :: Linux Classifier: License :: OSI Approved :: MIT License Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development Classifier: Topic :: Home Automation Classifier: Topic :: System :: Hardware RPi.GPIO-0.6.3/create_gpio_user_permissions.py0000644000175000017500000000200613005464447020342 0ustar pipi00000000000000import grp import subprocess def ensure_gpiogroup(): try: grp.getgrnam('gpio') except KeyError: print('GPIO group does not exist - creating...') subprocess.call(['groupadd', '-f', '-r', 'gpio']) subprocess.call(['adduser', 'pi', 'gpio']) # in future, also for groups: # spi # i2c add_udev_rules() def add_udev_rules(): with open('/etc/udev/rules.d/99-gpio.rules','w') as f: f.write("""SUBSYSTEM=="bcm2835-gpiomem", KERNEL=="gpiomem", GROUP="gpio", MODE="0660" SUBSYSTEM=="gpio", KERNEL=="gpiochip*", ACTION=="add", PROGRAM="/bin/sh -c 'chown root:gpio /sys/class/gpio/export /sys/class/gpio/unexport ; chmod 220 /sys/class/gpio/export /sys/class/gpio/unexport'" SUBSYSTEM=="gpio", KERNEL=="gpio*", ACTION=="add", PROGRAM="/bin/sh -c 'chown root:gpio /sys%p/active_low /sys%p/direction /sys%p/edge /sys%p/value ; chmod 660 /sys%p/active_low /sys%p/direction /sys%p/edge /sys%p/value'" """) if __name__ == '__main__': ensure_gpiogroup() RPi.GPIO-0.6.3/test/0000755000175000017500000000000013005465261012772 5ustar pipi00000000000000RPi.GPIO-0.6.3/test/test.py0000644000175000017500000006742013005464450014333 0ustar pipi00000000000000#!/usr/bin/env python2 """ Copyright (c) 2013-2016 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ """This test suite assumes the following circuit is connected: GND_PIN = 6 LED_PIN = 12 (with resistor to 0v) SWITCH_PIN = 18 (with 0.1 uF capacitor around switch) to 0v LOOP_IN = 16 connected with 1K resistor to LOOP_OUT LOOP_OUT = 22 """ import os import subprocess import sys import warnings import time from threading import Timer import RPi.GPIO as GPIO if sys.version[:3] == '2.6': import unittest2 as unittest else: import unittest GND_PIN = 6 LED_PIN = 12 LED_PIN_BCM = 18 SWITCH_PIN = 18 LOOP_IN = 16 LOOP_OUT = 22 non_interactive = False for i,val in enumerate(sys.argv): if val == '--non_interactive': non_interactive = True sys.argv.pop(i) # Test starts with 'AAA' so that it is run first class TestAAASetup(unittest.TestCase): def runTest(self): # Test mode not set (BOARD or BCM) exception with self.assertRaises(RuntimeError) as e: GPIO.setup(LED_PIN, GPIO.OUT) self.assertEqual(str(e.exception), 'Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)') # Test trying to change mode after it has been set GPIO.setmode(GPIO.BCM) with self.assertRaises(ValueError) as e: GPIO.setmode(GPIO.BOARD) GPIO.setup(LED_PIN_BCM, GPIO.IN) GPIO.cleanup() # Test setting an invalid mode with self.assertRaises(ValueError): GPIO.setmode(666) # Test getmode() self.assertEqual(GPIO.getmode(), None) GPIO.setmode(GPIO.BCM) self.assertEqual(GPIO.getmode(), GPIO.BCM) GPIO.setup(LED_PIN_BCM, GPIO.IN) GPIO.cleanup() GPIO.setmode(GPIO.BOARD) self.assertEqual(GPIO.getmode(), GPIO.BOARD) # Test not set as OUTPUT message GPIO.setmode(GPIO.BOARD) with self.assertRaises(RuntimeError) as e: GPIO.output(LED_PIN, GPIO.HIGH) self.assertEqual(str(e.exception), 'The GPIO channel has not been set up as an OUTPUT') # Test setup(..., pull_up_down=GPIO.HIGH) raises exception GPIO.setmode(GPIO.BOARD) with self.assertRaises(ValueError): GPIO.setup(LED_PIN, GPIO.IN, pull_up_down=GPIO.HIGH) # Test not valid on a raspi exception GPIO.setmode(GPIO.BOARD) with self.assertRaises(ValueError) as e: GPIO.setup(GND_PIN, GPIO.OUT) self.assertEqual(str(e.exception), 'The channel sent is invalid on a Raspberry Pi') # Test 'already in use' warning GPIO.setmode(GPIO.BOARD) with open('/sys/class/gpio/export','wb') as f: f.write(str(LED_PIN_BCM).encode()) time.sleep(0.2) # wait for udev to set permissions with open('/sys/class/gpio/gpio%s/direction'%LED_PIN_BCM,'wb') as f: f.write(b'out') time.sleep(0.2) with warnings.catch_warnings(record=True) as w: GPIO.setup(LED_PIN, GPIO.OUT) # generate 'already in use' warning self.assertEqual(w[0].category, RuntimeWarning) with open('/sys/class/gpio/unexport','wb') as f: f.write(str(LED_PIN_BCM).encode()) GPIO.cleanup() # test initial value of high reads back as high GPIO.setmode(GPIO.BOARD) GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.HIGH) self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) GPIO.cleanup() # test initial value of low reads back as low GPIO.setmode(GPIO.BOARD) GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.LOW) self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) GPIO.cleanup() # test setup of a list of channels GPIO.setmode(GPIO.BOARD) GPIO.setup( [LED_PIN, LOOP_OUT], GPIO.OUT) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) GPIO.cleanup() GPIO.setmode(GPIO.BOARD) with self.assertRaises(ValueError) as e: GPIO.setup( [LED_PIN, GND_PIN], GPIO.OUT) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) self.assertEqual(str(e.exception), 'The channel sent is invalid on a Raspberry Pi') GPIO.cleanup() # test setup of a tuple of channels GPIO.setmode(GPIO.BOARD) GPIO.setup( (LED_PIN, LOOP_OUT), GPIO.OUT) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) GPIO.cleanup() # test warning when using pull up/down on i2c channels GPIO.setmode(GPIO.BOARD) if GPIO.RPI_INFO['P1_REVISION'] == 0: # compute module pass # test not vailid else: # revision 1, 2 or A+/B+ with warnings.catch_warnings(record=True) as w: GPIO.setup(3, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) self.assertEqual(w[0].category, RuntimeWarning) with warnings.catch_warnings(record=True) as w: GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) self.assertEqual(w[0].category, RuntimeWarning) GPIO.cleanup() # test non integer channel GPIO.setmode(GPIO.BOARD) with self.assertRaises(ValueError): GPIO.setup('d', GPIO.OUT) with self.assertRaises(ValueError): GPIO.setup(('d',LED_PIN), GPIO.OUT) # test setting pull_up_down on an output GPIO.setmode(GPIO.BOARD) with self.assertRaises(ValueError): GPIO.setup(LOOP_OUT, GPIO.OUT, pull_up_down=GPIO.PUD_DOWN) # test setting initial on an input GPIO.setmode(GPIO.BOARD) with self.assertRaises(ValueError): GPIO.setup(LOOP_IN, GPIO.IN, initial=GPIO.LOW) class TestInputOutput(unittest.TestCase): def setUp(self): GPIO.setmode(GPIO.BOARD) def test_outputread(self): """Test that an output() can be input()""" GPIO.setup(LED_PIN, GPIO.OUT) GPIO.output(LED_PIN, GPIO.HIGH) self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) GPIO.output(LED_PIN, GPIO.LOW) self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) def test_loopback(self): """Test output loops back to another input""" GPIO.setup(LOOP_IN, GPIO.IN, pull_up_down=GPIO.PUD_OFF) GPIO.setup(LOOP_OUT, GPIO.OUT, initial=GPIO.LOW) self.assertEqual(GPIO.input(LOOP_IN), GPIO.LOW) GPIO.output(LOOP_OUT, GPIO.HIGH) self.assertEqual(GPIO.input(LOOP_IN), GPIO.HIGH) def test_output_on_input(self): """Test output() can not be done on input""" GPIO.setup(SWITCH_PIN, GPIO.IN) with self.assertRaises(RuntimeError): GPIO.output(SWITCH_PIN, GPIO.LOW) def test_output_list(self): """Test output() using lists""" GPIO.setup(LOOP_OUT, GPIO.OUT) GPIO.setup(LED_PIN, GPIO.OUT) GPIO.output( [LOOP_OUT, LED_PIN], GPIO.HIGH) self.assertEqual(GPIO.input(LOOP_OUT), GPIO.HIGH) self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) GPIO.output( (LOOP_OUT, LED_PIN), GPIO.LOW) self.assertEqual(GPIO.input(LOOP_OUT), GPIO.LOW) self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) GPIO.output( [LOOP_OUT, LED_PIN], [GPIO.HIGH, GPIO.LOW] ) self.assertEqual(GPIO.input(LOOP_OUT), GPIO.HIGH) self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) GPIO.output( (LOOP_OUT, LED_PIN), (GPIO.LOW, GPIO.HIGH) ) self.assertEqual(GPIO.input(LOOP_OUT), GPIO.LOW) self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) with self.assertRaises(RuntimeError): GPIO.output( [LOOP_OUT, LED_PIN], [0,0,0] ) with self.assertRaises(RuntimeError): GPIO.output( [LOOP_OUT, LED_PIN], (0,) ) with self.assertRaises(RuntimeError): GPIO.output(LOOP_OUT, (0,0)) with self.assertRaises(ValueError): GPIO.output( [LOOP_OUT, 'x'], (0,0) ) with self.assertRaises(ValueError): GPIO.output( [LOOP_OUT, LED_PIN], (0,'x') ) with self.assertRaises(ValueError): GPIO.output( [LOOP_OUT, GND_PIN], (0,0) ) with self.assertRaises(RuntimeError): GPIO.output( [LOOP_OUT, LOOP_IN], (0,0) ) def tearDown(self): GPIO.cleanup() class TestSoftPWM(unittest.TestCase): @unittest.skipIf(non_interactive, 'Non interactive mode') def runTest(self): GPIO.setmode(GPIO.BOARD) GPIO.setup(LED_PIN, GPIO.OUT) pwm = GPIO.PWM(LED_PIN, 50) pwm.start(100) print "\nPWM tests" response = raw_input('Is the LED on (y/n) ? ').upper() self.assertEqual(response,'Y') pwm.start(0) response = raw_input('Is the LED off (y/n) ? ').upper() self.assertEqual(response,'Y') print "LED Brighten/fade test..." for i in range(0,3): for x in range(0,101,5): pwm.ChangeDutyCycle(x) time.sleep(0.1) for x in range(100,-1,-5): pwm.ChangeDutyCycle(x) time.sleep(0.1) pwm.stop() response = raw_input('Did it work (y/n) ? ').upper() self.assertEqual(response,'Y') GPIO.cleanup() class TestSetWarnings(unittest.TestCase): def test_alreadyinuse(self): """Test 'already in use' warning""" GPIO.setmode(GPIO.BOARD) GPIO.setwarnings(False) with open('/sys/class/gpio/export','wb') as f: f.write(str(LED_PIN_BCM).encode()) time.sleep(0.2) # wait for udev to set permissions with open('/sys/class/gpio/gpio%s/direction'%LED_PIN_BCM,'wb') as f: f.write(b'out') with warnings.catch_warnings(record=True) as w: GPIO.setup(LED_PIN, GPIO.OUT) # generate 'already in use' warning self.assertEqual(len(w),0) # should be no warnings with open('/sys/class/gpio/unexport','wb') as f: f.write(str(LED_PIN_BCM).encode()) GPIO.cleanup() GPIO.setmode(GPIO.BOARD) GPIO.setwarnings(True) with open('/sys/class/gpio/export','wb') as f: f.write(str(LED_PIN_BCM).encode()) time.sleep(0.2) # wait for udev to set permissions with open('/sys/class/gpio/gpio%s/direction'%LED_PIN_BCM,'wb') as f: f.write(b'out') with warnings.catch_warnings(record=True) as w: GPIO.setup(LED_PIN, GPIO.OUT) # generate 'already in use' warning self.assertEqual(w[0].category, RuntimeWarning) with open('/sys/class/gpio/unexport','wb') as f: f.write(str(LED_PIN_BCM).encode()) GPIO.cleanup() def test_cleanupwarning(self): """Test initial GPIO.cleanup() produces warning""" GPIO.setwarnings(False) GPIO.setmode(GPIO.BOARD) GPIO.setup(SWITCH_PIN, GPIO.IN) with warnings.catch_warnings(record=True) as w: GPIO.cleanup() self.assertEqual(len(w),0) # no warnings GPIO.cleanup() self.assertEqual(len(w),0) # no warnings GPIO.setwarnings(True) GPIO.setmode(GPIO.BOARD) GPIO.setup(SWITCH_PIN, GPIO.IN) with warnings.catch_warnings(record=True) as w: GPIO.cleanup() self.assertEqual(len(w),0) # no warnings GPIO.cleanup() self.assertEqual(w[0].category, RuntimeWarning) # a warning class TestVersions(unittest.TestCase): def test_rpi_info(self): print 'RPi Board Information' print '---------------------' for key,val in GPIO.RPI_INFO.items(): print '%s => %s'%(key,val) response = raw_input('\nIs this board info correct (y/n) ? ').upper() self.assertEqual(response, 'Y') def test_gpio_version(self): response = raw_input('\nRPi.GPIO version %s - is this correct (y/n) ? '%GPIO.VERSION).upper() self.assertEqual(response, 'Y') class TestGPIOFunction(unittest.TestCase): def runTest(self): GPIO.setmode(GPIO.BCM) GPIO.setup(LED_PIN_BCM, GPIO.IN) self.assertEqual(GPIO.gpio_function(LED_PIN_BCM), GPIO.IN) GPIO.setup(LED_PIN_BCM, GPIO.OUT) self.assertEqual(GPIO.gpio_function(LED_PIN_BCM), GPIO.OUT) GPIO.cleanup() GPIO.setmode(GPIO.BOARD) GPIO.setup(LED_PIN, GPIO.IN) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) GPIO.setup(LED_PIN, GPIO.OUT) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) def tearDown(self): GPIO.cleanup() class TestSwitchBounce(unittest.TestCase): def __init__(self, *a, **k): unittest.TestCase.__init__(self, *a, **k) self.switchcount = 0 def cb(self,chan): self.switchcount += 1 print 'Button press',self.switchcount def setUp(self): GPIO.setmode(GPIO.BOARD) GPIO.setup(SWITCH_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) @unittest.skipIf(non_interactive, 'Non interactive mode') def test_switchbounce(self): self.switchcount = 0 print "\nSwitch bounce test. Press switch at least 10 times and count..." GPIO.add_event_detect(SWITCH_PIN, GPIO.FALLING, callback=self.cb, bouncetime=200) while self.switchcount < 10: time.sleep(1) GPIO.remove_event_detect(SWITCH_PIN) @unittest.skipIf(non_interactive, 'Non interactive mode') def test_event_detected(self): self.switchcount = 0 print "\nGPIO.event_detected() switch bounce test. Press switch at least 10 times and count..." GPIO.add_event_detect(SWITCH_PIN, GPIO.FALLING, bouncetime=200) while self.switchcount < 10: if GPIO.event_detected(SWITCH_PIN): self.switchcount += 1 print 'Button press',self.switchcount GPIO.remove_event_detect(SWITCH_PIN) def tearDown(self): GPIO.cleanup() class TestEdgeDetection(unittest.TestCase): def setUp(self): GPIO.setmode(GPIO.BOARD) GPIO.setup(LOOP_IN, GPIO.IN) GPIO.setup(LOOP_OUT, GPIO.OUT) # Running a shell command with os.sytem has caused problems # with sending SIGCHLD to the polling thread, causing it # to exit. Test for that. def testShellCmdWithWaitForEdge(self): self.finished = False def shellcmd(): for i in range(50): os.system('sleep 0') subprocess.call('sleep 0', shell=True) self.finished = True def makehigh(): GPIO.output(LOOP_OUT, GPIO.HIGH) GPIO.output(LOOP_OUT, GPIO.LOW) t1 = Timer(0.1, shellcmd) t2 = Timer(0.5, makehigh) t1.start() t2.start() starttime = time.time() channel = GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, timeout=1000) endtime = time.time() self.assertGreater(endtime - starttime, 0.5) self.assertLess(endtime - starttime, 0.6) self.assertEqual(channel, LOOP_IN) # make sure tasks in this test have finished before continuing while not self.finished: time.sleep(0.1) def testShellCmdWithEventCallback(self): self.run_cb = False def cb(channel): self.run_cb = True GPIO.output(LOOP_OUT, GPIO.LOW) GPIO.add_event_detect(LOOP_IN, GPIO.RISING, callback=cb) time.sleep(0.01) for i in range(50): os.system('sleep 0') subprocess.call('sleep 0', shell=True) GPIO.output(LOOP_OUT, GPIO.HIGH) time.sleep(0.01) GPIO.remove_event_detect(LOOP_IN) self.assertEqual(self.run_cb, True) def testWaitForEdgeInLoop(self): def makelow(): GPIO.output(LOOP_OUT, GPIO.LOW) count = 0 timestart = time.time() GPIO.output(LOOP_OUT, GPIO.HIGH) while True: t = Timer(0.1, makelow) t.start() starttime = time.time() channel = GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING, timeout=200) endtime = time.time() self.assertLess(endtime-starttime, 0.12) self.assertEqual(channel, LOOP_IN) GPIO.output(LOOP_OUT, GPIO.HIGH) count += 1 if time.time() - timestart > 5 or count > 150: break def testWaitForEdgeWithCallback(self): def cb(): raise Exception("Callback should not be called") def makehigh(): GPIO.output(LOOP_OUT, GPIO.HIGH) GPIO.output(LOOP_OUT, GPIO.LOW) t = Timer(0.1, makehigh) GPIO.add_event_detect(LOOP_IN, GPIO.RISING) t.start() GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) GPIO.output(LOOP_OUT, GPIO.LOW) GPIO.add_event_callback(LOOP_IN, callback=cb) with self.assertRaises(RuntimeError): # conflicting edge exception GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) GPIO.remove_event_detect(LOOP_IN) def testWaitForEventSwitchbounce(self): self.finished = False def bounce(): GPIO.output(LOOP_OUT, GPIO.HIGH) time.sleep(0.01) GPIO.output(LOOP_OUT, GPIO.LOW) time.sleep(0.01) GPIO.output(LOOP_OUT, GPIO.HIGH) time.sleep(0.01) GPIO.output(LOOP_OUT, GPIO.LOW) time.sleep(0.2) GPIO.output(LOOP_OUT, GPIO.HIGH) time.sleep(0.01) GPIO.output(LOOP_OUT, GPIO.LOW) time.sleep(0.01) GPIO.output(LOOP_OUT, GPIO.HIGH) time.sleep(0.01) GPIO.output(LOOP_OUT, GPIO.LOW) self.finished = True GPIO.output(LOOP_OUT, GPIO.LOW) t1 = Timer(0.1, bounce) t1.start() starttime = time.time() GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=100) GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=100) finishtime = time.time() self.assertGreater(finishtime-starttime, 0.2) while not self.finished: time.sleep(0.1) def testInvalidBouncetime(self): with self.assertRaises(ValueError): GPIO.add_event_detect(LOOP_IN, GPIO.RISING, bouncetime=-1) with self.assertRaises(ValueError): GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=-1) GPIO.add_event_detect(LOOP_IN, GPIO.RISING, bouncetime=123) with self.assertRaises(RuntimeError): GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=321) GPIO.remove_event_detect(LOOP_IN) def testAlreadyAdded(self): GPIO.add_event_detect(LOOP_IN, GPIO.RISING) with self.assertRaises(RuntimeError): GPIO.add_event_detect(LOOP_IN, GPIO.RISING) GPIO.remove_event_detect(LOOP_IN) def testHighLowEvent(self): with self.assertRaises(ValueError): GPIO.add_event_detect(LOOP_IN, GPIO.LOW) with self.assertRaises(ValueError): GPIO.add_event_detect(LOOP_IN, GPIO.HIGH) def testFallingEventDetected(self): GPIO.output(LOOP_OUT, GPIO.HIGH) GPIO.add_event_detect(LOOP_IN, GPIO.FALLING) time.sleep(0.01) self.assertEqual(GPIO.event_detected(LOOP_IN), False) GPIO.output(LOOP_OUT, GPIO.LOW) time.sleep(0.01) self.assertEqual(GPIO.event_detected(LOOP_IN), True) GPIO.output(LOOP_OUT, GPIO.HIGH) time.sleep(0.01) self.assertEqual(GPIO.event_detected(LOOP_IN), False) GPIO.remove_event_detect(LOOP_IN) def testRisingEventDetected(self): GPIO.output(LOOP_OUT, GPIO.LOW) GPIO.add_event_detect(LOOP_IN, GPIO.RISING) time.sleep(0.01) self.assertEqual(GPIO.event_detected(LOOP_IN), False) GPIO.output(LOOP_OUT, GPIO.HIGH) time.sleep(0.01) self.assertEqual(GPIO.event_detected(LOOP_IN), True) GPIO.output(LOOP_OUT, GPIO.LOW) time.sleep(0.01) self.assertEqual(GPIO.event_detected(LOOP_IN), False) GPIO.remove_event_detect(LOOP_IN) def testBothEventDetected(self): GPIO.output(LOOP_OUT, GPIO.LOW) GPIO.add_event_detect(LOOP_IN, GPIO.BOTH) time.sleep(0.01) self.assertEqual(GPIO.event_detected(LOOP_IN), False) GPIO.output(LOOP_OUT, GPIO.HIGH) time.sleep(0.01) self.assertEqual(GPIO.event_detected(LOOP_IN), True) self.assertEqual(GPIO.event_detected(LOOP_IN), False) GPIO.output(LOOP_OUT, GPIO.LOW) time.sleep(0.01) self.assertEqual(GPIO.event_detected(LOOP_IN), True) GPIO.remove_event_detect(LOOP_IN) def testWaitForRising(self): def makehigh(): GPIO.output(LOOP_OUT, GPIO.HIGH) GPIO.output(LOOP_OUT, GPIO.LOW) t = Timer(0.1, makehigh) t.start() GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) def testWaitForFalling(self): def makelow(): GPIO.output(LOOP_OUT, GPIO.LOW) GPIO.output(LOOP_OUT, GPIO.HIGH) t = Timer(0.1, makelow) t.start() GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING) def testExceptionInCallback(self): self.run_cb = False def cb(channel): with self.assertRaises(ZeroDivisionError): self.run_cb = True a = 1/0 GPIO.output(LOOP_OUT, GPIO.LOW) GPIO.add_event_detect(LOOP_IN, GPIO.RISING, callback=cb) time.sleep(0.01) GPIO.output(LOOP_OUT, GPIO.HIGH) time.sleep(0.01) self.assertEqual(self.run_cb, True) GPIO.remove_event_detect(LOOP_IN) def testAddEventCallback(self): def cb(channel): self.callback_count += 1 # falling test self.callback_count = 0 GPIO.output(LOOP_OUT, GPIO.HIGH) GPIO.add_event_detect(LOOP_IN, GPIO.FALLING) GPIO.add_event_callback(LOOP_IN, cb) time.sleep(0.01) for i in range(2048): GPIO.output(LOOP_OUT, GPIO.LOW) time.sleep(0.001) GPIO.output(LOOP_OUT, GPIO.HIGH) time.sleep(0.001) GPIO.remove_event_detect(LOOP_IN) self.assertEqual(self.callback_count, 2048) # rising test self.callback_count = 0 GPIO.output(LOOP_OUT, GPIO.LOW) GPIO.add_event_detect(LOOP_IN, GPIO.RISING, callback=cb) time.sleep(0.01) for i in range(2048): GPIO.output(LOOP_OUT, GPIO.HIGH) time.sleep(0.001) GPIO.output(LOOP_OUT, GPIO.LOW) time.sleep(0.001) GPIO.remove_event_detect(LOOP_IN) self.assertEqual(self.callback_count, 2048) # both test self.callback_count = 0 GPIO.output(LOOP_OUT, GPIO.LOW) GPIO.add_event_detect(LOOP_IN, GPIO.BOTH, callback=cb) time.sleep(0.01) for i in range(2048): GPIO.output(LOOP_OUT, GPIO.HIGH) time.sleep(0.001) GPIO.output(LOOP_OUT, GPIO.LOW) time.sleep(0.001) GPIO.remove_event_detect(LOOP_IN) self.assertEqual(self.callback_count, 4096) def testEventOnOutput(self): with self.assertRaises(RuntimeError): GPIO.add_event_detect(LOOP_OUT, GPIO.FALLING) def testAlternateWaitForEdge(self): def makehigh(): GPIO.output(LOOP_OUT, GPIO.HIGH) def makelow(): GPIO.output(LOOP_OUT, GPIO.LOW) GPIO.output(LOOP_OUT, GPIO.LOW) t = Timer(0.1, makehigh) t2 = Timer(0.15, makelow) t.start() t2.start() GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING) def testWaitForEdgeTimeout(self): def makehigh(): GPIO.output(LOOP_OUT, GPIO.HIGH) def makelow(): GPIO.output(LOOP_OUT, GPIO.LOW) with self.assertRaises(TypeError): GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, timeout="beer") with self.assertRaises(ValueError): GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, timeout=-1234) makelow() chan = GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, timeout=200) self.assertEqual(chan, None) t = Timer(0.1, makehigh) t.start() chan = GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, timeout=200) self.assertEqual(chan, LOOP_IN) def tearDown(self): GPIO.cleanup() class TestCleanup(unittest.TestCase): def setUp(self): GPIO.setmode(GPIO.BOARD) def test_cleanall(self): GPIO.setup(LOOP_OUT, GPIO.OUT) GPIO.setup(LED_PIN, GPIO.OUT) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) GPIO.cleanup() GPIO.setmode(GPIO.BOARD) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) def test_cleanone(self): GPIO.setup(LOOP_OUT, GPIO.OUT) GPIO.setup(LED_PIN, GPIO.OUT) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) GPIO.cleanup(LOOP_OUT) GPIO.setmode(GPIO.BOARD) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) GPIO.cleanup(LED_PIN) GPIO.setmode(GPIO.BOARD) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) def test_cleantuple(self): GPIO.setup(LOOP_OUT, GPIO.OUT) GPIO.setup(LED_PIN, GPIO.OUT) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) GPIO.cleanup((LOOP_OUT,)) GPIO.setmode(GPIO.BOARD) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) GPIO.cleanup((LED_PIN,)) GPIO.setmode(GPIO.BOARD) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) GPIO.setup(LOOP_OUT, GPIO.OUT) GPIO.setup(LED_PIN, GPIO.OUT) GPIO.cleanup((LOOP_OUT,LED_PIN)) GPIO.setmode(GPIO.BOARD) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) def test_cleanlist(self): GPIO.setup(LOOP_OUT, GPIO.OUT) GPIO.setup(LED_PIN, GPIO.OUT) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) GPIO.cleanup([LOOP_OUT]) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) GPIO.cleanup([LED_PIN]) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) GPIO.setup(LOOP_OUT, GPIO.OUT) GPIO.setup(LED_PIN, GPIO.OUT) GPIO.cleanup([LOOP_OUT,LED_PIN]) self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) if __name__ == '__main__': unittest.main() RPi.GPIO-0.6.3/RPi/0000755000175000017500000000000013005465261012505 5ustar pipi00000000000000RPi.GPIO-0.6.3/RPi/GPIO/0000755000175000017500000000000013005465261013243 5ustar pipi00000000000000RPi.GPIO-0.6.3/RPi/GPIO/__init__.py0000644000175000017500000000213013005464567015360 0ustar pipi00000000000000""" Copyright (c) 2012-2016 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from RPi._GPIO import * VERSION = '0.6.3' RPi.GPIO-0.6.3/RPi/__init__.py0000644000175000017500000000000013005464447014611 0ustar pipi00000000000000RPi.GPIO-0.6.3/README.txt0000644000175000017500000000166413005464447013525 0ustar pipi00000000000000This package provides a class to control the GPIO on a Raspberry Pi. Note that this module is unsuitable for real-time or timing critical applications. This is because you can not predict when Python will be busy garbage collecting. It also runs under the Linux kernel which is not suitable for real time applications - it is multitasking O/S and another process may be given priority over the CPU, causing jitter in your program. If you are after true real-time performance and predictability, buy yourself an Arduino http://www.arduino.cc ! Note that the current release does not support SPI, I2C, hardware PWM or serial functionality on the RPi yet. This is planned for the near future - watch this space! One-wire functionality is also planned. Although hardware PWM is not available yet, software PWM is available to use on all channels. For examples and documentation, visit http://sourceforge.net/p/raspberry-gpio-python/wiki/Home/ RPi.GPIO-0.6.3/CHANGELOG.txt0000644000175000017500000001253113005464470014046 0ustar pipi00000000000000Change Log ========== 0.6.3 ------- - Fix code so it builds under PyPy (Gasper Zejn) - os.system breaks event detection - Matt Kimball (issue 127) 0.6.2 ----- - Rewrote Debian packaging mechanism - RPI_INFO reports Pi 3 - Changed module layout - moved C components to RPi._GPIO 0.6.1 ----- - Update RPI_INFO to detect more board types - Issue 118 - add_event_detect sometimes gives runtime error with unpriv user - Issue 120 - setmode() remembers invalid mode 0.6.0a3 ------- - Now uses /dev/gpiomem if available to avoid being run as root - Fix warnings with pull up/down on pins 3/5 - Correct base address on Pi 2 when devicetree is disabled - caddr_t error on compile (Issue 109) - Error on invalid parameters to setup() (issue 93) - Add timeout parameter to wait_for_edge() (issue 91) 0.5.11 ------ - Fix - pins > 26 missing when using BOARD mode - Add getmode() - Raise exception when a mix of modes is used - GPIO.cleanaup() unsets the current pin mode 0.5.10 ------ - Issue 95 - support RPi 2 boards - Introduce RPI_INFO - Deprecate RPI_REVISION - Issue 97 - fixed docstring for setup() 0.5.9 ----- - Issue 87 - warn about pull up/down on i2c pins - Issue 86/75 - wait_for_edge() bugfix - Issue 84 - recognise RPi properly when using a custom kernel - Issue 90 - cleanup() on a list/tuple of channels 0.5.8 ----- - Allow lists/tuples of channels in GPIO.setup() - GPIO.output() now allows lists/tuples of values - GPIO.wait_for_edge() bug fixes (issue 78) 0.5.7 ----- - Issue 67 - speed up repeated calls to GPIO.wait_for_event() - Added bouncetime keyword to GPIO.wait_for_event() - Added extra edge/interrupt unit tests - GPIO.wait_for_event() can now be mixed with GPIO.add_event_detect() - Improved cleanups of events - Issue 69 resolved 0.5.6 ----- - Issue 68 - support for RPi Model B+ - Fix gpio_function() 0.5.5 ----- - Issue 52 - 'unallocate' a channel - Issue 35 - use switchbounce with GPIO.event_detected() - Refactored events code - Rewrote tests to use unittest mechanism and new test board with loopbacks - Fixed adding events after a GPIO.cleanup() - Issue 64 - misleading /dev/mem permissions error - Issue 59 - name collision with PWM constant and class 0.5.4 ----- - Changed release status (from alpha to full release) - Warn when GPIO.cleanup() used with nothing to clean up (issue 44) - Avoid collisions in constants (e.g. HIGH / RISING / PUD_DOWN) - Accept BOARD numbers in gpio_function (issue 34) - More return values for gpio_function (INPUT, OUTPUT, SPI, I2C, PWM, SERIAL, UNKNOWN) - Tidy up docstrings - Fix /dev/mem access error with gpio_function 0.5.3a ------ - Allow pydoc for non-root users (issue 27) - Fix add_event_detect error when run as daemon (issue 32) - Simplified exception types - Changed from distribute to pip 0.5.2a ------ - Added software PWM (experimental) - Added switch bounce handling to event callbacks - Added channel number parameter to event callbacks (issue 31) - Internal refactoring and code tidy up 0.5.1a ------ - Fixed callbacks for multiple GPIOs (issue 28) 0.5.0a ------ - Added new edge detection events (interrupt handling) - Added add_event_detect() - Added remove_event_detect() - Added add_event_callback() - Added wait_for_edge() - Removed old experimental event functions - Removed set_rising_event() - Removed set_falling_event() - Removed set_high_event() - Removed set_low_event() - Changed event_detected() for new edge detection functionality - input() now returns 0/LOW == False or 1/HIGH == True (integers) instead of False or True (booleans). - Fix error on repeated import (issue 3) - Change SetupException to a RuntimeError so it can be caught on import (issue 25, Chris Hager ) - Improved docstrings of functions 0.4.2a ------ - Fix for installing on Arch Linux (Python 3.3) (issue 20) - Initial value when setting a channel as an output (issue 19) 0.4.1a ------ - Added VERSION - Permit input() of channels set as outputs (Eric Ptak ) 0.4.0a ------ - Added support for Revision 2 boards - Added RPI_REVISION - Added cleanup() function and removed automatic reset functionality on program exit - Added get_function() to read existing GPIO channel functionality (suggestion from Eric Ptak ) - Added set_rising_event() - Added set_falling_event() - Added set_high_event() - Added set_low_event() - Added event_detected() - Added test/test.py - Converted debian to armhf - Fixed C function short_wait() (thanks to Thibault Porteboeuf ) 0.3.1a ------ - Fixed critical bug with swapped high/low state on outputs - Added pull-up / pull-down setup functionality for inputs 0.3.0a ------ - Rewritten as a C extension - Now uses /dev/mem and SoC registers instead of /sys/class/gpio - Faster! - Make call to GPIO.setmode() mandatory - Added GPIO.HIGH and GPIO.LOW constants 0.2.0 ----- - Changed status from alpha to beta - Added setmode() to be able to use BCM GPIO 00.nn channel numbers - Renamed InvalidPinException to InvalidChannelException 0.1.0 ------ - Fixed direction bug - Added MANIFEST.in (to include missing file) - Changed GPIO channel number to pin number - Tested and working! 0.0.3a ------ - Added GPIO table - Refactored - Fixed a few critical bugs - Still completely untested! 0.0.2a ------ - Internal refactoring. Still completely untested! 0.0.1a ------ - First version. Completely untested until I can get hold of a Raspberry Pi! RPi.GPIO-0.6.3/source/0000755000175000017500000000000013005465261013313 5ustar pipi00000000000000RPi.GPIO-0.6.3/source/common.c0000644000175000017500000000633713005464450014757 0ustar pipi00000000000000/* Copyright (c) 2013-2014 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "Python.h" #include "c_gpio.h" #include "common.h" int gpio_mode = MODE_UNKNOWN; const int pin_to_gpio_rev1[41] = {-1, -1, -1, 0, -1, 1, -1, 4, 14, -1, 15, 17, 18, 21, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; const int pin_to_gpio_rev2[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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; const int pin_to_gpio_rev3[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 }; int setup_error = 0; int module_setup = 0; int check_gpio_priv(void) { // check module has been imported cleanly if (setup_error) { PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!"); return 1; } // check mmap setup has worked if (!module_setup) { PyErr_SetString(PyExc_RuntimeError, "No access to /dev/mem. Try running as root!"); return 2; } return 0; } int get_gpio_number(int channel, unsigned int *gpio) { // check setmode() has been run if (gpio_mode != BOARD && gpio_mode != BCM) { PyErr_SetString(PyExc_RuntimeError, "Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)"); return 3; } // check channel number is in range if ( (gpio_mode == BCM && (channel < 0 || channel > 53)) || (gpio_mode == BOARD && (channel < 1 || channel > 26) && rpiinfo.p1_revision != 3) || (gpio_mode == BOARD && (channel < 1 || channel > 40) && rpiinfo.p1_revision == 3) ) { PyErr_SetString(PyExc_ValueError, "The channel sent is invalid on a Raspberry Pi"); return 4; } // convert channel to gpio if (gpio_mode == BOARD) { if (*(*pin_to_gpio+channel) == -1) { PyErr_SetString(PyExc_ValueError, "The channel sent is invalid on a Raspberry Pi"); return 5; } else { *gpio = *(*pin_to_gpio+channel); } } else // gpio_mode == BCM { *gpio = channel; } return 0; } RPi.GPIO-0.6.3/source/cpuinfo.c0000644000175000017500000001667113005464450015134 0ustar pipi00000000000000/* Copyright (c) 2012-2016 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include "cpuinfo.h" int get_rpi_info(rpi_info *info) { FILE *fp; char buffer[1024]; char hardware[1024]; char revision[1024]; char *rev; int found = 0; int len; if ((fp = fopen("/proc/cpuinfo", "r")) == NULL) return -1; while(!feof(fp)) { fgets(buffer, sizeof(buffer), fp); sscanf(buffer, "Hardware : %s", hardware); if (strcmp(hardware, "BCM2708") == 0 || strcmp(hardware, "BCM2709") == 0 || strcmp(hardware, "BCM2835") == 0 || strcmp(hardware, "BCM2836") == 0 || strcmp(hardware, "BCM2837") == 0 ) { found = 1; } sscanf(buffer, "Revision : %s", revision); } fclose(fp); if (!found) return -1; if ((len = strlen(revision)) == 0) return -1; if (len >= 6 && strtol((char[]){revision[len-6],0}, NULL, 16) & 8) { // new scheme //info->rev = revision[len-1]-'0'; strcpy(info->revision, revision); switch (revision[len-2]) { case '0': info->type = "Model A"; info->p1_revision = 2; break; case '1': info->type = "Model B"; info->p1_revision = 2; break; case '2': info->type = "Model A+"; info->p1_revision = 3; break; case '3': info->type = "Model B+"; info->p1_revision = 3; break; case '4': info->type = "Pi 2 Model B"; info->p1_revision = 3; break; case '5': info->type = "Alpha"; info->p1_revision = 3; break; case '6': info->type = "Compute"; info->p1_revision = 0; break; case '8': info->type = "Pi 3 Model B"; info->p1_revision = 3; break; case '9': info->type = "Zero"; info->p1_revision = 3; break; default : info->type = "Unknown"; info->p1_revision = 3; break; } switch (revision[len-4]) { case '0': info->processor = "BCM2835"; break; case '1': info->processor = "BCM2836"; break; case '2': info->processor = "BCM2837"; break; default : info->processor = "Unknown"; break; } switch (revision[len-5]) { case '0': info->manufacturer = "Sony"; break; case '1': info->manufacturer = "Egoman"; break; case '2': info->manufacturer = "Embest"; break; case '4': info->manufacturer = "Embest"; break; default : info->manufacturer = "Unknown"; break; } switch (strtol((char[]){revision[len-6],0}, NULL, 16) & 7) { case 0: info->ram = "256M"; break; case 1: info->ram = "512M"; break; case 2: info->ram = "1024M"; break; default: info->ram = "Unknown"; break; } } else { // old scheme info->ram = "Unknown"; info->manufacturer = "Unknown"; info->processor = "Unknown"; info->type = "Unknown"; strcpy(info->revision, revision); // get last four characters (ignore preceeding 1000 for overvolt) if (len > 4) rev = (char *)&revision+len-4; else rev = revision; if ((strcmp(rev, "0002") == 0) || (strcmp(rev, "0003") == 0)) { info->type = "Model B"; info->p1_revision = 1; info->ram = "256M"; info->processor = "BCM2835"; } else if (strcmp(rev, "0004") == 0) { info->type = "Model B"; info->p1_revision = 2; info->ram = "256M"; info->manufacturer = "Sony"; info->processor = "BCM2835"; } else if (strcmp(rev, "0005") == 0) { info->type = "Model B"; info->p1_revision = 2; info->ram = "256M"; info->manufacturer = "Qisda"; info->processor = "BCM2835"; } else if (strcmp(rev, "0006") == 0) { info->type = "Model B"; info->p1_revision = 2; info->ram = "256M"; info->manufacturer = "Egoman"; info->processor = "BCM2835"; } else if (strcmp(rev, "0007") == 0) { info->type = "Model A"; info->p1_revision = 2; info->ram = "256M"; info->manufacturer = "Egoman"; info->processor = "BCM2835"; } else if (strcmp(rev, "0008") == 0) { info->type = "Model A"; info->p1_revision = 2; info->ram = "256M"; info->manufacturer = "Sony"; info->processor = "BCM2835"; } else if (strcmp(rev, "0009") == 0) { info->type = "Model A"; info->p1_revision = 2; info->ram = "256M"; info->manufacturer = "Qisda"; info->processor = "BCM2835"; } else if (strcmp(rev, "000d") == 0) { info->type = "Model B"; info->p1_revision = 2; info->ram = "512M"; info->manufacturer = "Egoman"; info->processor = "BCM2835"; } else if (strcmp(rev, "000e") == 0) { info->type = "Model B"; info->p1_revision = 2; info->ram = "512M"; info->manufacturer = "Sony"; info->processor = "BCM2835"; } else if (strcmp(rev, "000f") == 0) { info->type = "Model B"; info->p1_revision = 2; info->ram = "512M"; info->manufacturer = "Qisda"; info->processor = "BCM2835"; } else if ((strcmp(rev, "0011") == 0) || (strcmp(rev, "0014") == 0)) { info->type = "Compute Module"; info->p1_revision = 0; info->ram = "512M"; info->processor = "BCM2835"; } else if (strcmp(rev, "0012") == 0) { info->type = "Model A+"; info->p1_revision = 3; info->ram = "256M"; info->processor = "BCM2835"; } else if ((strcmp(rev, "0010") == 0) || (strcmp(rev, "0013") == 0)) { info->type = "Model B+"; info->p1_revision = 3; info->ram = "512M"; info->processor = "BCM2835"; } else { // don't know - assume revision 3 p1 connector info->p1_revision = 3; } } return 0; } /* 32 bits NEW 23: will be 1 for the new scheme, 0 for the old scheme MEMSIZE 20: 0=256M 1=512M 2=1G MANUFACTURER 16: 0=SONY 1=EGOMAN PROCESSOR 12: 0=2835 1=2836 TYPE 04: 0=MODELA 1=MODELB 2=MODELA+ 3=MODELB+ 4=Pi2 MODEL B 5=ALPHA 6=CM REV 00: 0=REV0 1=REV1 2=REV2 pi2 = 1<<23 | 2<<20 | 1<<12 | 4<<4 = 0xa01040 -------------------- SRRR MMMM PPPP TTTT TTTT VVVV S scheme (0=old, 1=new) R RAM (0=256, 1=512, 2=1024) M manufacturer (0='SONY',1='EGOMAN',2='EMBEST',3='UNKNOWN',4='EMBEST') P processor (0=2835, 1=2836 2=2837) T type (0='A', 1='B', 2='A+', 3='B+', 4='Pi 2 B', 5='Alpha', 6='Compute Module') V revision (0-15) */ RPi.GPIO-0.6.3/source/c_gpio.c0000644000175000017500000001725013005464450014723 0ustar pipi00000000000000/* Copyright (c) 2012-2015 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include "c_gpio.h" #define BCM2708_PERI_BASE_DEFAULT 0x20000000 #define BCM2709_PERI_BASE_DEFAULT 0x3f000000 #define GPIO_BASE_OFFSET 0x200000 #define FSEL_OFFSET 0 // 0x0000 #define SET_OFFSET 7 // 0x001c / 4 #define CLR_OFFSET 10 // 0x0028 / 4 #define PINLEVEL_OFFSET 13 // 0x0034 / 4 #define EVENT_DETECT_OFFSET 16 // 0x0040 / 4 #define RISING_ED_OFFSET 19 // 0x004c / 4 #define FALLING_ED_OFFSET 22 // 0x0058 / 4 #define HIGH_DETECT_OFFSET 25 // 0x0064 / 4 #define LOW_DETECT_OFFSET 28 // 0x0070 / 4 #define PULLUPDN_OFFSET 37 // 0x0094 / 4 #define PULLUPDNCLK_OFFSET 38 // 0x0098 / 4 #define PAGE_SIZE (4*1024) #define BLOCK_SIZE (4*1024) static volatile uint32_t *gpio_map; void short_wait(void) { int i; for (i=0; i<150; i++) { // wait 150 cycles asm volatile("nop"); } } int setup(void) { int mem_fd; uint8_t *gpio_mem; uint32_t peri_base; uint32_t gpio_base; unsigned char buf[4]; FILE *fp; char buffer[1024]; char hardware[1024]; int found = 0; // try /dev/gpiomem first - this does not require root privs if ((mem_fd = open("/dev/gpiomem", O_RDWR|O_SYNC)) > 0) { gpio_map = (uint32_t *)mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0); if ((uint32_t)gpio_map < 0) { return SETUP_MMAP_FAIL; } else { return SETUP_OK; } } // revert to /dev/mem method - requires root // determine peri_base if ((fp = fopen("/proc/device-tree/soc/ranges", "rb")) != NULL) { // get peri base from device tree fseek(fp, 4, SEEK_SET); if (fread(buf, 1, sizeof buf, fp) == sizeof buf) { peri_base = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0; } fclose(fp); } else { // guess peri base based on /proc/cpuinfo hardware field if ((fp = fopen("/proc/cpuinfo", "r")) == NULL) return SETUP_CPUINFO_FAIL; while(!feof(fp) && !found) { fgets(buffer, sizeof(buffer), fp); sscanf(buffer, "Hardware : %s", hardware); if (strcmp(hardware, "BCM2708") == 0 || strcmp(hardware, "BCM2835") == 0) { // pi 1 hardware peri_base = BCM2708_PERI_BASE_DEFAULT; found = 1; } else if (strcmp(hardware, "BCM2709") == 0 || strcmp(hardware, "BCM2836") == 0) { // pi 2 hardware peri_base = BCM2709_PERI_BASE_DEFAULT; found = 1; } } fclose(fp); if (!found) return SETUP_NOT_RPI_FAIL; } gpio_base = peri_base + GPIO_BASE_OFFSET; // mmap the GPIO memory registers if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) return SETUP_DEVMEM_FAIL; if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) return SETUP_MALLOC_FAIL; if ((uint32_t)gpio_mem % PAGE_SIZE) gpio_mem += PAGE_SIZE - ((uint32_t)gpio_mem % PAGE_SIZE); gpio_map = (uint32_t *)mmap( (void *)gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, gpio_base); if ((uint32_t)gpio_map < 0) return SETUP_MMAP_FAIL; return SETUP_OK; } void clear_event_detect(int gpio) { int offset = EVENT_DETECT_OFFSET + (gpio/32); int shift = (gpio%32); *(gpio_map+offset) |= (1 << shift); short_wait(); *(gpio_map+offset) = 0; } int eventdetected(int gpio) { int offset, value, bit; offset = EVENT_DETECT_OFFSET + (gpio/32); bit = (1 << (gpio%32)); value = *(gpio_map+offset) & bit; if (value) clear_event_detect(gpio); return value; } void set_rising_event(int gpio, int enable) { int offset = RISING_ED_OFFSET + (gpio/32); int shift = (gpio%32); if (enable) *(gpio_map+offset) |= 1 << shift; else *(gpio_map+offset) &= ~(1 << shift); clear_event_detect(gpio); } void set_falling_event(int gpio, int enable) { int offset = FALLING_ED_OFFSET + (gpio/32); int shift = (gpio%32); if (enable) { *(gpio_map+offset) |= (1 << shift); *(gpio_map+offset) = (1 << shift); } else { *(gpio_map+offset) &= ~(1 << shift); } clear_event_detect(gpio); } void set_high_event(int gpio, int enable) { int offset = HIGH_DETECT_OFFSET + (gpio/32); int shift = (gpio%32); if (enable) *(gpio_map+offset) |= (1 << shift); else *(gpio_map+offset) &= ~(1 << shift); clear_event_detect(gpio); } void set_low_event(int gpio, int enable) { int offset = LOW_DETECT_OFFSET + (gpio/32); int shift = (gpio%32); if (enable) *(gpio_map+offset) |= 1 << shift; else *(gpio_map+offset) &= ~(1 << shift); clear_event_detect(gpio); } void set_pullupdn(int gpio, int pud) { int clk_offset = PULLUPDNCLK_OFFSET + (gpio/32); int shift = (gpio%32); if (pud == PUD_DOWN) *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_DOWN; else if (pud == PUD_UP) *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_UP; else // pud == PUD_OFF *(gpio_map+PULLUPDN_OFFSET) &= ~3; short_wait(); *(gpio_map+clk_offset) = 1 << shift; short_wait(); *(gpio_map+PULLUPDN_OFFSET) &= ~3; *(gpio_map+clk_offset) = 0; } void setup_gpio(int gpio, int direction, int pud) { int offset = FSEL_OFFSET + (gpio/10); int shift = (gpio%10)*3; set_pullupdn(gpio, pud); if (direction == OUTPUT) *(gpio_map+offset) = (*(gpio_map+offset) & ~(7< int gpio_function(int gpio) { int offset = FSEL_OFFSET + (gpio/10); int shift = (gpio%10)*3; int value = *(gpio_map+offset); value >>= shift; value &= 7; return value; // 0=input, 1=output, 4=alt0 } void output_gpio(int gpio, int value) { int offset, shift; if (value) // value == HIGH offset = SET_OFFSET + (gpio/32); else // value == LOW offset = CLR_OFFSET + (gpio/32); shift = (gpio%32); *(gpio_map+offset) = 1 << shift; } int input_gpio(int gpio) { int offset, value, mask; offset = PINLEVEL_OFFSET + (gpio/32); mask = (1 << gpio%32); value = *(gpio_map+offset) & mask; return value; } void cleanup(void) { munmap((void *)gpio_map, BLOCK_SIZE); } RPi.GPIO-0.6.3/source/soft_pwm.h0000644000175000017500000000240213005464450015317 0ustar pipi00000000000000/* Copyright (c) 2013 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Software PWM using threads */ void pwm_set_duty_cycle(unsigned int gpio, float dutycycle); void pwm_set_frequency(unsigned int gpio, float freq); void pwm_start(unsigned int gpio); void pwm_stop(unsigned int gpio); RPi.GPIO-0.6.3/source/py_pwm.c0000644000175000017500000001417213005464450014776 0ustar pipi00000000000000/* Copyright (c) 2013 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "Python.h" #include "soft_pwm.h" #include "py_pwm.h" #include "common.h" #include "c_gpio.h" typedef struct { PyObject_HEAD unsigned int gpio; float freq; float dutycycle; } PWMObject; // python method PWM.__init__(self, channel, frequency) static int PWM_init(PWMObject *self, PyObject *args, PyObject *kwds) { int channel; float frequency; if (!PyArg_ParseTuple(args, "if", &channel, &frequency)) return -1; // convert channel to gpio if (get_gpio_number(channel, &(self->gpio))) return -1; // ensure channel set as output if (gpio_direction[self->gpio] != OUTPUT) { PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an output first"); return -1; } if (frequency <= 0.0) { PyErr_SetString(PyExc_ValueError, "frequency must be greater than 0.0"); return -1; } self->freq = frequency; pwm_set_frequency(self->gpio, self->freq); return 0; } // python method PWM.start(self, dutycycle) static PyObject *PWM_start(PWMObject *self, PyObject *args) { float dutycycle; if (!PyArg_ParseTuple(args, "f", &dutycycle)) return NULL; if (dutycycle < 0.0 || dutycycle > 100.0) { PyErr_SetString(PyExc_ValueError, "dutycycle must have a value from 0.0 to 100.0"); return NULL; } self->dutycycle = dutycycle; pwm_set_duty_cycle(self->gpio, self->dutycycle); pwm_start(self->gpio); Py_RETURN_NONE; } // python method PWM.ChangeDutyCycle(self, dutycycle) static PyObject *PWM_ChangeDutyCycle(PWMObject *self, PyObject *args) { float dutycycle = 0.0; if (!PyArg_ParseTuple(args, "f", &dutycycle)) return NULL; if (dutycycle < 0.0 || dutycycle > 100.0) { PyErr_SetString(PyExc_ValueError, "dutycycle must have a value from 0.0 to 100.0"); return NULL; } self->dutycycle = dutycycle; pwm_set_duty_cycle(self->gpio, self->dutycycle); Py_RETURN_NONE; } // python method PWM. ChangeFrequency(self, frequency) static PyObject *PWM_ChangeFrequency(PWMObject *self, PyObject *args) { float frequency = 1.0; if (!PyArg_ParseTuple(args, "f", &frequency)) return NULL; if (frequency <= 0.0) { PyErr_SetString(PyExc_ValueError, "frequency must be greater than 0.0"); return NULL; } self->freq = frequency; pwm_set_frequency(self->gpio, self->freq); Py_RETURN_NONE; } // python function PWM.stop(self) static PyObject *PWM_stop(PWMObject *self, PyObject *args) { pwm_stop(self->gpio); Py_RETURN_NONE; } // deallocation method static void PWM_dealloc(PWMObject *self) { pwm_stop(self->gpio); Py_TYPE(self)->tp_free((PyObject*)self); } static PyMethodDef PWM_methods[] = { { "start", (PyCFunction)PWM_start, METH_VARARGS, "Start software PWM\ndutycycle - the duty cycle (0.0 to 100.0)" }, { "ChangeDutyCycle", (PyCFunction)PWM_ChangeDutyCycle, METH_VARARGS, "Change the duty cycle\ndutycycle - between 0.0 and 100.0" }, { "ChangeFrequency", (PyCFunction)PWM_ChangeFrequency, METH_VARARGS, "Change the frequency\nfrequency - frequency in Hz (freq > 1.0)" }, { "stop", (PyCFunction)PWM_stop, METH_VARARGS, "Stop software PWM" }, { NULL } }; PyTypeObject PWMType = { PyVarObject_HEAD_INIT(NULL,0) "RPi.GPIO.PWM", // tp_name sizeof(PWMObject), // tp_basicsize 0, // tp_itemsize (destructor)PWM_dealloc, // tp_dealloc 0, // tp_print 0, // tp_getattr 0, // tp_setattr 0, // tp_compare 0, // tp_repr 0, // tp_as_number 0, // tp_as_sequence 0, // tp_as_mapping 0, // tp_hash 0, // tp_call 0, // tp_str 0, // tp_getattro 0, // tp_setattro 0, // tp_as_buffer Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flag "Pulse Width Modulation class", // tp_doc 0, // tp_traverse 0, // tp_clear 0, // tp_richcompare 0, // tp_weaklistoffset 0, // tp_iter 0, // tp_iternext PWM_methods, // tp_methods 0, // tp_members 0, // tp_getset 0, // tp_base 0, // tp_dict 0, // tp_descr_get 0, // tp_descr_set 0, // tp_dictoffset (initproc)PWM_init, // tp_init 0, // tp_alloc 0, // tp_new }; PyTypeObject *PWM_init_PWMType(void) { // Fill in some slots in the type, and make it ready PWMType.tp_new = PyType_GenericNew; if (PyType_Ready(&PWMType) < 0) return NULL; return &PWMType; } RPi.GPIO-0.6.3/source/constants.h0000644000175000017500000000270213005464450015500 0ustar pipi00000000000000/* Copyright (c) 2013 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define PY_PUD_CONST_OFFSET 20 #define PY_EVENT_CONST_OFFSET 30 PyObject *high; PyObject *low; PyObject *input; PyObject *output; PyObject *pwm; PyObject *serial; PyObject *i2c; PyObject *spi; PyObject *unknown; PyObject *board; PyObject *bcm; PyObject *pud_off; PyObject *pud_up; PyObject *pud_down; PyObject *rising_edge; PyObject *falling_edge; PyObject *both_edge; void define_constants(PyObject *module); RPi.GPIO-0.6.3/source/cpuinfo.h0000644000175000017500000000243213005464450015127 0ustar pipi00000000000000/* Copyright (c) 2012-2015 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef CPUINFO_H #define CPUINFO_H typedef struct { int p1_revision; char *ram; char *manufacturer; char *processor; char *type; char revision[1024]; } rpi_info; #endif /* CPUINFO_H */ int get_rpi_info(rpi_info *info); RPi.GPIO-0.6.3/source/py_pwm.h0000644000175000017500000000214213005464450014775 0ustar pipi00000000000000/* Copyright (c) 2013 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ PyTypeObject PWMType; PyTypeObject *PWM_init_PWMType(void); RPi.GPIO-0.6.3/source/c_gpio.h0000644000175000017500000000346413005464450014732 0ustar pipi00000000000000/* Copyright (c) 2012-2015 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ int setup(void); void setup_gpio(int gpio, int direction, int pud); int gpio_function(int gpio); void output_gpio(int gpio, int value); int input_gpio(int gpio); void set_rising_event(int gpio, int enable); void set_falling_event(int gpio, int enable); void set_high_event(int gpio, int enable); void set_low_event(int gpio, int enable); int eventdetected(int gpio); void cleanup(void); #define SETUP_OK 0 #define SETUP_DEVMEM_FAIL 1 #define SETUP_MALLOC_FAIL 2 #define SETUP_MMAP_FAIL 3 #define SETUP_CPUINFO_FAIL 4 #define SETUP_NOT_RPI_FAIL 5 #define INPUT 1 // is really 0 for control register! #define OUTPUT 0 // is really 1 for control register! #define ALT0 4 #define HIGH 1 #define LOW 0 #define PUD_OFF 0 #define PUD_DOWN 1 #define PUD_UP 2 RPi.GPIO-0.6.3/source/constants.c0000644000175000017500000000546713005464450015506 0ustar pipi00000000000000/* Copyright (c) 2013-2016 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "Python.h" #include "constants.h" #include "common.h" #include "c_gpio.h" #include "event_gpio.h" void define_constants(PyObject *module) { high = Py_BuildValue("i", HIGH); PyModule_AddObject(module, "HIGH", high); low = Py_BuildValue("i", LOW); PyModule_AddObject(module, "LOW", low); output = Py_BuildValue("i", OUTPUT); PyModule_AddObject(module, "OUT", output); input = Py_BuildValue("i", INPUT); PyModule_AddObject(module, "IN", input); pwm = Py_BuildValue("i", PWM); PyModule_AddObject(module, "HARD_PWM", pwm); serial = Py_BuildValue("i", SERIAL); PyModule_AddObject(module, "SERIAL", serial); i2c = Py_BuildValue("i", I2C); PyModule_AddObject(module, "I2C", i2c); spi = Py_BuildValue("i", SPI); PyModule_AddObject(module, "SPI", spi); unknown = Py_BuildValue("i", MODE_UNKNOWN); PyModule_AddObject(module, "UNKNOWN", unknown); board = Py_BuildValue("i", BOARD); PyModule_AddObject(module, "BOARD", board); bcm = Py_BuildValue("i", BCM); PyModule_AddObject(module, "BCM", bcm); pud_off = Py_BuildValue("i", PUD_OFF + PY_PUD_CONST_OFFSET); PyModule_AddObject(module, "PUD_OFF", pud_off); pud_up = Py_BuildValue("i", PUD_UP + PY_PUD_CONST_OFFSET); PyModule_AddObject(module, "PUD_UP", pud_up); pud_down = Py_BuildValue("i", PUD_DOWN + PY_PUD_CONST_OFFSET); PyModule_AddObject(module, "PUD_DOWN", pud_down); rising_edge = Py_BuildValue("i", RISING_EDGE + PY_EVENT_CONST_OFFSET); PyModule_AddObject(module, "RISING", rising_edge); falling_edge = Py_BuildValue("i", FALLING_EDGE + PY_EVENT_CONST_OFFSET); PyModule_AddObject(module, "FALLING", falling_edge); both_edge = Py_BuildValue("i", BOTH_EDGE + PY_EVENT_CONST_OFFSET); PyModule_AddObject(module, "BOTH", both_edge); } RPi.GPIO-0.6.3/source/py_gpio.c0000644000175000017500000007637013005464450015141 0ustar pipi00000000000000/* Copyright (c) 2012-2016 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "Python.h" #include "c_gpio.h" #include "event_gpio.h" #include "py_pwm.h" #include "cpuinfo.h" #include "constants.h" #include "common.h" static PyObject *rpi_revision; // deprecated static PyObject *board_info; static int gpio_warnings = 1; struct py_callback { unsigned int gpio; PyObject *py_cb; struct py_callback *next; }; static struct py_callback *py_callbacks = NULL; static int mmap_gpio_mem(void) { int result; if (module_setup) return 0; result = setup(); if (result == SETUP_DEVMEM_FAIL) { PyErr_SetString(PyExc_RuntimeError, "No access to /dev/mem. Try running as root!"); return 1; } else if (result == SETUP_MALLOC_FAIL) { PyErr_NoMemory(); return 2; } else if (result == SETUP_MMAP_FAIL) { PyErr_SetString(PyExc_RuntimeError, "Mmap of GPIO registers failed"); return 3; } else if (result == SETUP_CPUINFO_FAIL) { PyErr_SetString(PyExc_RuntimeError, "Unable to open /proc/cpuinfo"); return 4; } else if (result == SETUP_NOT_RPI_FAIL) { PyErr_SetString(PyExc_RuntimeError, "Not running on a RPi!"); return 5; } else { // result == SETUP_OK module_setup = 1; return 0; } } // python function cleanup(channel=None) static PyObject *py_cleanup(PyObject *self, PyObject *args, PyObject *kwargs) { int i; int chancount = -666; int found = 0; int channel = -666; unsigned int gpio; PyObject *chanlist = NULL; PyObject *chantuple = NULL; PyObject *tempobj; static char *kwlist[] = {"channel", NULL}; void cleanup_one(void) { // clean up any /sys/class exports event_cleanup(gpio); // set everything back to input if (gpio_direction[gpio] != -1) { setup_gpio(gpio, INPUT, PUD_OFF); gpio_direction[gpio] = -1; found = 1; } } if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &chanlist)) return NULL; if (chanlist == NULL) { // channel kwarg not set // do nothing #if PY_MAJOR_VERSION > 2 } else if (PyLong_Check(chanlist)) { channel = (int)PyLong_AsLong(chanlist); #else } else if (PyInt_Check(chanlist)) { channel = (int)PyInt_AsLong(chanlist); #endif if (PyErr_Occurred()) return NULL; chanlist = NULL; } else if (PyList_Check(chanlist)) { chancount = PyList_Size(chanlist); } else if (PyTuple_Check(chanlist)) { chantuple = chanlist; chanlist = NULL; chancount = PyTuple_Size(chantuple); } else { // raise exception PyErr_SetString(PyExc_ValueError, "Channel must be an integer or list/tuple of integers"); return NULL; } if (module_setup && !setup_error) { if (channel == -666 && chancount == -666) { // channel not set - cleanup everything // clean up any /sys/class exports event_cleanup_all(); // set everything back to input for (i=0; i<54; i++) { if (gpio_direction[i] != -1) { setup_gpio(i, INPUT, PUD_OFF); gpio_direction[i] = -1; found = 1; } } gpio_mode = MODE_UNKNOWN; } else if (channel != -666) { // channel was an int indicating single channel if (get_gpio_number(channel, &gpio)) return NULL; cleanup_one(); } else { // channel was a list/tuple for (i=0; i 2 if (PyLong_Check(tempobj)) { channel = (int)PyLong_AsLong(tempobj); #else if (PyInt_Check(tempobj)) { channel = (int)PyInt_AsLong(tempobj); #endif if (PyErr_Occurred()) return NULL; } else { PyErr_SetString(PyExc_ValueError, "Channel must be an integer"); return NULL; } if (get_gpio_number(channel, &gpio)) return NULL; cleanup_one(); } } } // check if any channels set up - if not warn about misuse of GPIO.cleanup() if (!found && gpio_warnings) { 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); } Py_RETURN_NONE; } // python function setup(channel(s), direction, pull_up_down=PUD_OFF, initial=None) static PyObject *py_setup_channel(PyObject *self, PyObject *args, PyObject *kwargs) { unsigned int gpio; int channel = -1; int direction; int i, chancount; PyObject *chanlist = NULL; PyObject *chantuple = NULL; PyObject *tempobj; int pud = PUD_OFF + PY_PUD_CONST_OFFSET; int initial = -1; static char *kwlist[] = {"channel", "direction", "pull_up_down", "initial", NULL}; int func; int setup_one(void) { if (get_gpio_number(channel, &gpio)) return 0; func = gpio_function(gpio); if (gpio_warnings && // warnings enabled and ((func != 0 && func != 1) || // (already one of the alt functions or (gpio_direction[gpio] == -1 && func == 1))) // already an output not set from this program) { PyErr_WarnEx(NULL, "This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.", 1); } // warn about pull/up down on i2c channels if (gpio_warnings) { if (rpiinfo.p1_revision == 0) { // compute module - do nothing } else if ((rpiinfo.p1_revision == 1 && (gpio == 0 || gpio == 1)) || (gpio == 2 || gpio == 3)) { if (pud == PUD_UP || pud == PUD_DOWN) PyErr_WarnEx(NULL, "A physical pull up resistor is fitted on this channel!", 1); } } if (direction == OUTPUT && (initial == LOW || initial == HIGH)) { output_gpio(gpio, initial); } setup_gpio(gpio, direction, pud); gpio_direction[gpio] = direction; return 1; } if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii", kwlist, &chanlist, &direction, &pud, &initial)) return NULL; #if PY_MAJOR_VERSION > 2 if (PyLong_Check(chanlist)) { channel = (int)PyLong_AsLong(chanlist); #else if (PyInt_Check(chanlist)) { channel = (int)PyInt_AsLong(chanlist); #endif if (PyErr_Occurred()) return NULL; chanlist = NULL; } else if (PyList_Check(chanlist)) { // do nothing } else if (PyTuple_Check(chanlist)) { chantuple = chanlist; chanlist = NULL; } else { // raise exception PyErr_SetString(PyExc_ValueError, "Channel must be an integer or list/tuple of integers"); return NULL; } // check module has been imported cleanly if (setup_error) { PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!"); return NULL; } if (mmap_gpio_mem()) return NULL; if (direction != INPUT && direction != OUTPUT) { PyErr_SetString(PyExc_ValueError, "An invalid direction was passed to setup()"); return 0; } if (direction == OUTPUT && pud != PUD_OFF + PY_PUD_CONST_OFFSET) { PyErr_SetString(PyExc_ValueError, "pull_up_down parameter is not valid for outputs"); return 0; } if (direction == INPUT && initial != -1) { PyErr_SetString(PyExc_ValueError, "initial parameter is not valid for inputs"); return 0; } if (direction == OUTPUT) pud = PUD_OFF + PY_PUD_CONST_OFFSET; pud -= PY_PUD_CONST_OFFSET; if (pud != PUD_OFF && pud != PUD_DOWN && pud != PUD_UP) { PyErr_SetString(PyExc_ValueError, "Invalid value for pull_up_down - should be either PUD_OFF, PUD_UP or PUD_DOWN"); return NULL; } if (chanlist) { chancount = PyList_Size(chanlist); } else if (chantuple) { chancount = PyTuple_Size(chantuple); } else { if (!setup_one()) return NULL; Py_RETURN_NONE; } for (i=0; i 2 if (PyLong_Check(tempobj)) { channel = (int)PyLong_AsLong(tempobj); #else if (PyInt_Check(tempobj)) { channel = (int)PyInt_AsLong(tempobj); #endif if (PyErr_Occurred()) return NULL; } else { PyErr_SetString(PyExc_ValueError, "Channel must be an integer"); return NULL; } if (!setup_one()) return NULL; } Py_RETURN_NONE; } // python function output(channel(s), value(s)) static PyObject *py_output_gpio(PyObject *self, PyObject *args) { unsigned int gpio; int channel = -1; int value = -1; int i; PyObject *chanlist = NULL; PyObject *valuelist = NULL; PyObject *chantuple = NULL; PyObject *valuetuple = NULL; PyObject *tempobj = NULL; int chancount = -1; int valuecount = -1; int output(void) { if (get_gpio_number(channel, &gpio)) return 0; if (gpio_direction[gpio] != OUTPUT) { PyErr_SetString(PyExc_RuntimeError, "The GPIO channel has not been set up as an OUTPUT"); return 0; } if (check_gpio_priv()) return 0; output_gpio(gpio, value); return 1; } if (!PyArg_ParseTuple(args, "OO", &chanlist, &valuelist)) return NULL; #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(chanlist)) { channel = (int)PyLong_AsLong(chanlist); #else if (PyInt_Check(chanlist)) { channel = (int)PyInt_AsLong(chanlist); #endif if (PyErr_Occurred()) return NULL; chanlist = NULL; } else if (PyList_Check(chanlist)) { // do nothing } else if (PyTuple_Check(chanlist)) { chantuple = chanlist; chanlist = NULL; } else { PyErr_SetString(PyExc_ValueError, "Channel must be an integer or list/tuple of integers"); return NULL; } #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(valuelist)) { value = (int)PyLong_AsLong(valuelist); #else if (PyInt_Check(valuelist)) { value = (int)PyInt_AsLong(valuelist); #endif if (PyErr_Occurred()) return NULL; valuelist = NULL; } else if (PyList_Check(valuelist)) { // do nothing } else if (PyTuple_Check(valuelist)) { valuetuple = valuelist; valuelist = NULL; } else { PyErr_SetString(PyExc_ValueError, "Value must be an integer/boolean or a list/tuple of integers/booleans"); return NULL; } if (chanlist) chancount = PyList_Size(chanlist); if (chantuple) chancount = PyTuple_Size(chantuple); if (valuelist) valuecount = PyList_Size(valuelist); if (valuetuple) valuecount = PyTuple_Size(valuetuple); if ((chancount != -1 && chancount != valuecount && valuecount != -1) || (chancount == -1 && valuecount != -1)) { PyErr_SetString(PyExc_RuntimeError, "Number of channels != number of values"); return NULL; } if (chancount == -1) { if (!output()) return NULL; Py_RETURN_NONE; } for (i=0; i= 3 if (PyLong_Check(tempobj)) { channel = (int)PyLong_AsLong(tempobj); #else if (PyInt_Check(tempobj)) { channel = (int)PyInt_AsLong(tempobj); #endif if (PyErr_Occurred()) return NULL; } else { PyErr_SetString(PyExc_ValueError, "Channel must be an integer"); return NULL; } // get value if (valuecount > 0) { if (valuelist) { if ((tempobj = PyList_GetItem(valuelist, i)) == NULL) { return NULL; } } else { // assume valuetuple if ((tempobj = PyTuple_GetItem(valuetuple, i)) == NULL) { return NULL; } } #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(tempobj)) { value = (int)PyLong_AsLong(tempobj); #else if (PyInt_Check(tempobj)) { value = (int)PyInt_AsLong(tempobj); #endif if (PyErr_Occurred()) return NULL; } else { PyErr_SetString(PyExc_ValueError, "Value must be an integer or boolean"); return NULL; } } if (!output()) return NULL; } Py_RETURN_NONE; } // python function value = input(channel) static PyObject *py_input_gpio(PyObject *self, PyObject *args) { unsigned int gpio; int channel; PyObject *value; if (!PyArg_ParseTuple(args, "i", &channel)) return NULL; if (get_gpio_number(channel, &gpio)) return NULL; // check channel is set up as an input or output if (gpio_direction[gpio] != INPUT && gpio_direction[gpio] != OUTPUT) { PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel first"); return NULL; } if (check_gpio_priv()) return NULL; if (input_gpio(gpio)) { value = Py_BuildValue("i", HIGH); } else { value = Py_BuildValue("i", LOW); } return value; } // python function setmode(mode) static PyObject *py_setmode(PyObject *self, PyObject *args) { int new_mode; if (!PyArg_ParseTuple(args, "i", &new_mode)) return NULL; if (gpio_mode != MODE_UNKNOWN && new_mode != gpio_mode) { PyErr_SetString(PyExc_ValueError, "A different mode has already been set!"); return NULL; } if (setup_error) { PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!"); return NULL; } if (new_mode != BOARD && new_mode != BCM) { PyErr_SetString(PyExc_ValueError, "An invalid mode was passed to setmode()"); return NULL; } if (rpiinfo.p1_revision == 0 && new_mode == BOARD) { PyErr_SetString(PyExc_RuntimeError, "BOARD numbering system not applicable on compute module"); return NULL; } gpio_mode = new_mode; Py_RETURN_NONE; } // python function getmode() static PyObject *py_getmode(PyObject *self, PyObject *args) { PyObject *value; if (setup_error) { PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!"); return NULL; } if (gpio_mode == MODE_UNKNOWN) Py_RETURN_NONE; value = Py_BuildValue("i", gpio_mode); return value; } static unsigned int chan_from_gpio(unsigned int gpio) { int chan; int chans; if (gpio_mode == BCM) return gpio; if (rpiinfo.p1_revision == 0) // not applicable for compute module return -1; else if (rpiinfo.p1_revision == 1 || rpiinfo.p1_revision == 2) chans = 26; else chans = 40; for (chan=1; chan<=chans; chan++) if (*(*pin_to_gpio+chan) == gpio) return chan; return -1; } static void run_py_callbacks(unsigned int gpio) { PyObject *result; PyGILState_STATE gstate; struct py_callback *cb = py_callbacks; while (cb != NULL) { if (cb->gpio == gpio) { // run callback gstate = PyGILState_Ensure(); result = PyObject_CallFunction(cb->py_cb, "i", chan_from_gpio(gpio)); if (result == NULL && PyErr_Occurred()){ PyErr_Print(); PyErr_Clear(); } Py_XDECREF(result); PyGILState_Release(gstate); } cb = cb->next; } } static int add_py_callback(unsigned int gpio, PyObject *cb_func) { struct py_callback *new_py_cb; struct py_callback *cb = py_callbacks; // add callback to py_callbacks list new_py_cb = malloc(sizeof(struct py_callback)); if (new_py_cb == 0) { PyErr_NoMemory(); return -1; } new_py_cb->py_cb = cb_func; Py_XINCREF(cb_func); // Add a reference to new callback new_py_cb->gpio = gpio; new_py_cb->next = NULL; if (py_callbacks == NULL) { py_callbacks = new_py_cb; } else { // add to end of list while (cb->next != NULL) cb = cb->next; cb->next = new_py_cb; } add_edge_callback(gpio, run_py_callbacks); return 0; } // python function add_event_callback(gpio, callback) static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject *kwargs) { unsigned int gpio; int channel; PyObject *cb_func; char *kwlist[] = {"gpio", "callback", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iO|i", kwlist, &channel, &cb_func)) return NULL; if (!PyCallable_Check(cb_func)) { PyErr_SetString(PyExc_TypeError, "Parameter must be callable"); return NULL; } if (get_gpio_number(channel, &gpio)) return NULL; // check channel is set up as an input if (gpio_direction[gpio] != INPUT) { PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first"); return NULL; } if (!gpio_event_added(gpio)) { PyErr_SetString(PyExc_RuntimeError, "Add event detection using add_event_detect first before adding a callback"); return NULL; } if (add_py_callback(gpio, cb_func) != 0) return NULL; Py_RETURN_NONE; } // python function add_event_detect(gpio, edge, callback=None, bouncetime=None) static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *kwargs) { unsigned int gpio; int channel, edge, result; int bouncetime = -666; PyObject *cb_func = NULL; char *kwlist[] = {"gpio", "edge", "callback", "bouncetime", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|Oi", kwlist, &channel, &edge, &cb_func, &bouncetime)) return NULL; if (cb_func != NULL && !PyCallable_Check(cb_func)) { PyErr_SetString(PyExc_TypeError, "Parameter must be callable"); return NULL; } if (get_gpio_number(channel, &gpio)) return NULL; // check channel is set up as an input if (gpio_direction[gpio] != INPUT) { PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first"); return NULL; } // is edge valid value edge -= PY_EVENT_CONST_OFFSET; if (edge != RISING_EDGE && edge != FALLING_EDGE && edge != BOTH_EDGE) { PyErr_SetString(PyExc_ValueError, "The edge must be set to RISING, FALLING or BOTH"); return NULL; } if (bouncetime <= 0 && bouncetime != -666) { PyErr_SetString(PyExc_ValueError, "Bouncetime must be greater than 0"); return NULL; } if (check_gpio_priv()) return NULL; if ((result = add_edge_detect(gpio, edge, bouncetime)) != 0) // starts a thread { if (result == 1) { PyErr_SetString(PyExc_RuntimeError, "Conflicting edge detection already enabled for this GPIO channel"); return NULL; } else { PyErr_SetString(PyExc_RuntimeError, "Failed to add edge detection"); return NULL; } } if (cb_func != NULL) if (add_py_callback(gpio, cb_func) != 0) return NULL; Py_RETURN_NONE; } // python function remove_event_detect(gpio) static PyObject *py_remove_event_detect(PyObject *self, PyObject *args) { unsigned int gpio; int channel; struct py_callback *cb = py_callbacks; struct py_callback *temp; struct py_callback *prev = NULL; if (!PyArg_ParseTuple(args, "i", &channel)) return NULL; if (get_gpio_number(channel, &gpio)) return NULL; // remove all python callbacks for gpio while (cb != NULL) { if (cb->gpio == gpio) { Py_XDECREF(cb->py_cb); if (prev == NULL) py_callbacks = cb->next; else prev->next = cb->next; temp = cb; cb = cb->next; free(temp); } else { prev = cb; cb = cb->next; } } if (check_gpio_priv()) return NULL; remove_edge_detect(gpio); Py_RETURN_NONE; } // python function value = event_detected(channel) static PyObject *py_event_detected(PyObject *self, PyObject *args) { unsigned int gpio; int channel; if (!PyArg_ParseTuple(args, "i", &channel)) return NULL; if (get_gpio_number(channel, &gpio)) return NULL; if (event_detected(gpio)) Py_RETURN_TRUE; else Py_RETURN_FALSE; } // python function channel = wait_for_edge(channel, edge, bouncetime=None, timeout=None) static PyObject *py_wait_for_edge(PyObject *self, PyObject *args, PyObject *kwargs) { unsigned int gpio; int channel, edge, result; int bouncetime = -666; // None int timeout = -1; // None static char *kwlist[] = {"channel", "edge", "bouncetime", "timeout", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|ii", kwlist, &channel, &edge, &bouncetime, &timeout)) return NULL; if (get_gpio_number(channel, &gpio)) return NULL; // check channel is setup as an input if (gpio_direction[gpio] != INPUT) { PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first"); return NULL; } // is edge a valid value? edge -= PY_EVENT_CONST_OFFSET; if (edge != RISING_EDGE && edge != FALLING_EDGE && edge != BOTH_EDGE) { PyErr_SetString(PyExc_ValueError, "The edge must be set to RISING, FALLING or BOTH"); return NULL; } if (bouncetime <= 0 && bouncetime != -666) { PyErr_SetString(PyExc_ValueError, "Bouncetime must be greater than 0"); return NULL; } if (timeout <= 0 && timeout != -1) { PyErr_SetString(PyExc_ValueError, "Timeout must be greater than 0"); return NULL; } if (check_gpio_priv()) return NULL; Py_BEGIN_ALLOW_THREADS // disable GIL result = blocking_wait_for_edge(gpio, edge, bouncetime, timeout); Py_END_ALLOW_THREADS // enable GIL if (result == 0) { Py_RETURN_NONE; } else if (result == -1) { PyErr_SetString(PyExc_RuntimeError, "Conflicting edge detection events already exist for this GPIO channel"); return NULL; } else if (result == -2) { PyErr_SetString(PyExc_RuntimeError, "Error waiting for edge"); return NULL; } else { return Py_BuildValue("i", channel); } } // python function value = gpio_function(channel) static PyObject *py_gpio_function(PyObject *self, PyObject *args) { unsigned int gpio; int channel; int f; PyObject *func; if (!PyArg_ParseTuple(args, "i", &channel)) return NULL; if (get_gpio_number(channel, &gpio)) return NULL; if (mmap_gpio_mem()) return NULL; f = gpio_function(gpio); switch (f) { case 0 : f = INPUT; break; case 1 : f = OUTPUT; break; // ALT 0 case 4 : switch (gpio) { case 0 : case 1 : case 2 : case 3 : f = I2C; break; case 7 : case 8 : case 9 : case 10 : case 11 : f = SPI; break; case 12 : case 13 : f = PWM; break; case 14 : case 15 : f = SERIAL; break; case 28 : case 29 : f = I2C; break; default : f = MODE_UNKNOWN; break; } break; // ALT 5 case 2 : if (gpio == 18 || gpio == 19) f = PWM; else f = MODE_UNKNOWN; break; // ALT 4 case 3 : switch (gpio) { case 16 : case 17 : case 18 : case 19 : case 20 : case 21 : f = SPI; break; default : f = MODE_UNKNOWN; break; } break; default : f = MODE_UNKNOWN; break; } func = Py_BuildValue("i", f); return func; } // python function setwarnings(state) static PyObject *py_setwarnings(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "i", &gpio_warnings)) return NULL; if (setup_error) { PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!"); return NULL; } Py_RETURN_NONE; } static const char moduledocstring[] = "GPIO functionality of a Raspberry Pi using Python"; PyMethodDef rpi_gpio_methods[] = { {"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 or BCM 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"}, {"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."}, {"output", py_output_gpio, METH_VARARGS, "Output to a GPIO channel or list of channels\nchannel - either board pin number or BCM number depending on which mode is set.\nvalue - 0/1 or False/True or LOW/HIGH"}, {"input", py_input_gpio, METH_VARARGS, "Input from a GPIO channel. Returns HIGH=1=True or LOW=0=False\nchannel - either board pin number or BCM number depending on which mode is set."}, {"setmode", py_setmode, METH_VARARGS, "Set up numbering mode to use for channels.\nBOARD - Use Raspberry Pi board numbers\nBCM - Use Broadcom GPIO 00..nn numbers"}, {"getmode", py_getmode, METH_VARARGS, "Get numbering mode used for channel numbers.\nReturns BOARD, BCM or None"}, {"add_event_detect", (PyCFunction)py_add_event_detect, METH_VARARGS | METH_KEYWORDS, "Enable edge detection events for a particular GPIO channel.\nchannel - either board pin number or BCM number depending on which mode is set.\nedge - RISING, FALLING or BOTH\n[callback] - A callback function for the event (optional)\n[bouncetime] - Switch bounce timeout in ms for callback"}, {"remove_event_detect", py_remove_event_detect, METH_VARARGS, "Remove edge detection for a particular GPIO channel\nchannel - either board pin number or BCM number depending on which mode is set."}, {"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 or BCM number depending on which mode is set."}, {"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 or BCM number depending on which mode is set.\ncallback - a callback function"}, {"wait_for_edge", (PyCFunction)py_wait_for_edge, METH_VARARGS | METH_KEYWORDS, "Wait for an edge. Returns the channel number or None on timeout.\nchannel - either board pin number or BCM number depending on which mode is set.\nedge - RISING, FALLING or BOTH\n[bouncetime] - time allowed between calls to allow for switchbounce\n[timeout] - timeout in ms"}, {"gpio_function", py_gpio_function, METH_VARARGS, "Return the current GPIO function (IN, OUT, PWM, SERIAL, I2C, SPI)\nchannel - either board pin number or BCM number depending on which mode is set."}, {"setwarnings", py_setwarnings, METH_VARARGS, "Enable or disable warning messages"}, {NULL, NULL, 0, NULL} }; #if PY_MAJOR_VERSION > 2 static struct PyModuleDef rpigpiomodule = { PyModuleDef_HEAD_INIT, "RPi._GPIO", // name of module moduledocstring, // module documentation, may be NULL -1, // size of per-interpreter state of the module, or -1 if the module keeps state in global variables. rpi_gpio_methods }; #endif #if PY_MAJOR_VERSION > 2 PyMODINIT_FUNC PyInit__GPIO(void) #else PyMODINIT_FUNC init_GPIO(void) #endif { int i; PyObject *module = NULL; #if PY_MAJOR_VERSION > 2 if ((module = PyModule_Create(&rpigpiomodule)) == NULL) return NULL; #else if ((module = Py_InitModule3("RPi._GPIO", rpi_gpio_methods, moduledocstring)) == NULL) return; #endif define_constants(module); for (i=0; i<54; i++) gpio_direction[i] = -1; // detect board revision and set up accordingly if (get_rpi_info(&rpiinfo)) { PyErr_SetString(PyExc_RuntimeError, "This module can only be run on a Raspberry Pi!"); setup_error = 1; #if PY_MAJOR_VERSION > 2 return NULL; #else return; #endif } board_info = Py_BuildValue("{sissssssssss}", "P1_REVISION",rpiinfo.p1_revision, "REVISION",&rpiinfo.revision, "TYPE",rpiinfo.type, "MANUFACTURER",rpiinfo.manufacturer, "PROCESSOR",rpiinfo.processor, "RAM",rpiinfo.ram); PyModule_AddObject(module, "RPI_INFO", board_info); if (rpiinfo.p1_revision == 1) { pin_to_gpio = &pin_to_gpio_rev1; } else if (rpiinfo.p1_revision == 2) { pin_to_gpio = &pin_to_gpio_rev2; } else { // assume model B+ or A+ or 2B pin_to_gpio = &pin_to_gpio_rev3; } rpi_revision = Py_BuildValue("i", rpiinfo.p1_revision); // deprecated PyModule_AddObject(module, "RPI_REVISION", rpi_revision); // deprecated // Add PWM class if (PWM_init_PWMType() == NULL) #if PY_MAJOR_VERSION > 2 return NULL; #else return; #endif Py_INCREF(&PWMType); PyModule_AddObject(module, "PWM", (PyObject*)&PWMType); if (!PyEval_ThreadsInitialized()) PyEval_InitThreads(); // register exit functions - last declared is called first if (Py_AtExit(cleanup) != 0) { setup_error = 1; cleanup(); #if PY_MAJOR_VERSION > 2 return NULL; #else return; #endif } if (Py_AtExit(event_cleanup_all) != 0) { setup_error = 1; cleanup(); #if PY_MAJOR_VERSION > 2 return NULL; #else return; #endif } #if PY_MAJOR_VERSION > 2 return module; #else return; #endif } RPi.GPIO-0.6.3/source/common.h0000644000175000017500000000302513005464450014753 0ustar pipi00000000000000/* Copyright (c) 2013-2015 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "cpuinfo.h" #define MODE_UNKNOWN -1 #define BOARD 10 #define BCM 11 #define SERIAL 40 #define SPI 41 #define I2C 42 #define PWM 43 int gpio_mode; const int pin_to_gpio_rev1[41]; const int pin_to_gpio_rev2[41]; const int pin_to_gpio_rev3[41]; const int (*pin_to_gpio)[41]; int gpio_direction[54]; rpi_info rpiinfo; int setup_error; int module_setup; int check_gpio_priv(void); int get_gpio_number(int channel, unsigned int *gpio); RPi.GPIO-0.6.3/source/event_gpio.c0000644000175000017500000003452713005464450015630 0ustar pipi00000000000000/* Copyright (c) 2013-2016 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include "event_gpio.h" const char *stredge[4] = {"none", "rising", "falling", "both"}; struct gpios { unsigned int gpio; int value_fd; int exported; int edge; int initial_thread; int initial_wait; int thread_added; int bouncetime; unsigned long long lastcall; struct gpios *next; }; struct gpios *gpio_list = NULL; // event callbacks struct callback { unsigned int gpio; void (*func)(unsigned int gpio); struct callback *next; }; struct callback *callbacks = NULL; pthread_t threads; int event_occurred[54] = { 0 }; int thread_running = 0; int epfd_thread = -1; int epfd_blocking = -1; /************* /sys/class/gpio functions ************/ int gpio_export(unsigned int gpio) { int fd, len; char str_gpio[3]; if ((fd = open("/sys/class/gpio/export", O_WRONLY)) < 0) return -1; len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio); write(fd, str_gpio, len); close(fd); return 0; } int gpio_unexport(unsigned int gpio) { int fd, len; char str_gpio[3]; if ((fd = open("/sys/class/gpio/unexport", O_WRONLY)) < 0) return -1; len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio); write(fd, str_gpio, len); close(fd); return 0; } int gpio_set_direction(unsigned int gpio, unsigned int in_flag) { int retry; struct timespec delay; int fd; char filename[33]; snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio); // retry waiting for udev to set correct file permissions delay.tv_sec = 0; delay.tv_nsec = 10000000L; // 10ms for (retry=0; retry<100; retry++) { if ((fd = open(filename, O_WRONLY)) >= 0) break; nanosleep(&delay, NULL); } if (retry >= 100) return -1; if (in_flag) write(fd, "in", 3); else write(fd, "out", 4); close(fd); return 0; } int gpio_set_edge(unsigned int gpio, unsigned int edge) { int fd; char filename[28]; snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/edge", gpio); if ((fd = open(filename, O_WRONLY)) < 0) return -1; write(fd, stredge[edge], strlen(stredge[edge]) + 1); close(fd); return 0; } int open_value_file(unsigned int gpio) { int fd; char filename[29]; // create file descriptor of value file snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio); if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0) return -1; return fd; } /********* gpio list functions **********/ struct gpios *get_gpio(unsigned int gpio) { struct gpios *g = gpio_list; while (g != NULL) { if (g->gpio == gpio) return g; g = g->next; } return NULL; } struct gpios *get_gpio_from_value_fd(int fd) { struct gpios *g = gpio_list; while (g != NULL) { if (g->value_fd == fd) return g; g = g->next; } return NULL; } struct gpios *new_gpio(unsigned int gpio) { struct gpios *new_gpio; new_gpio = malloc(sizeof(struct gpios)); if (new_gpio == 0) { return NULL; // out of memory } new_gpio->gpio = gpio; if (gpio_export(gpio) != 0) { free(new_gpio); return NULL; } new_gpio->exported = 1; if (gpio_set_direction(gpio,1) != 0) { // 1==input free(new_gpio); return NULL; } if ((new_gpio->value_fd = open_value_file(gpio)) == -1) { gpio_unexport(gpio); free(new_gpio); return NULL; } new_gpio->initial_thread = 1; new_gpio->initial_wait = 1; new_gpio->bouncetime = -666; new_gpio->lastcall = 0; new_gpio->thread_added = 0; if (gpio_list == NULL) { new_gpio->next = NULL; } else { new_gpio->next = gpio_list; } gpio_list = new_gpio; return new_gpio; } void delete_gpio(unsigned int gpio) { struct gpios *g = gpio_list; struct gpios *temp; struct gpios *prev = NULL; while (g != NULL) { if (g->gpio == gpio) { if (prev == NULL) gpio_list = g->next; else prev->next = g->next; temp = g; g = g->next; free(temp); return; } else { prev = g; g = g->next; } } } int gpio_event_added(unsigned int gpio) { struct gpios *g = gpio_list; while (g != NULL) { if (g->gpio == gpio) return g->edge; g = g->next; } return 0; } /******* callback list functions ********/ int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio)) { struct callback *cb = callbacks; struct callback *new_cb; new_cb = malloc(sizeof(struct callback)); if (new_cb == 0) return -1; // out of memory new_cb->gpio = gpio; new_cb->func = func; new_cb->next = NULL; if (callbacks == NULL) { // start new list callbacks = new_cb; } else { // add to end of list while (cb->next != NULL) cb = cb->next; cb->next = new_cb; } return 0; } int callback_exists(unsigned int gpio) { struct callback *cb = callbacks; while (cb != NULL) { if (cb->gpio == gpio) return 1; cb = cb->next; } return 0; } void run_callbacks(unsigned int gpio) { struct callback *cb = callbacks; while (cb != NULL) { if (cb->gpio == gpio) cb->func(cb->gpio); cb = cb->next; } } void remove_callbacks(unsigned int gpio) { struct callback *cb = callbacks; struct callback *temp; struct callback *prev = NULL; while (cb != NULL) { if (cb->gpio == gpio) { if (prev == NULL) callbacks = cb->next; else prev->next = cb->next; temp = cb; cb = cb->next; free(temp); } else { prev = cb; cb = cb->next; } } } void *poll_thread(void *threadarg) { struct epoll_event events; char buf; struct timeval tv_timenow; unsigned long long timenow; struct gpios *g; int n; thread_running = 1; while (thread_running) { n = epoll_wait(epfd_thread, &events, 1, -1); if (n > 0) { lseek(events.data.fd, 0, SEEK_SET); if (read(events.data.fd, &buf, 1) != 1) { thread_running = 0; pthread_exit(NULL); } g = get_gpio_from_value_fd(events.data.fd); if (g->initial_thread) { // ignore first epoll trigger g->initial_thread = 0; } else { gettimeofday(&tv_timenow, NULL); timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec; if (g->bouncetime == -666 || timenow - g->lastcall > g->bouncetime*1000 || g->lastcall == 0 || g->lastcall > timenow) { g->lastcall = timenow; event_occurred[g->gpio] = 1; run_callbacks(g->gpio); } } } else if (n == -1) { /* If a signal is received while we are waiting, epoll_wait will return with an EINTR error. Just try again in that case. */ if (errno == EINTR) { continue; } thread_running = 0; pthread_exit(NULL); } } thread_running = 0; pthread_exit(NULL); } void remove_edge_detect(unsigned int gpio) { struct epoll_event ev; struct gpios *g = get_gpio(gpio); if (g == NULL) return; // delete epoll of fd ev.events = EPOLLIN | EPOLLET | EPOLLPRI; ev.data.fd = g->value_fd; epoll_ctl(epfd_thread, EPOLL_CTL_DEL, g->value_fd, &ev); // delete callbacks for gpio remove_callbacks(gpio); // btc fixme - check return result?? gpio_set_edge(gpio, NO_EDGE); g->edge = NO_EDGE; if (g->value_fd != -1) close(g->value_fd); // btc fixme - check return result?? gpio_unexport(gpio); event_occurred[gpio] = 0; delete_gpio(gpio); } int event_detected(unsigned int gpio) { if (event_occurred[gpio]) { event_occurred[gpio] = 0; return 1; } else { return 0; } } void event_cleanup(unsigned int gpio) // gpio of -666 means clean every channel used { struct gpios *g = gpio_list; struct gpios *temp = NULL; while (g != NULL) { if ((gpio == -666) || (g->gpio == gpio)) temp = g->next; remove_edge_detect(g->gpio); g = temp; } if (gpio_list == NULL) if (epfd_blocking != -1) close(epfd_blocking); epfd_blocking = -1; if (epfd_thread != -1) close(epfd_thread); epfd_thread = -1; thread_running = 0; } void event_cleanup_all(void) { event_cleanup(-666); } int add_edge_detect(unsigned int gpio, unsigned int edge, int bouncetime) // return values: // 0 - Success // 1 - Edge detection already added // 2 - Other error { pthread_t threads; struct epoll_event ev; long t = 0; struct gpios *g; int i = -1; i = gpio_event_added(gpio); if (i == 0) { // event not already added if ((g = new_gpio(gpio)) == NULL) return 2; gpio_set_edge(gpio, edge); g->edge = edge; g->bouncetime = bouncetime; } else if (i == edge) { // get existing event g = get_gpio(gpio); if ((bouncetime != -666 && g->bouncetime != bouncetime) || // different event bouncetime used (g->thread_added)) // event already added return 1; } else { return 1; } // create epfd_thread if not already open if ((epfd_thread == -1) && ((epfd_thread = epoll_create(1)) == -1)) return 2; // add to epoll fd ev.events = EPOLLIN | EPOLLET | EPOLLPRI; ev.data.fd = g->value_fd; if (epoll_ctl(epfd_thread, EPOLL_CTL_ADD, g->value_fd, &ev) == -1) { remove_edge_detect(gpio); return 2; } g->thread_added = 1; // start poll thread if it is not already running if (!thread_running) { if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0) { remove_edge_detect(gpio); return 2; } } return 0; } int blocking_wait_for_edge(unsigned int gpio, unsigned int edge, int bouncetime, int timeout) // return values: // 1 - Success (edge detected) // 0 - Timeout // -1 - Edge detection already added // -2 - Other error { int n, ed; struct epoll_event events, ev; char buf; struct gpios *g = NULL; struct timeval tv_timenow; unsigned long long timenow; int finished = 0; int initial_edge = 1; if (callback_exists(gpio)) return -1; // add gpio if it has not been added already ed = gpio_event_added(gpio); if (ed == edge) { // get existing record g = get_gpio(gpio); if (g->bouncetime != -666 && g->bouncetime != bouncetime) { return -1; } } else if (ed == NO_EDGE) { // not found so add event if ((g = new_gpio(gpio)) == NULL) { return -2; } gpio_set_edge(gpio, edge); g->edge = edge; g->bouncetime = bouncetime; } else { // ed != edge - event for a different edge g = get_gpio(gpio); gpio_set_edge(gpio, edge); g->edge = edge; g->bouncetime = bouncetime; g->initial_wait = 1; } // create epfd_blocking if not already open if ((epfd_blocking == -1) && ((epfd_blocking = epoll_create(1)) == -1)) { return -2; } // add to epoll fd ev.events = EPOLLIN | EPOLLET | EPOLLPRI; ev.data.fd = g->value_fd; if (epoll_ctl(epfd_blocking, EPOLL_CTL_ADD, g->value_fd, &ev) == -1) { return -2; } // wait for edge while (!finished) { n = epoll_wait(epfd_blocking, &events, 1, timeout); if (n == -1) { /* If a signal is received while we are waiting, epoll_wait will return with an EINTR error. Just try again in that case. */ if (errno == EINTR) { continue; } epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev); return -2; } if (initial_edge) { // first time triggers with current state, so ignore initial_edge = 0; } else { gettimeofday(&tv_timenow, NULL); timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec; if (g->bouncetime == -666 || timenow - g->lastcall > g->bouncetime*1000 || g->lastcall == 0 || g->lastcall > timenow) { g->lastcall = timenow; finished = 1; } } } // check event was valid if (n > 0) { lseek(events.data.fd, 0, SEEK_SET); if ((read(events.data.fd, &buf, 1) != 1) || (events.data.fd != g->value_fd)) { epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev); return -2; } } epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev); if (n == 0) { return 0; // timeout } else { return 1; // edge found } } RPi.GPIO-0.6.3/source/soft_pwm.c0000644000175000017500000001144413005464450015320 0ustar pipi00000000000000/* Copyright (c) 2013 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include "c_gpio.h" #include "soft_pwm.h" pthread_t threads; struct pwm { unsigned int gpio; float freq; float dutycycle; float basetime; float slicetime; struct timespec req_on, req_off; int running; struct pwm *next; }; struct pwm *pwm_list = NULL; void remove_pwm(unsigned int gpio) { struct pwm *p = pwm_list; struct pwm *prev = NULL; struct pwm *temp; while (p != NULL) { if (p->gpio == gpio) { if (prev == NULL) pwm_list = p->next; else prev->next = p->next; temp = p; p = p->next; free(temp); } else { prev = p; p = p->next; } } } void calculate_times(struct pwm *p) { long long usec; usec = (long long)(p->dutycycle * p->slicetime * 1000.0); p->req_on.tv_sec = (int)(usec / 1000000LL); usec -= (long long)p->req_on.tv_sec * 1000000LL; p->req_on.tv_nsec = (long)usec * 1000L; usec = (long long)((100.0-p->dutycycle) * p->slicetime * 1000.0); p->req_off.tv_sec = (int)(usec / 1000000LL); usec -= (long long)p->req_off.tv_sec * 1000000LL; p->req_off.tv_nsec = (long)usec * 1000L; } void full_sleep(struct timespec *req) { struct timespec rem = {0}; if (nanosleep(req,&rem) == -1) full_sleep(&rem); } void *pwm_thread(void *threadarg) { struct pwm *p = (struct pwm *)threadarg; while (p->running) { if (p->dutycycle > 0.0) { output_gpio(p->gpio, 1); full_sleep(&p->req_on); } if (p->dutycycle < 100.0) { output_gpio(p->gpio, 0); full_sleep(&p->req_off); } } // clean up output_gpio(p->gpio, 0); remove_pwm(p->gpio); pthread_exit(NULL); } struct pwm *add_new_pwm(unsigned int gpio) { struct pwm *new_pwm; new_pwm = malloc(sizeof(struct pwm)); new_pwm->gpio = gpio; new_pwm->running = 0; new_pwm->next = NULL; // default to 1 kHz frequency, dutycycle 0.0 new_pwm->freq = 1000.0; new_pwm->dutycycle = 0.0; new_pwm->basetime = 1.0; // 1 ms new_pwm->slicetime = 0.01; // 0.01 ms calculate_times(new_pwm); return new_pwm; } struct pwm *find_pwm(unsigned int gpio) { struct pwm *p = pwm_list; if (pwm_list == NULL) { pwm_list = add_new_pwm(gpio); return pwm_list; } while (p != NULL) { if (p->gpio == gpio) return p; if (p->next == NULL) { p->next = add_new_pwm(gpio); return p->next; } p = p->next; } return NULL; } void pwm_set_duty_cycle(unsigned int gpio, float dutycycle) { struct pwm *p; if (dutycycle < 0.0 || dutycycle > 100.0) { // btc fixme - error return; } if ((p = find_pwm(gpio)) != NULL) { p->dutycycle = dutycycle; calculate_times(p); } } void pwm_set_frequency(unsigned int gpio, float freq) { struct pwm *p; if (freq <= 0.0) // to avoid divide by zero { // btc fixme - error return; } if ((p = find_pwm(gpio)) != NULL) { p->basetime = 1000.0 / freq; // calculated in ms p->slicetime = p->basetime / 100.0; calculate_times(p); } } void pwm_start(unsigned int gpio) { struct pwm *p; if (((p = find_pwm(gpio)) == NULL) || p->running) return; p->running = 1; if (pthread_create(&threads, NULL, pwm_thread, (void *)p) != 0) { // btc fixme - error p->running = 0; return; } } void pwm_stop(unsigned int gpio) { struct pwm *p; if ((p = find_pwm(gpio)) != NULL) p->running = 0; } RPi.GPIO-0.6.3/source/event_gpio.h0000644000175000017500000000313213005464450015621 0ustar pipi00000000000000/* Copyright (c) 2013-2015 Ben Croston Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define NO_EDGE 0 #define RISING_EDGE 1 #define FALLING_EDGE 2 #define BOTH_EDGE 3 int add_edge_detect(unsigned int gpio, unsigned int edge, int bouncetime); void remove_edge_detect(unsigned int gpio); int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio)); int event_detected(unsigned int gpio); int gpio_event_added(unsigned int gpio); int event_initialise(void); void event_cleanup(unsigned int gpio); void event_cleanup_all(void); int blocking_wait_for_edge(unsigned int gpio, unsigned int edge, int bouncetime, int timeout);