]> Repositories - Adafruit_Blinka-hackapet.git/blob - src/adafruit_blinka/microcontroller/generic_linux/libgpiod_pin.py
09f527e8511c4878da27708e8f27aee7f4ed46e3
[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 class Pin:
14     """Pins dont exist in CPython so...lets make our own!"""
15
16     IN = 0
17     OUT = 1
18     LOW = 0
19     HIGH = 1
20     PULL_NONE = 0
21     PULL_UP = 1
22     PULL_DOWN = 2
23     _CONSUMER = "adafruit_blinka"
24
25     id = None
26     _value = LOW
27     _mode = IN
28
29     def __init__(self, pin_id):
30         self.id = pin_id
31         if isinstance(pin_id, tuple):
32             self._num = int(pin_id[1])
33             if hasattr(gpiod, 'Chip'):
34                 self._chip = gpiod.Chip(str(pin_id[0]), gpiod.Chip.OPEN_BY_NUMBER)
35             else:
36                 self._chip = gpiod.chip(str(pin_id[0]), gpiod.chip.OPEN_BY_NUMBER)
37         else:
38             self._num = int(pin_id)
39             if hasattr(gpiod, 'Chip'):
40                 self._chip = gpiod.Chip("gpiochip0", gpiod.Chip.OPEN_BY_NAME)
41             else:
42                 self._chip = gpiod.chip("gpiochip0", gpiod.chip.OPEN_BY_NAME)
43         self._line = None
44
45     def __repr__(self):
46         return str(self.id)
47
48     def __eq__(self, other):
49         return self.id == other
50
51     def init(self, mode=IN, pull=None):
52         """Initialize the Pin"""
53         if not self._line:
54             self._line = self._chip.get_line(int(self._num))
55             # print("init line: ", self.id, self._line)
56
57         if mode is not None:
58             if mode == self.IN:
59                 flags = 0
60                 self._line.release()
61                 if pull is not None:
62                     if pull == self.PULL_UP:
63                         if hasattr(gpiod, 'line') and hasattr(gpiod.line, 'BIAS_PULL_UP') :
64                             config = gpiod.line_request()
65                             config.consumer = self._CONSUMER
66                             config.request_type = gpiod.line.BIAS_PULL_UP
67                             self._line.request(config)
68                         else:
69                             self._line.request(
70                                 consumer=self._CONSUMER, type=gpiod.LINE_REQ_DIR_IN, flags=flags
71                             )
72                             raise NotImplementedError(
73                                 "Internal pullups not supported in this version of libgpiod, "
74                                 "use physical resistor instead!"
75                             )
76                     elif pull == self.PULL_DOWN:
77                         if hasattr(gpiod, 'line') and hasattr(gpiod.line, 'BIAS_PULL_DOWN') :
78                             config = gpiod.line_request()
79                             config.consumer = self._CONSUMER
80                             config.request_type = gpiod.line.BIAS_PULL_DOWN
81                             self._line.request(config)                     
82                         else:
83                             raise NotImplementedError(
84                                 "Internal pulldowns not supported in this version of libgpiod, "
85                                 "use physical resistor instead!"
86                             )
87                     elif pull == self.PULL_NONE:
88                         if hasattr(gpiod, 'line') and hasattr(gpiod.line, 'BIAS_DISABLE') :
89                             config = gpiod.line_request()
90                             config.consumer = self._CONSUMER
91                             config.request_type = gpiod.line.BIAS_DISABLE
92                             self._line.request(config)
93                     else:
94                         raise RuntimeError(f"Invalid pull for pin: {self.id}")
95
96                 self._mode = self.IN
97                 self._line.release()
98                 if hasattr(gpiod, 'LINE_REQ_DIR_IN'):
99                     self._line.request(
100                         consumer=self._CONSUMER, type=gpiod.LINE_REQ_DIR_IN, flags=flags
101                     )
102                 else:
103                     config = gpiod.line_request()
104                     config.consumer = self._CONSUMER
105                     config.request_type = gpiod.line_request.DIRECTION_INPUT
106                     self._line.request(config)
107
108             elif mode == self.OUT:
109                 if pull is not None:
110                     raise RuntimeError("Cannot set pull resistor on output")
111                 self._mode = self.OUT
112                 self._line.release()
113                 if hasattr(gpiod, 'LINE_REQ_DIR_OUT'):
114                     self._line.request(consumer=self._CONSUMER, type=gpiod.LINE_REQ_DIR_OUT)
115                 else:
116                     config = gpiod.line_request()
117                     config.consumer = self._CONSUMER
118                     config.request_type = gpiod.line_request.DIRECTION_OUTPUT
119                     self._line.request(config)
120             else:
121                 raise RuntimeError("Invalid mode for pin: %s" % self.id)
122
123     def value(self, val=None):
124         """Set or return the Pin Value"""
125         if val is None:
126             return self._line.get_value()
127
128         if val in (self.LOW, self.HIGH):
129             self._value = val
130             self._line.set_value(val)
131             return None
132         raise RuntimeError("Invalid value for pin")