Skip to content

Commit 91a5b7b

Browse files
authored
Merge pull request #34 from JulianOrteil/fix-32
Fix #32
2 parents 011a184 + 915572c commit 91a5b7b

File tree

1 file changed

+104
-36
lines changed

1 file changed

+104
-36
lines changed

adafruit_mpr121.py

Lines changed: 104 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@
3232

3333
import time
3434

35+
try:
36+
from typing import List, Optional, Tuple
37+
import busio
38+
except ImportError:
39+
# typing hint modules not needed or not available in CircuitPython
40+
pass
41+
42+
3543
from adafruit_bus_device import i2c_device
3644
from micropython import const
3745

@@ -79,71 +87,96 @@
7987

8088
class MPR121_Channel:
8189
# pylint: disable=protected-access
82-
"""Helper class to represent a touch channel on the MPR121. Not meant to
83-
be used directly."""
90+
"""Represents a single channel on the touch sensor.
91+
92+
Not meant to be used directly.
93+
"""
94+
95+
_mpr121: "MPR121"
96+
_channel: int
8497

85-
def __init__(self, mpr121, channel):
98+
def __init__(self, mpr121: "MPR121", channel: int) -> None:
99+
"""Creates a new ``MPR121_Channel`` instance.
100+
101+
:param mpr121: An instance of the touch sensor driver.
102+
:param channel: The channel this instance represents (0-11).
103+
"""
86104
self._mpr121 = mpr121
87105
self._channel = channel
88106

89107
@property
90-
def value(self):
91-
"""Whether the touch pad is being touched or not."""
108+
def value(self) -> bool:
109+
"""Get whether the touch pad is being touched or not."""
92110
return self._mpr121.touched() & (1 << self._channel) != 0
93111

94112
@property
95-
def raw_value(self):
96-
"""The raw touch measurement."""
113+
def raw_value(self) -> int:
114+
"""Get the raw touch measurement."""
97115
return self._mpr121.filtered_data(self._channel)
98116

99117
@property
100-
def threshold(self):
101-
"""The touch threshold."""
118+
def threshold(self) -> int:
119+
"""Get or set the touch threshold."""
102120
buf = bytearray(1)
103121
self._mpr121._read_register_bytes(MPR121_TOUCHTH_0 + 2 * self._channel, buf, 1)
104122
return buf[0]
105123

106124
@threshold.setter
107-
def threshold(self, value):
108-
self._mpr121._write_register_byte(MPR121_TOUCHTH_0 + 2 * self._channel, value)
125+
def threshold(self, new_thresh: int) -> None:
126+
self._mpr121._write_register_byte(
127+
MPR121_TOUCHTH_0 + 2 * self._channel, new_thresh
128+
)
109129

110130
@property
111-
def release_threshold(self):
112-
"""The release threshold."""
131+
def release_threshold(self) -> int:
132+
"""Get or set the release threshold."""
113133
buf = bytearray(1)
114134
self._mpr121._read_register_bytes(
115135
MPR121_RELEASETH_0 + 2 * self._channel, buf, 1
116136
)
117137
return buf[0]
118138

119139
@release_threshold.setter
120-
def release_threshold(self, value):
121-
self._mpr121._write_register_byte(MPR121_RELEASETH_0 + 2 * self._channel, value)
140+
def release_threshold(self, new_thresh: int) -> None:
141+
self._mpr121._write_register_byte(
142+
MPR121_RELEASETH_0 + 2 * self._channel, new_thresh
143+
)
122144

123145

124146
class MPR121:
125147
"""Driver for the MPR121 capacitive touch breakout board."""
126148

127-
def __init__(self, i2c, address=MPR121_I2CADDR_DEFAULT):
149+
_i2c: i2c_device.I2CDevice
150+
_buffer: bytearray
151+
_channels: List[Optional[MPR121_Channel]]
152+
153+
def __init__(self, i2c: busio.I2C, address: int = MPR121_I2CADDR_DEFAULT) -> None:
154+
"""Creates a new ``MPR121`` instance.
155+
156+
:param i2c: An I2C driver.
157+
:type i2c: class:`busio.I2C`
158+
:param address: The address of the touch sensor (0x5A - 0x5D).
159+
:type address: int
160+
"""
128161
self._i2c = i2c_device.I2CDevice(i2c, address)
129162
self._buffer = bytearray(2)
130163
self._channels = [None] * 12
131164
self.reset()
132165

133-
def __getitem__(self, key):
166+
def __getitem__(self, key: int) -> MPR121_Channel:
134167
if key < 0 or key > 11:
135-
raise IndexError("Pin must be a value 0-11.")
168+
raise IndexError("pin must be a value 0-11")
136169
if self._channels[key] is None:
137170
self._channels[key] = MPR121_Channel(self, key)
138171
return self._channels[key]
139172

140173
@property
141-
def touched_pins(self):
142-
"""A tuple of touched state for all pins."""
174+
def touched_pins(self) -> Tuple[bool]:
175+
"""Get a tuple of the touched state for all pins."""
143176
touched = self.touched()
144177
return tuple(bool(touched >> i & 1) for i in range(12))
145178

146-
def _write_register_byte(self, register, value):
179+
def _write_register_byte(self, register: int, value: int) -> None:
147180
# Write a byte value to the specifier register address.
148181
# MPR121 must be put in Stop Mode to write to most registers
149182
stop_required = True
@@ -156,7 +189,9 @@ def _write_register_byte(self, register, value):
156189
if stop_required:
157190
self._i2c.write(bytes([MPR121_ECR, 0x8F]))
158191

