2
2
#
3
3
# SPDX-License-Identifier: MIT
4
4
"""Broadcom BCM283x pin names"""
5
- from RPi import GPIO
5
+ from pathlib import Path
6
+ import lgpio
6
7
7
- GPIO .setmode (GPIO .BCM ) # Use BCM pins D4 = GPIO #4
8
- GPIO .setwarnings (False ) # shh!
8
+
9
+ def _get_gpiochip ():
10
+ """
11
+ Determines the handle of the GPIO chip device to access.
12
+
13
+ iterate through sysfs to find a GPIO chip device with a driver known to be
14
+ used for userspace GPIO access.
15
+ """
16
+ for dev in Path ("/sys/bus/gpio/devices" ).glob ("gpiochip*" ):
17
+ drivers = set ((dev / "of_node/compatible" ).read_text ().split ("\0 " ))
18
+ # check if driver names are intended for userspace control
19
+ if drivers & {
20
+ "raspberrypi,rp1-gpio" ,
21
+ "raspberrypi,bcm2835-gpio" ,
22
+ "raspberrypi,bcm2711-gpio" ,
23
+ }:
24
+ return lgpio .gpiochip_open (int (dev .name [- 1 ]))
25
+ # return chip0 as a fallback
26
+ return lgpio .gpiochip_open (0 )
27
+
28
+
29
+ CHIP = _get_gpiochip ()
9
30
10
31
11
32
class Pin :
12
33
"""Pins dont exist in CPython so...lets make our own!"""
13
34
14
- IN = 0
15
- OUT = 1
16
35
LOW = 0
17
36
HIGH = 1
18
- PULL_NONE = 0
19
- PULL_UP = 1
20
- PULL_DOWN = 2
37
+ OFF = LOW
38
+ ON = HIGH
39
+
40
+ # values of lg mode constants
41
+ PULL_NONE = 0x80
42
+ PULL_UP = 0x20
43
+ PULL_DOWN = 0x40
44
+ ACTIVE_LOW = 0x02
45
+
46
+ # drive mode lg constants
47
+ OPEN_DRAIN = 0x04
48
+ IN = 0x0100
49
+ OUT = 0x0200
50
+
51
+ # LG mode constants
52
+ _LG_ALERT = 0x400
53
+ _LG_GROUP = 0x800
54
+ _LG_MODES = IN | OUT | _LG_ALERT | _LG_GROUP
55
+ _LG_PULLS = PULL_NONE | PULL_UP | PULL_NONE | ACTIVE_LOW
56
+ _LG_DRIVES = OPEN_DRAIN
21
57
22
58
id = None
23
59
_value = LOW
24
60
_mode = IN
25
61
62
+ # we want exceptions
63
+ lgpio .exceptions = True
64
+
26
65
def __init__ (self , bcm_number ):
27
- self .id = bcm_number
66
+ self .id = bcm_number # pylint: disable=invalid-name
28
67
29
68
def __repr__ (self ):
30
69
return str (self .id )
@@ -35,40 +74,60 @@ def __eq__(self, other):
35
74
def init (self , mode = IN , pull = None ):
36
75
"""Initialize the Pin"""
37
76
if mode is not None :
38
- if mode == self .IN :
39
- self ._mode = self .IN
40
- GPIO . setup ( self .id , GPIO . IN )
77
+ if mode == Pin .IN :
78
+ self ._mode = Pin .IN
79
+ self ._set_gpio_mode_in ( )
41
80
elif mode == self .OUT :
42
- self ._mode = self .OUT
43
- GPIO . setup ( self .id , GPIO . OUT )
81
+ self ._mode = Pin .OUT
82
+ Pin . _check_result ( lgpio . gpio_claim_output ( CHIP , self .id , Pin . LOW ) )
44
83
else :
45
- raise RuntimeError ("Invalid mode for pin: %s" % self .id )
84
+ raise RuntimeError (f "Invalid mode for pin: { self .id } " )
46
85
if pull is not None :
47
- if self ._mode != self .IN :
48
- raise RuntimeError ("Cannot set pull resistor on output" )
49
- if pull == self .PULL_UP :
50
- GPIO .setup (self .id , GPIO .IN , pull_up_down = GPIO .PUD_UP )
51
- elif pull == self .PULL_DOWN :
52
- GPIO .setup (self .id , GPIO .IN , pull_up_down = GPIO .PUD_DOWN )
86
+ if self ._mode != Pin .IN :
87
+ raise RuntimeError ("Can only set pull resistor on input" )
88
+ if pull in {Pin .PULL_UP , Pin .PULL_DOWN , Pin .PULL_NONE }:
89
+ self ._set_gpio_mode_in (lflags = pull )
53
90
else :
54
- raise RuntimeError ("Invalid pull for pin: %s" % self .id )
91
+ raise RuntimeError (f "Invalid pull for pin: { self .id } " )
55
92
56
93
def value (self , val = None ):
57
94
"""Set or return the Pin Value"""
58
95
if val is not None :
59
- if val == self .LOW :
96
+ if val == Pin .LOW :
60
97
self ._value = val
61
- GPIO . output ( self .id , val )
62
- elif val == self .HIGH :
98
+ Pin . _check_result ( lgpio . gpio_write ( CHIP , self .id , val ) )
99
+ elif val == Pin .HIGH :
63
100
self ._value = val
64
- GPIO . output ( self .id , val )
101
+ Pin . _check_result ( lgpio . gpio_write ( CHIP , self .id , val ) )
65
102
else :
66
103
raise RuntimeError ("Invalid value for pin" )
67
104
return None
68
- return GPIO .input (self .id )
105
+ return Pin ._check_result (lgpio .gpio_read (CHIP , self .id ))
106
+
107
+ @staticmethod
108
+ def _check_result (result ):
109
+ """
110
+ convert any result other than zero to a text message and pass it back
111
+ as a runtime exception. Typical usage: use the lgpio call as the
112
+ argument.
113
+ """
114
+ if result < 0 :
115
+ raise RuntimeError (lgpio .error_text (result ))
116
+ return result
117
+
118
+ def _set_gpio_mode_in (self , lflags = 0 ):
119
+ """
120
+ claim a gpio as input, or modify the flags (PULL_UP, PULL_DOWN, ... )
121
+ """
122
+ # This gpio_free may seem redundant, but is required when
123
+ # changing the line-flags of an already acquired input line
124
+ try :
125
+ lgpio .gpio_free (CHIP , self .id )
126
+ except lgpio .error :
127
+ pass
128
+ Pin ._check_result (lgpio .gpio_claim_input (CHIP , self .id , lFlags = lflags ))
69
129
70
130
71
- # Pi 1B rev1 only?
72
131
D0 = Pin (0 )
73
132
D1 = Pin (1 )
74
133
0 commit comments