mirror of
				https://github.com/KevinMidboe/python-gpiozero.git
				synced 2025-10-29 17:50:37 +00:00 
			
		
		
		
	Related to @lurch's comments on #148, this PR contains a database of pins for each Pi revision, along with various other bits of miscellany (I might've gotten a bit carried away here...). Any corrections/extensions welcome!
		
			
				
	
	
		
			231 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			231 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from __future__ import (
 | |
|     unicode_literals,
 | |
|     absolute_import,
 | |
|     print_function,
 | |
|     division,
 | |
|     )
 | |
| str = type('')
 | |
| 
 | |
| from RPi import GPIO
 | |
| 
 | |
| from . import Pin
 | |
| from .data import pi_info
 | |
| from ..exc import (
 | |
|     PinInvalidFunction,
 | |
|     PinSetInput,
 | |
|     PinFixedPull,
 | |
|     PinInvalidPull,
 | |
|     PinInvalidState,
 | |
|     PinInvalidBounce,
 | |
|     PinPWMFixedValue,
 | |
|     )
 | |
| 
 | |
| 
 | |
| class RPiGPIOPin(Pin):
 | |
|     """
 | |
|     Uses the `RPi.GPIO`_ library to interface to the Pi's GPIO pins. This is
 | |
|     the default pin implementation if the RPi.GPIO library is installed.
 | |
|     Supports all features including PWM (via software).
 | |
| 
 | |
|     Because this is the default pin implementation you can use it simply by
 | |
|     specifying an integer number for the pin in most operations, e.g.::
 | |
| 
 | |
|         from gpiozero import LED
 | |
| 
 | |
|         led = LED(12)
 | |
| 
 | |
|     However, you can also construct RPi.GPIO pins manually if you wish::
 | |
| 
 | |
|         from gpiozero.pins.rpigpio import RPiGPIOPin
 | |
|         from gpiozero import LED
 | |
| 
 | |
|         led = LED(RPiGPIOPin(12))
 | |
| 
 | |
|     .. _RPi.GPIO: https://pypi.python.org/pypi/RPi.GPIO
 | |
|     """
 | |
| 
 | |
|     _PINS = {}
 | |
| 
 | |
|     GPIO_FUNCTIONS = {
 | |
|         'input':   GPIO.IN,
 | |
|         'output':  GPIO.OUT,
 | |
|         'i2c':     GPIO.I2C,
 | |
|         'spi':     GPIO.SPI,
 | |
|         'pwm':     GPIO.HARD_PWM,
 | |
|         'serial':  GPIO.SERIAL,
 | |
|         'unknown': GPIO.UNKNOWN,
 | |
|         }
 | |
| 
 | |
|     GPIO_PULL_UPS = {
 | |
|         'up':       GPIO.PUD_UP,
 | |
|         'down':     GPIO.PUD_DOWN,
 | |
|         'floating': GPIO.PUD_OFF,
 | |
|         }
 | |
| 
 | |
|     GPIO_EDGES = {
 | |
|         'both':    GPIO.BOTH,
 | |
|         'rising':  GPIO.RISING,
 | |
|         'falling': GPIO.FALLING,
 | |
|         }
 | |
| 
 | |
|     GPIO_FUNCTION_NAMES = {v: k for (k, v) in GPIO_FUNCTIONS.items()}
 | |
|     GPIO_PULL_UP_NAMES = {v: k for (k, v) in GPIO_PULL_UPS.items()}
 | |
|     GPIO_EDGES_NAMES = {v: k for (k, v) in GPIO_EDGES.items()}
 | |
| 
 | |
|     PI_INFO = None
 | |
| 
 | |
|     def __new__(cls, number):
 | |
|         if not cls._PINS:
 | |
|             GPIO.setmode(GPIO.BCM)
 | |
|             GPIO.setwarnings(False)
 | |
|         if cls.PI_INFO is None:
 | |
|             cls.PI_INFO = pi_info()
 | |
|         try:
 | |
|             return cls._PINS[number]
 | |
|         except KeyError:
 | |
|             self = super(RPiGPIOPin, cls).__new__(cls)
 | |
|             cls._PINS[number] = self
 | |
|             self._number = number
 | |
|             self._pull = 'up' if cls.PI_INFO.pulled_up('GPIO%d' % number) else 'floating'
 | |
|             self._pwm = None
 | |
|             self._frequency = None
 | |
|             self._duty_cycle = None
 | |
|             self._bounce = -666
 | |
|             self._when_changed = None
 | |
|             self._edges = GPIO.BOTH
 | |
|             GPIO.setup(self._number, GPIO.IN, self.GPIO_PULL_UPS[self._pull])
 | |
|             return self
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return "GPIO%d" % self._number
 | |
| 
 | |
|     @property
 | |
|     def number(self):
 | |
|         return self._number
 | |
| 
 | |
|     def close(self):
 | |
|         self.frequency = None
 | |
|         self.when_changed = None
 | |
|         GPIO.cleanup(self._number)
 | |
| 
 | |
|     def output_with_state(self, state):
 | |
|         self._pull = 'floating'
 | |
|         GPIO.setup(self._number, GPIO.OUT, initial=state)
 | |
| 
 | |
|     def input_with_pull(self, pull):
 | |
|         if pull != 'up' and self.PI_INFO.pulled_up('GPIO%d' % self._number):
 | |
