Coverage for /usr/lib/python3/dist-packages/gpiozero/pins/rpigpio.py: 60%
126 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-02-10 12:38 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2024-02-10 12:38 +0000
1# vim: set fileencoding=utf-8:
2#
3# GPIO Zero: a library for controlling the Raspberry Pi's GPIO pins
4#
5# Copyright (c) 2015-2021 Dave Jones <dave@waveform.org.uk>
6# Copyright (c) 2016 Andrew Scheller <github@loowis.durge.org>
7#
8# SPDX-License-Identifier: BSD-3-Clause
10from __future__ import (
11 unicode_literals,
12 absolute_import,
13 print_function,
14 division,
15 )
16str = type('')
18import warnings
20from RPi import GPIO
22from .local import LocalPiFactory, LocalPiPin
23from ..exc import (
24 PinInvalidFunction,
25 PinSetInput,
26 PinFixedPull,
27 PinInvalidPull,
28 PinInvalidState,
29 PinInvalidBounce,
30 PinPWMFixedValue,
31 )
34class RPiGPIOFactory(LocalPiFactory):
35 """
36 Extends :class:`~gpiozero.pins.local.LocalPiFactory`. Uses the `RPi.GPIO`_
37 library to interface to the Pi's GPIO pins. This is the default pin
38 implementation if the RPi.GPIO library is installed. Supports all features
39 including PWM (via software).
41 Because this is the default pin implementation you can use it simply by
42 specifying an integer number for the pin in most operations, e.g.::
44 from gpiozero import LED
46 led = LED(12)
48 However, you can also construct RPi.GPIO pins manually if you wish::
50 from gpiozero.pins.rpigpio import RPiGPIOFactory
51 from gpiozero import LED
53 factory = RPiGPIOFactory()
54 led = LED(12, pin_factory=factory)
56 .. _RPi.GPIO: https://pypi.python.org/pypi/RPi.GPIO
57 """
59 def __init__(self):
60 super(RPiGPIOFactory, self).__init__()
61 GPIO.setmode(GPIO.BCM)
62 GPIO.setwarnings(False)
63 self.pin_class = RPiGPIOPin
65 def close(self):
66 super(RPiGPIOFactory, self).close()
67 GPIO.cleanup()
70class RPiGPIOPin(LocalPiPin):
71 """
72 Extends :class:`~gpiozero.pins.local.LocalPiPin`. Pin implementation for
73 the `RPi.GPIO`_ library. See :class:`RPiGPIOFactory` for more information.
75 .. _RPi.GPIO: https://pypi.python.org/pypi/RPi.GPIO
76 """
77 GPIO_FUNCTIONS = {
78 'input': GPIO.IN,
79 'output': GPIO.OUT,
80 'i2c': GPIO.I2C,
81 'spi': GPIO.SPI,
82 'pwm': GPIO.HARD_PWM,
83 'serial': GPIO.SERIAL,
84 'unknown': GPIO.UNKNOWN,
85 }
87 GPIO_PULL_UPS = {
88 'up': GPIO.PUD_UP,
89 'down': GPIO.PUD_DOWN,
90 'floating': GPIO.PUD_OFF,
91 }
93 GPIO_EDGES = {
94 'both': GPIO.BOTH,
95 'rising': GPIO.RISING,
96 'falling': GPIO.FALLING,
97 }
99 GPIO_FUNCTION_NAMES = {v: k for (k, v) in GPIO_FUNCTIONS.items()}
100 GPIO_PULL_UP_NAMES = {v: k for (k, v) in GPIO_PULL_UPS.items()}
101 GPIO_EDGES_NAMES = {v: k for (k, v) in GPIO_EDGES.items()}
103 def __init__(self, factory, number):
104 super(RPiGPIOPin, self).__init__(factory, number)
105 self._pull = 'up' if self.factory.pi_info.pulled_up(repr(self)) else 'floating'
106 self._pwm = None
107 self._frequency = None
108 self._duty_cycle = None
109 self._bounce = -666
110 self._edges = GPIO.BOTH
111 GPIO.setup(self.number, GPIO.IN, self.GPIO_PULL_UPS[self._pull])
113 def close(self):
114 self.frequency = None
115 self.when_changed = None
116 GPIO.cleanup(self.number)
118 def output_with_state(self, state):
119 self._pull = 'floating'
120 GPIO.setup(self.number, GPIO.OUT, initial=state)
122 def input_with_pull(self, pull):
123 if pull != 'up' and self.factory.pi_info.pulled_up(repr(self)):
124 raise PinFixedPull('%r has a physical pull-up resistor' % self)
125 try:
126 GPIO.setup(self.number, GPIO.IN, self.GPIO_PULL_UPS[pull])
127 self._pull = pull
128 except KeyError:
129 raise PinInvalidPull('invalid pull "%s" for pin %r' % (pull, self))
131 def _get_function(self):
132 return self.GPIO_FUNCTION_NAMES[GPIO.gpio_function(self.number)]
134 def _set_function(self, value):
135 if value != 'input': 135 ↛ 136line 135 didn't jump to line 136, because the condition on line 135 was never true
136 self._pull = 'floating'
137 if value in ('input', 'output') and value in self.GPIO_FUNCTIONS: 137 ↛ 140line 137 didn't jump to line 140, because the condition on line 137 was never false
138 GPIO.setup(self.number, self.GPIO_FUNCTIONS[value], self.GPIO_PULL_UPS[self._pull])
139 else:
140 raise PinInvalidFunction('invalid function "%s" for pin %r' % (value, self))
142 def _get_state(self):
143 if self._pwm: 143 ↛ 144line 143 didn't jump to line 144, because the condition on line 143 was never true
144 return self._duty_cycle
145 else:
146 return GPIO.input(self.number)
148 def _set_state(self, value):
149 if self._pwm:
150 try:
151 self._pwm.ChangeDutyCycle(value * 100)
152 except ValueError:
153 raise PinInvalidState('invalid state "%s" for pin %r' % (value, self))
154 self._duty_cycle = value
155 else:
156 try:
157 GPIO.output(self.number, value)
158 except ValueError:
159 raise PinInvalidState('invalid state "%s" for pin %r' % (value, self))
160 except RuntimeError:
161 raise PinSetInput('cannot set state of pin %r' % self)
163 def _get_pull(self):
164 return self._pull
166 def _set_pull(self, value):
167 if self.function != 'input': 167 ↛ 168line 167 didn't jump to line 168, because the condition on line 167 was never true
168 raise PinFixedPull('cannot set pull on non-input pin %r' % self)
169 if value != 'up' and self.factory.pi_info.pulled_up(repr(self)): 169 ↛ 170line 169 didn't jump to line 170, because the condition on line 169 was never true
170 raise PinFixedPull('%r has a physical pull-up resistor' % self)
171 try:
172 GPIO.setup(self.number, GPIO.IN, self.GPIO_PULL_UPS[value])
173 self._pull = value
174 except KeyError:
175 raise PinInvalidPull('invalid pull "%s" for pin %r' % (value, self))
177 def _get_frequency(self):
178 return self._frequency
180 def _set_frequency(self, value):
181 if self._frequency is None and value is not None: 181 ↛ 182line 181 didn't jump to line 182, because the condition on line 181 was never true
182 try:
183 self._pwm = GPIO.PWM(self.number, value)
184 except RuntimeError:
185 raise PinPWMFixedValue('cannot start PWM on pin %r' % self)
186 self._pwm.start(0)
187 self._duty_cycle = 0
188 self._frequency = value
189 elif self._frequency is not None and value is not None: 189 ↛ 190line 189 didn't jump to line 190, because the condition on line 189 was never true
190 self._pwm.ChangeFrequency(value)
191 self._frequency = value
192 elif self._frequency is not None and value is None: 192 ↛ 193line 192 didn't jump to line 193, because the condition on line 192 was never true
193 self._pwm.stop()
194 self._pwm = None
195 self._duty_cycle = None
196 self._frequency = None
198 def _get_bounce(self):
199 return None if self._bounce == -666 else (self._bounce / 1000)
201 def _set_bounce(self, value):
202 if value is not None and value < 0: 202 ↛ 203line 202 didn't jump to line 203, because the condition on line 202 was never true
203 raise PinInvalidBounce('bounce must be 0 or greater')
204 f = self.when_changed
205 self.when_changed = None
206 try:
207 self._bounce = -666 if value is None else int(value * 1000)
208 finally:
209 self.when_changed = f
211 def _get_edges(self):
212 return self.GPIO_EDGES_NAMES[self._edges]
214 def _set_edges(self, value):
215 f = self.when_changed
216 self.when_changed = None
217 try:
218 self._edges = self.GPIO_EDGES[value]
219 finally:
220 self.when_changed = f
222 def _call_when_changed(self, channel):
223 super(RPiGPIOPin, self)._call_when_changed()
225 def _enable_event_detect(self):
226 GPIO.add_event_detect(
227 self.number, self._edges,
228 callback=self._call_when_changed,
229 bouncetime=self._bounce)
231 def _disable_event_detect(self):
232 GPIO.remove_event_detect(self.number)