]> Repositories - Adafruit_Blinka-hackapet.git/blob - src/adafruit_blinka/microcontroller/generic_linux/libgpiod_pin.py
Merge pull request #750 from how2flow/odroid
[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_REQ_FLAG_BIAS_PULL_UP"):
66                             flags |= gpiod.LINE_REQ_FLAG_BIAS_PULL_UP
67                         else:
68                             raise NotImplementedError(
69                                 "Internal pullups not supported in this version of libgpiod, "
70                                 "use physical resistor instead!"
71                             )
72                     elif pull == self.PULL_DOWN:
73                         if hasattr(gpiod, "line") and hasattr(
74                             gpiod, "LINE_REQ_FLAG_BIAS_PULL_DOWN"
75                         ):
76                             flags |= gpiod.LINE_REQ_FLAG_BIAS_PULL_DOWN
77                         else:
78                             raise NotImplementedError(
79                                 "Internal pulldowns not supported in this version of libgpiod, "
80                                 "use physical resistor instead!"
81                             )
82                     elif pull == self.PULL_NONE:
83                         if hasattr(gpiod, "line") and hasattr(
84                             gpiod, "LINE_REQ_FLAG_BIAS_DISABLE"
85                         ):
86                             flags |= gpiod.LINE_REQ_FLAG_BIAS_DISABLE
87                         else:
88                             raise NotImplementedError(
89                                 "Internal pulldowns not supported in this version of libgpiod, "
90                                 "use physical resistor instead!"
91                             )
92                     else:
93                         raise RuntimeError(f"Invalid pull for pin: {self.id}")
94
95                 self._mode = self.IN
96                 self._line.release()
97                 if hasattr(gpiod, "LINE_REQ_DIR_IN"):
98                     self._line.request(
99                         consumer=self._CONSUMER, type=gpiod.LINE_REQ_DIR_IN, flags=flags
100                     )
101                 else:
102                     config = gpiod.line_request()
103                     config.consumer = self._CONSUMER
104                     config.request_type = gpiod.line_request.DIRECTION_INPUT
105                     self._line.request(config)
106
107             elif mode == self.OUT:
108                 if pull is not None:
109                     raise RuntimeError("Cannot set pull resistor on output")
110                 self._mode = self.OUT
111                 self._line.release()
112                 if hasattr(gpiod, "LINE_REQ_DIR_OUT"):
113                     self._line.request(
114                         consumer=self._CONSUMER, type=gpiod.LINE_REQ_DIR_OUT
115                     )
116                 else:
117                     config = gpiod.line_request()
118                     config.consumer = self._CONSUMER
119                     config.request_type = gpiod.line_request.DIRECTION_OUTPUT
120                     self._line.request(config)
121             else:
122                 raise RuntimeError("Invalid mode for pin: %s" % self.id)
123
124     def value(self, val=None):
125         """Set or return the Pin Value"""
126         if val is None:
127             return self._line.get_value()
128
129         if val in (self.LOW, self.HIGH):
130             self._value = val
131             self._line.set_value(val)
132             return None
133         raise RuntimeError("Invalid value for pin")