|             raise PinFixedPull('%r has a physical pull-up resistor' % self)
 | |
|         try:
 | |
|             GPIO.setup(self._number, GPIO.IN, self.GPIO_PULL_UPS[pull])
 | |
|             self._pull = pull
 | |
|         except KeyError:
 | |
|             raise PinInvalidPull('invalid pull "%s" for pin %r' % (pull, self))
 | |
| 
 | |
|     def _get_function(self):
 | |
|         return self.GPIO_FUNCTION_NAMES[GPIO.gpio_function(self._number)]
 | |
| 
 | |
|     def _set_function(self, value):
 | |
|         if value != 'input':
 | |
|             self._pull = 'floating'
 | |
|         if value in ('input', 'output') and value in self.GPIO_FUNCTIONS:
 | |
|             GPIO.setup(self._number, self.GPIO_FUNCTIONS[value], self.GPIO_PULL_UPS[self._pull])
 | |
|         else:
 | |
|             raise PinInvalidFunction('invalid function "%s" for pin %r' % (value, self))
 | |
| 
 | |
|     def _get_state(self):
 | |
|         if self._pwm:
 | |
|             return self._duty_cycle
 | |
|         else:
 | |
|             return GPIO.input(self._number)
 | |
| 
 | |
|     def _set_state(self, value):
 | |
|         if self._pwm:
 | |
|             try:
 | |
|                 self._pwm.ChangeDutyCycle(value * 100)
 | |
|             except ValueError:
 | |
|                 raise PinInvalidState('invalid state "%s" for pin %r' % (value, self))
 | |
|             self._duty_cycle = value
 | |
|         else:
 | |
|             try:
 | |
|                 GPIO.output(self._number, value)
 | |
|             except ValueError:
 | |
|                 raise PinInvalidState('invalid state "%s" for pin %r' % (value, self))
 | |
|             except RuntimeError:
 | |
|                 raise PinSetInput('cannot set state of pin %r' % self)
 | |
| 
 | |
|     def _get_pull(self):
 | |
|         return self._pull
 | |
| 
 | |
|     def _set_pull(self, value):
 | |
|         if self.function != 'input':
 | |
|             raise PinFixedPull('cannot set pull on non-input pin %r' % self)
 | |
|         if value != 'up' and self.PI_INFO.pulled_up('GPIO%d' % self._number):
 | |
|             raise PinFixedPull('%r has a physical pull-up resistor' % self)
 | |
|         try:
 | |
|             GPIO.setup(self._number, GPIO.IN, self.GPIO_PULL_UPS[value])
 | |
|             self._pull = value
 | |
|         except KeyError:
 | |
|             raise PinInvalidPull('invalid pull "%s" for pin %r' % (value, self))
 | |
| 
 | |
|     def _get_frequency(self):
 | |
|         return self._frequency
 | |
| 
 | |
|     def _set_frequency(self, value):
 | |
|         if self._frequency is None and value is not None:
 | |
|             try:
 | |
|                 self._pwm = GPIO.PWM(self._number, value)
 | |
|             except RuntimeError:
 | |
|                 raise PinPWMFixedValue('cannot start PWM on pin %r' % self)
 | |
|             self._pwm.start(0)
 | |
|             self._duty_cycle = 0
 | |
|             self._frequency = value
 | |
|         elif self._frequency is not None and value is not None:
 | |
|             self._pwm.ChangeFrequency(value)
 | |
|             self._frequency = value
 | |
|         elif self._frequency is not None and value is None:
 | |
|             self._pwm.stop()
 | |
|             self._pwm = None
 | |
|             self._duty_cycle = None
 | |
|             self._frequency = None
 | |
| 
 | |
|     def _get_bounce(self):
 | |
|         return None if self._bounce == -666 else (self._bounce / 1000)
 | |
| 
 | |
|     def _set_bounce(self, value):
 | |
|         if value is not None and value < 0:
 | |
|             raise PinInvalidBounce('bounce must be 0 or greater')
 | |
|         f = self.when_changed
 | |
|         self.when_changed = None
 | |
|         try:
 | |
|             self._bounce = -666 if value is None else int(value * 1000)
 | |
|         finally:
 | |
|             self.when_changed = f
 | |
| 
 | |
|     def _get_edges(self):
 | |
|         return self.GPIO_EDGES_NAMES[self._edges]
 | |
| 
 | |
|     def _set_edges(self, value):
 | |
|         f = self.when_changed
 | |
|         self.when_changed = None
 | |
|         try:
 | |
|             self._edges = self.GPIO_EDGES[value]
 | |
|         finally:
 | |
|             self.when_changed = f
 | |
| 
 | |
|     def _get_when_changed(self):
 | |
|         return self._when_changed
 | |
| 
 | |
|     def _set_when_changed(self, value):
 | |
|         if self._when_changed is None and value is not None:
 | |
|             self._when_changed = value
 | |
|             GPIO.add_event_detect(
 | |
|                 self._number, self._edges,
 | |
|                 callback=lambda channel: self._when_changed(),
 | |
|                 bouncetime=self._bounce)
 | |
|         elif self._when_changed is not None and value is None:
 | |
|             GPIO.remove_event_detect(self._number)
 | |
|             self._when_changed = None
 | |
|         else:
 | |
|             self._when_changed = value
 | |
| 
 |