]> Repositories - Adafruit_Blinka-hackapet.git/blob - src/adafruit_blinka/microcontroller/generic_linux/libgpiod_pin.py
Separate SPDX to separate files for markdown
[Adafruit_Blinka-hackapet.git] / src / adafruit_blinka / microcontroller / generic_linux / libgpiod_pin.py
1 # SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
2 #
3 # SPDX-License-Identifier: MIT
4 """A Pin class for use with libgpiod."""
5 try:
6     import gpiod
7 except ImportError:
8     raise ImportError(
9         "libgpiod Python bindings not found, please install and try again! See "
10         "https://github.com/adafruit/Raspberry-Pi-Installer-Scripts/blob/master/libgpiod.sh"
11     ) from ImportError
12
13
14 # pylint: disable=too-many-branches,too-many-statements
15 class Pin:
16     """Pins dont exist in CPython so...lets make our own!"""
17
18     IN = 0
19     OUT = 1
20     LOW = 0
21     HIGH = 1
22     PULL_NONE = 0
23     PULL_UP = 1
24     PULL_DOWN = 2
25     _CONSUMER = "adafruit_blinka"
26
27     id = None
28     _value = LOW
29     _mode = IN
30
31     def __init__(self, pin_id):
32         self.id = pin_id
33         if isinstance(pin_id, tuple):
34             self._num = int(pin_id[1])
35             if hasattr(gpiod, "Chip"):
36                 self._chip = gpiod.Chip(str(pin_id[0]), gpiod.Chip.OPEN_BY_NUMBER)
37             else:
38                 self._chip = gpiod.chip(str(pin_id[0]), gpiod.chip.OPEN_BY_NUMBER)
39         else:
40             self._num = int(pin_id)
41             if hasattr(gpiod, "Chip"):
42                 self._chip = gpiod.Chip("gpiochip0", gpiod.Chip.OPEN_BY_NAME)
43             else:
44                 self._chip = gpiod.chip("gpiochip0", gpiod.chip.OPEN_BY_NAME)
45         self._line = None
46
47     def __repr__(self):
48         return str(self.id)
49
50     def __eq__(self, other):
51         return self.id == other
52
53     def init(self, mode=IN, pull=None):
54         """Initialize the Pin"""
55         if not self._line:
56             self._line = self._chip.get_line(int(self._num))
57             # print("init line: ", self.id, self._line)
58
59         if mode is not None:
60             if mode == self.IN:
61                 flags = 0
62                 self._line.release()
63                 if pull is not None:
64                     if pull == self.PULL_UP:
65                         if hasattr(gpiod, "line") and hasattr(
66                             gpiod.line, "BIAS_PULL_UP"
67                         ):
68                             config = gpiod.line_request()
69                             config.consumer = self._CONSUMER
70                             config.request_type = gpiod.line.BIAS_PULL_UP
71                             self._line.request(config)
72                         else:
73                             self._line.request(
74                                 consumer=self._CONSUMER,
75                                 type=gpiod.LINE_REQ_DIR_IN,
76                                 flags=flags,
77                             )
78                             raise NotImplementedError(
79                                 "Internal pullups not supported in this version of libgpiod, "
80                                 "use physical resistor instead!"
81                             )
82                     elif pull == self.PULL_DOWN:
83                         if hasattr(gpiod, "line") and hasattr(
84                             gpiod.line, "BIAS_PULL_DOWN"
85                         ):
86                             config = gpiod.line_request()
87                             config.consumer = self._CONSUMER
88                             config.request_type = gpiod.line.BIAS_PULL_DOWN
89                             self._line.request(config)
90                         else:
91                             raise NotImplementedError(
92                                 "Internal pulldowns not supported in this version of libgpiod, "
93                                 "use physical resistor instead!"
94                             )
95                     elif pull == self.PULL_NONE:
96                         if hasattr(gpiod, "line") and hasattr(
97                             gpiod.line, "BIAS_DISABLE"
98                         ):
99                             config = gpiod.line_request()
100                             config.consumer = self._CONSUMER
101                             config.request_type = gpiod.line.BIAS_DISABLE
102                             self._line.request(config)
103                     else:
104                         raise RuntimeError(f"Invalid pull for pin: {self.id}")
105
106                 self._mode = self.IN
107                 self._line.release()
108                 if hasattr(gpiod, "LINE_REQ_DIR_IN"):
109                     self._line.request(
110                         consumer=self._CONSUMER, type=gpiod.LINE_REQ_DIR_IN, flags=flags
111                     )
112                 else:
113                     config = gpiod.line_request()
114                     config.consumer = self._CONSUMER
115                     config.request_type = gpiod.line_request.DIRECTION_INPUT
116                     self._line.request(config)
117
118             elif mode == self.OUT:
119                 if pull is not None:
120                     raise RuntimeError("Cannot set pull resistor on output")
121                 self._mode = self.OUT
122                 self._line.release()
123                 if hasattr(gpiod, "LINE_REQ_DIR_OUT"):
124                     self._line.request(
125                         consumer=self._CONSUMER, type=gpiod.LINE_REQ_DIR_OUT
126                     )
127                 else:
128                     config = gpiod.line_request()
129                     config.consumer = self._CONSUMER
130                     config.request_type = gpiod.line_request.DIRECTION_OUTPUT
131                     self._line.request(config)
132             else:
133                 raise RuntimeError("Invalid mode for pin: %s" % self.id)
134
135     def value(self, val=None):
136         """Set or return the Pin Value"""
137         if val is None:
138             return self._line.get_value()
139
140         if val in (self.LOW, self.HIGH):
141             self._value = val
142             self._line.set_value(val)
143             return None
144         raise RuntimeError("Invalid value for pin")