159-
def _read_register_bytes(self, register, result, length=None):
192+
def _read_register_bytes(
193+
self, register: int, result: bytearray, length: Optional[int] = None
194+
) -> None:
160195
# Read the specified register address and fill the specified result byte
161196
# array with result bytes. Make sure result buffer is the desired size
162197
# of data to read.
@@ -165,23 +200,32 @@ def _read_register_bytes(self, register, result, length=None):
165200
with self._i2c:
166201
self._i2c.write_then_readinto(bytes([register]), result, in_end=length)
167202

168-
def reset(self):
169-
"""Reset the MPR121 into a default state ready to detect touch inputs."""
203+
def reset(self) -> None:
204+
"""Reset the MPR121 into a default state.
205+
206+
All configurations and states previously set are lost.
207+
208+
:raises RuntimeError: The sensor is in an invalid config state.
209+
"""
170210
# Write to the reset register.
171211
self._write_register_byte(MPR121_SOFTRESET, 0x63)
172212
time.sleep(
173213
0.001
174214
) # This 1ms delay here probably isn't necessary but can't hurt.
215+
175216
# Set electrode configuration to default values.
176217
self._write_register_byte(MPR121_ECR, 0x00)
218+
177219
# Check CDT, SFI, ESI configuration is at default values.
178220
self._read_register_bytes(MPR121_CONFIG2, self._buffer, 1)
179221
if self._buffer[0] != 0x24:
180222
raise RuntimeError("Failed to find MPR121 in expected config state!")
223+
181224
# Default touch and release thresholds
182225
for i in range(12):
183226
self._write_register_byte(MPR121_TOUCHTH_0 + 2 * i, 12)
184227
self._write_register_byte(MPR121_RELEASETH_0 + 2 * i, 6)
228+
185229
# Configure baseline filtering control registers.
186230
self._write_register_byte(MPR121_MHDR, 0x01)
187231
self._write_register_byte(MPR121_NHDR, 0x01)
@@ -194,43 +238,67 @@ def reset(self):
194238
self._write_register_byte(MPR121_NHDT, 0x00)
195239
self._write_register_byte(MPR121_NCLT, 0x00)
196240
self._write_register_byte(MPR121_FDLT, 0x00)
241+
197242
# Set other configuration registers.
198243
self._write_register_byte(MPR121_DEBOUNCE, 0)
199244
self._write_register_byte(MPR121_CONFIG1, 0x10) # default, 16uA charge current
200245
self._write_register_byte(MPR121_CONFIG2, 0x20) # 0.5uS encoding, 1ms period
246+
201247
# Enable all electrodes.
202248
self._write_register_byte(
203249
MPR121_ECR, 0x8F
204250
) # start with first 5 bits of baseline tracking
205251

206-
def filtered_data(self, pin):
207-
"""Return filtered data register value for the provided pin (0-11).
208-
Useful for debugging.
252+
def filtered_data(self, pin: int) -> int:
253+
"""Get the filtered data register value.
254+
255+
:param pin: The pin to read (0 - 11).
256+
:type pin: int
257+
258+
:raises ValueError: Argument ``pin`` is invalid.
259+
260+
:return: The filtered data value stored in the register.
261+
:rtype: int
209262
"""
210263
if pin < 0 or pin > 11:
211264
raise ValueError("Pin must be a value 0-11.")
212265
self._read_register_bytes(MPR121_FILTDATA_0L + pin * 2, self._buffer)
213266
return ((self._buffer[1] << 8) | (self._buffer[0])) & 0xFFFF
214267

215-
def baseline_data(self, pin):
216-
"""Return baseline data register value for the provided pin (0-11).
217-
Useful for debugging.
268+
def baseline_data(self, pin: int) -> int:
269+
"""Get the baseline data register value.
270+
271+
:param pin: The pin to read (0 - 11).
272+
:type pin: int
273+
274+
:raises ValueError: Argument ``pin`` is invalid.
275+
276+
:return: The baseline data value stored in the register.
277+
:rtype: int
218278
"""
219279
if pin < 0 or pin > 11:
220280
raise ValueError("Pin must be a value 0-11.")
221281
self._read_register_bytes(MPR121_BASELINE_0 + pin, self._buffer, 1)
222282
return self._buffer[0] << 2
223283

224-
def touched(self):
225-
"""Return touch state of all pins as a 12-bit value where each bit
226-
represents a pin, with a value of 1 being touched and 0 not being touched.
284+
def touched(self) -> int:
285+
"""Get the touch state of all pins as a 12-bit value.
286+
287+
:return: A 12-bit value representing the touch state of each
288+
pin. Each state in the value is represented by either a 1 or
289+
0; touched or not.
290+
:rtype: int
227291
"""
228292
self._read_register_bytes(MPR121_TOUCHSTATUS_L, self._buffer)
229293
return ((self._buffer[1] << 8) | (self._buffer[0])) & 0xFFFF
230294

231-
def is_touched(self, pin):
232-
"""Return True if the specified pin is being touched, otherwise returns
233-
False.
295+
def is_touched(self, pin: int) -> bool:
296+
"""Get if ``pin`` is being touched.
297+
298+
:raises ValueError: Argument ``pin`` is invalid.
299+
300+
:return: True if ``pin`` is being touched; otherwise False.
301+
:rtype: bool
234302
"""
235303
if pin < 0 or pin > 11:
236304
raise ValueError("Pin must be a value 0-11.")

0 commit comments

Comments
 (0)