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