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

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 

9 

10from __future__ import ( 

11 unicode_literals, 

12 absolute_import, 

13 print_function, 

14 division, 

15 ) 

16str = type('') 

17 

18import warnings 

19 

20from RPi import GPIO 

21 

22from .local import LocalPiFactory, LocalPiPin 

23from ..exc import ( 

24 PinInvalidFunction, 

25 PinSetInput, 

26 PinFixedPull, 

27 PinInvalidPull, 

28 PinInvalidState, 

29 PinInvalidBounce, 

30 PinPWMFixedValue, 

31 ) 

32 

33 

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). 

40 

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.:: 

43 

44 from gpiozero import LED 

45 

46 led = LED(12) 

47 

48 However, you can also construct RPi.GPIO pins manually if you wish:: 

49 

50 from gpiozero.pins.rpigpio import RPiGPIOFactory 

51 from gpiozero import LED 

52 

53 factory = RPiGPIOFactory() 

54 led = LED(12, pin_factory=factory) 

55 

56 .. _RPi.GPIO: https://pypi.python.org/pypi/RPi.GPIO 

57 """ 

58 

59 def __init__(self): 

60 super(RPiGPIOFactory, self).__init__() 

61 GPIO.setmode(GPIO.BCM) 

62 GPIO.setwarnings(False) 

63 self.pin_class = RPiGPIOPin 

64 

65 def close(self): 

66 super(RPiGPIOFactory, self).close() 

67 GPIO.cleanup() 

68 

69 

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. 

74 

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 } 

86 

87 GPIO_PULL_UPS = { 

88 'up': GPIO.PUD_UP, 

89 'down': GPIO.PUD_DOWN, 

90 'floating': GPIO.PUD_OFF, 

91 } 

92 

93 GPIO_EDGES = { 

94 'both': GPIO.BOTH, 

95 'rising': GPIO.RISING, 

96 'falling': GPIO.FALLING, 

97 } 

98 

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()} 

102 

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]) 

112 

113 def close(self): 

114 self.frequency = None 

115 self.when_changed = None 

116 GPIO.cleanup(self.number) 

117 

118 def output_with_state(self, state): 

119 self._pull = 'floating' 

120 GPIO.setup(self.number, GPIO.OUT, initial=state) 

121 

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)) 

130 

131 def _get_function(self): 

132 return self.GPIO_FUNCTION_NAMES[GPIO.gpio_function(self.number)] 

133 

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)) 

141 

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) 

147 

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) 

162 

163 def _get_pull(self): 

164 return self._pull 

165 

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)) 

176 

177 def _get_frequency(self): 

178 return self._frequency 

179 

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 

197 

198 def _get_bounce(self): 

199 return None if self._bounce == -666 else (self._bounce / 1000) 

200 

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 

210 

211 def _get_edges(self): 

212 return self.GPIO_EDGES_NAMES[self._edges] 

213 

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 

221 

222 def _call_when_changed(self, channel): 

223 super(RPiGPIOPin, self)._call_when_changed() 

224 

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) 

230 

231 def _disable_event_detect(self): 

232 GPIO.remove_event_detect(self.number)