32
32
33
33
import time
34
34
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
+
35
43
from adafruit_bus_device import i2c_device
36
44
from micropython import const
37
45
79
87
80
88
class MPR121_Channel :
81
89
# 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
84
97
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
+ """
86
104
self ._mpr121 = mpr121
87
105
self ._channel = channel
88
106
89
107
@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."""
92
110
return self ._mpr121 .touched () & (1 << self ._channel ) != 0
93
111
94
112
@property
95
- def raw_value (self ):
96
- """The raw touch measurement."""
113
+ def raw_value (self ) -> int :
114
+ """Get the raw touch measurement."""
97
115
return self ._mpr121 .filtered_data (self ._channel )
98
116
99
117
@property
100
- def threshold (self ):
101
- """The touch threshold."""
118
+ def threshold (self ) -> int :
119
+ """Get or set the touch threshold."""
102
120
buf = bytearray (1 )
103
121
self ._mpr121 ._read_register_bytes (MPR121_TOUCHTH_0 + 2 * self ._channel , buf , 1 )
104
122
return buf [0 ]
105
123
106
124
@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
+ )
109
129
110
130
@property
111
- def release_threshold (self ):
112
- """The release threshold."""
131
+ def release_threshold (self ) -> int :
132
+ """Get or set the release threshold."""
113
133
buf = bytearray (1 )
114
134
self ._mpr121 ._read_register_bytes (
115
135
MPR121_RELEASETH_0 + 2 * self ._channel , buf , 1
116
136
)
117
137
return buf [0 ]
118
138
119
139
@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
+ )
122
144
123
145
124
146
class MPR121 :
125
147
"""Driver for the MPR121 capacitive touch breakout board."""
126
148
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
+ """
128
161
self ._i2c = i2c_device .I2CDevice (i2c , address )
129
162
self ._buffer = bytearray (2 )
130
163
self ._channels = [None ] * 12
131
164
self .reset ()
132
165
133
- def __getitem__ (self , key ) :
166
+ def __getitem__ (self , key : int ) -> MPR121_Channel :
134
167
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" )
136
169
if self ._channels [key ] is None :
137
170
self ._channels [key ] = MPR121_Channel (self , key )
138
171
return self ._channels [key ]
139
172
140
173
@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."""
143
176
touched = self .touched ()
144
177
return tuple (bool (touched >> i & 1 ) for i in range (12 ))
145
178
146
- def _write_register_byte (self , register , value ) :
179
+ def _write_register_byte (self , register : int , value : int ) -> None :
147
180
# Write a byte value to the specifier register address.
148
181
# MPR121 must be put in Stop Mode to write to most registers
149
182
stop_required = True
@@ -156,7 +189,9 @@ def _write_register_byte(self, register, value):
156
189
if stop_required :
157
190
self ._i2c .write (bytes ([MPR121_ECR , 0x8F ]))
158
191
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 :
160
195
# Read the specified register address and fill the specified result byte
161
196
# array with result bytes. Make sure result buffer is the desired size
162
197
# of data to read.
@@ -165,23 +200,32 @@ def _read_register_bytes(self, register, result, length=None):
165
200
with self ._i2c :
166
201
self ._i2c .write_then_readinto (bytes ([register ]), result , in_end = length )
167
202
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
+ """
170
210
# Write to the reset register.
171
211
self ._write_register_byte (MPR121_SOFTRESET , 0x63 )
172
212
time .sleep (
173
213
0.001
174
214
) # This 1ms delay here probably isn't necessary but can't hurt.
215
+
175
216
# Set electrode configuration to default values.
176
217
self ._write_register_byte (MPR121_ECR , 0x00 )
218
+
177
219
# Check CDT, SFI, ESI configuration is at default values.
178
220
self ._read_register_bytes (MPR121_CONFIG2 , self ._buffer , 1 )
179
221
if self ._buffer [0 ] != 0x24 :
180
222
raise RuntimeError ("Failed to find MPR121 in expected config state!" )
223
+
181
224
# Default touch and release thresholds
182
225
for i in range (12 ):
183
226
self ._write_register_byte (MPR121_TOUCHTH_0 + 2 * i , 12 )
184
227
self ._write_register_byte (MPR121_RELEASETH_0 + 2 * i , 6 )
228
+
185
229
# Configure baseline filtering control registers.
186
230
self ._write_register_byte (MPR121_MHDR , 0x01 )
187
231
self ._write_register_byte (MPR121_NHDR , 0x01 )
@@ -194,43 +238,67 @@ def reset(self):
194
238
self ._write_register_byte (MPR121_NHDT , 0x00 )
195
239
self ._write_register_byte (MPR121_NCLT , 0x00 )
196
240
self ._write_register_byte (MPR121_FDLT , 0x00 )
241
+
197
242
# Set other configuration registers.
198
243
self ._write_register_byte (MPR121_DEBOUNCE , 0 )
199
244
self ._write_register_byte (MPR121_CONFIG1 , 0x10 ) # default, 16uA charge current
200
245
self ._write_register_byte (MPR121_CONFIG2 , 0x20 ) # 0.5uS encoding, 1ms period
246
+
201
247
# Enable all electrodes.
202
248
self ._write_register_byte (
203
249
MPR121_ECR , 0x8F
204
250
) # start with first 5 bits of baseline tracking
205
251
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
209
262
"""
210
263
if pin < 0 or pin > 11 :
211
264
raise ValueError ("Pin must be a value 0-11." )
212
265
self ._read_register_bytes (MPR121_FILTDATA_0L + pin * 2 , self ._buffer )
213
266
return ((self ._buffer [1 ] << 8 ) | (self ._buffer [0 ])) & 0xFFFF
214
267
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
218
278
"""
219
279
if pin < 0 or pin > 11 :
220
280
raise ValueError ("Pin must be a value 0-11." )
221
281
self ._read_register_bytes (MPR121_BASELINE_0 + pin , self ._buffer , 1 )
222
282
return self ._buffer [0 ] << 2
223
283
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
227
291
"""
228
292
self ._read_register_bytes (MPR121_TOUCHSTATUS_L , self ._buffer )
229
293
return ((self ._buffer [1 ] << 8 ) | (self ._buffer [0 ])) & 0xFFFF
230
294
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
234
302
"""
235
303
if pin < 0 or pin > 11 :
236
304
raise ValueError ("Pin must be a value 0-11." )
0 commit comments