forked from adafruit/Adafruit_CircuitPython_ESP32SPI
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdigitalio.py
executable file
·214 lines (168 loc) · 6.15 KB
/
digitalio.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# SPDX-FileCopyrightText: Copyright (c) 2019 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
`digitalio`
==============================
DigitalIO for ESP32 over SPI.
* Author(s): Brent Rubell, based on Adafruit_Blinka digitalio implementation
and bcm283x Pin implementation.
https://github.com/adafruit/Adafruit_Blinka/blob/master/src/adafruit_blinka/microcontroller/bcm283x/pin.py
https://github.com/adafruit/Adafruit_Blinka/blob/master/src/digitalio.py
"""
from micropython import const
class Pin:
"""
Implementation of CircuitPython API Pin Handling
for ESP32SPI.
:param int esp_pin: Valid ESP32 GPIO Pin, predefined in ESP32_GPIO_PINS.
:param ESP_SPIcontrol esp: The ESP object we are using.
NOTE: This class does not currently implement reading digital pins
or the use of internal pull-up resistors.
"""
# pylint: disable=invalid-name
IN = const(0x00)
OUT = const(0x01)
LOW = const(0x00)
HIGH = const(0x01)
_value = LOW
_mode = IN
pin_id = None
ESP32_GPIO_PINS = set(
[0, 1, 2, 4, 5, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 32, 33]
)
def __init__(self, esp_pin, esp):
if esp_pin in self.ESP32_GPIO_PINS:
self.pin_id = esp_pin
else:
raise AttributeError("Pin %d is not a valid ESP32 GPIO Pin." % esp_pin)
self._esp = esp
def init(self, mode=IN):
"""Initalizes a pre-defined pin.
:param mode: Pin mode (IN, OUT, LOW, HIGH). Defaults to IN.
"""
if mode is not None:
if mode == self.IN:
self._mode = self.IN
self._esp.set_pin_mode(self.pin_id, 0)
elif mode == self.OUT:
self._mode = self.OUT
self._esp.set_pin_mode(self.pin_id, 1)
else:
raise ValueError("Invalid mode defined")
def value(self, val=None):
"""Sets ESP32 Pin GPIO output mode.
:param val: Pin output level (LOW, HIGH)
"""
if val is not None:
if val == self.LOW:
self._value = val
self._esp.set_digital_write(self.pin_id, 0)
elif val == self.HIGH:
self._value = val
self._esp.set_digital_write(self.pin_id, 1)
else:
raise ValueError("Invalid value for pin")
else:
raise NotImplementedError(
"digitalRead not currently implemented in esp32spi"
)
def __repr__(self):
return str(self.pin_id)
# pylint: disable = too-few-public-methods
class DriveMode:
"""DriveMode Enum."""
PUSH_PULL = None
OPEN_DRAIN = None
DriveMode.PUSH_PULL = DriveMode()
DriveMode.OPEN_DRAIN = DriveMode()
class Direction:
"""DriveMode Enum."""
INPUT = None
OUTPUT = None
Direction.INPUT = Direction()
Direction.OUTPUT = Direction()
class DigitalInOut:
"""Implementation of DigitalIO module for ESP32SPI.
:param ESP_SPIcontrol esp: The ESP object we are using.
:param int pin: Valid ESP32 GPIO Pin, predefined in ESP32_GPIO_PINS.
"""
_pin = None
# pylint: disable = attribute-defined-outside-init
def __init__(self, esp, pin):
self._esp = esp
self._pin = Pin(pin, self._esp)
self.direction = Direction.INPUT
def __enter__(self):
return self
def __exit__(self, exception_type, exception_value, traceback):
self.deinit()
def deinit(self):
"""De-initializes the pin object."""
self._pin = None
def switch_to_output(self, value=False, drive_mode=DriveMode.PUSH_PULL):
"""Set the drive mode and value and then switch to writing out digital values.
:param bool value: Default mode to set upon switching.
:param DriveMode drive_mode: Drive mode for the output.
"""
self._direction = Direction.OUTPUT
self._drive_mode = drive_mode
self.value = value
def switch_to_input(self, pull=None):
"""Sets the pull and then switch to read in digital values.
:param Pull pull: Pull configuration for the input.
"""
raise NotImplementedError(
"Digital reads are not currently supported in ESP32SPI."
)
@property
def direction(self):
"""Returns the pin's direction."""
return self.__direction
@direction.setter
def direction(self, pin_dir):
"""Sets the direction of the pin.
:param Direction dir: Pin direction (Direction.OUTPUT or Direction.INPUT)
"""
self.__direction = pin_dir
if pin_dir is Direction.OUTPUT:
self._pin.init(mode=Pin.OUT)
self.value = False
self.drive_mode = DriveMode.PUSH_PULL
elif pin_dir is Direction.INPUT:
self._pin.init(mode=Pin.IN)
else:
raise AttributeError("Not a Direction")
@property
def value(self):
"""Returns the digital logic level value of the pin."""
return self._pin.value() == 1
@value.setter
def value(self, val):
"""Sets the digital logic level of the pin.
:param type value: Pin logic level.
:param int value: Pin logic level. 1 is logic high, 0 is logic low.
:param bool value: Pin logic level. True is logic high, False is logic low.
"""
if self.direction is Direction.OUTPUT:
self._pin.value(1 if val else 0)
else:
raise AttributeError("Not an output")
@property
def drive_mode(self):
"""Returns pin drive mode."""
if self.direction is Direction.OUTPUT:
return self._drive_mode
raise AttributeError("Not an output")
@drive_mode.setter
def drive_mode(self, mode):
"""Sets the pin drive mode.
:param DriveMode mode: Defines the drive mode when outputting digital values.
Either PUSH_PULL or OPEN_DRAIN
"""
if mode is DriveMode.OPEN_DRAIN:
raise NotImplementedError(
"Drive mode %s not implemented in ESP32SPI." % mode
)
if mode is DriveMode.PUSH_PULL:
self._pin.init(mode=Pin.OUT)