Skip to content

Commit 92f8966

Browse files
authored
Merge pull request #14 from tcfranks/main
Add Missing Type Annotations
2 parents 56ee7c1 + 8ff53ab commit 92f8966

File tree

2 files changed

+47
-32
lines changed

2 files changed

+47
-32
lines changed

adafruit_mcp4728.py

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@
3232
from time import sleep
3333
from adafruit_bus_device import i2c_device
3434

35+
try:
36+
from typing import Dict, Iterable, Iterator, List, Optional, Tuple
37+
from typing_extensions import Literal
38+
from busio import I2C
39+
except ImportError:
40+
pass
41+
3542
MCP4728_DEFAULT_ADDRESS = 0x60
3643

3744
MCP4728A4_DEFAULT_ADDRESS = 0x64
@@ -51,7 +58,9 @@ class CV:
5158
"""struct helper"""
5259

5360
@classmethod
54-
def add_values(cls, value_tuples):
61+
def add_values(
62+
cls, value_tuples: Iterable[Tuple[str, int, str, Optional[float]]]
63+
) -> None:
5564
"""creates CV entries"""
5665
cls.string = {}
5766
cls.lsb = {}
@@ -63,16 +72,14 @@ def add_values(cls, value_tuples):
6372
cls.lsb[value] = lsb
6473

6574
@classmethod
66-
def is_valid(cls, value):
75+
def is_valid(cls, value: int) -> bool:
6776
"""Returns true if the given value is a member of the CV"""
6877
return value in cls.string
6978

7079

7180
class Vref(CV):
7281
"""Options for ``vref``"""
7382

74-
pass # pylint: disable=unnecessary-pass
75-
7683

7784
Vref.add_values(
7885
(
@@ -117,7 +124,7 @@ class MCP4728:
117124
118125
"""
119126

120-
def __init__(self, i2c_bus, address: int = MCP4728_DEFAULT_ADDRESS):
127+
def __init__(self, i2c_bus: I2C, address: int = MCP4728_DEFAULT_ADDRESS) -> None:
121128

122129
self.i2c_device = i2c_device.I2CDevice(i2c_bus, address)
123130

@@ -129,17 +136,19 @@ def __init__(self, i2c_bus, address: int = MCP4728_DEFAULT_ADDRESS):
129136
self.channel_d = Channel(self, self._cache_page(*raw_registers[3]), 3)
130137

131138
@staticmethod
132-
def _get_flags(high_byte):
139+
def _get_flags(high_byte: int) -> Tuple[int, int, int]:
133140
vref = (high_byte & 1 << 7) > 0
134141
gain = (high_byte & 1 << 4) > 0
135142
power_state = (high_byte & 0b011 << 5) >> 5
136143
return (vref, gain, power_state)
137144

138145
@staticmethod
139-
def _cache_page(value, vref, gain, power_state):
146+
def _cache_page(
147+
value: int, vref: int, gain: int, power_state: int
148+
) -> Dict[str, int]:
140149
return {"value": value, "vref": vref, "gain": gain, "power_state": power_state}
141150

142-
def _read_registers(self):
151+
def _read_registers(self) -> List[Tuple[int, int, int, int]]:
143152
buf = bytearray(24)
144153

145154
with self.i2c_device as i2c:
@@ -158,7 +167,7 @@ def _read_registers(self):
158167

159168
return current_values
160169

161-
def save_settings(self):
170+
def save_settings(self) -> None:
162171
"""Saves the currently selected values, Vref, and gain selections for each channel
163172
to the EEPROM, setting them as defaults on power up"""
164173
byte_list = []
@@ -169,7 +178,7 @@ def save_settings(self):
169178
self._write_multi_eeprom(byte_list)
170179

171180
# TODO: add the ability to set an offset
172-
def _write_multi_eeprom(self, byte_list):
181+
def _write_multi_eeprom(self, byte_list: List[int]) -> None:
173182
buffer_list = [_MCP4728_CH_A_MULTI_EEPROM]
174183
buffer_list += byte_list
175184

@@ -180,7 +189,7 @@ def _write_multi_eeprom(self, byte_list):
180189

181190
sleep(0.015) # the better to write you with
182191

183-
def sync_vrefs(self):
192+
def sync_vrefs(self) -> None:
184193
"""Syncs the driver's vref state with the DAC"""
185194
gain_setter_command = 0b10000000
186195
gain_setter_command |= self.channel_a.vref << 3
@@ -193,7 +202,7 @@ def sync_vrefs(self):
193202
with self.i2c_device as i2c:
194203
i2c.write(buf)
195204

196-
def sync_gains(self):
205+
def sync_gains(self) -> None:
197206
"""Syncs the driver's gain state with the DAC"""
198207

199208
sync_setter_command = 0b11000000
@@ -208,7 +217,7 @@ def sync_gains(self):
208217
with self.i2c_device as i2c:
209218
i2c.write(buf)
210219

211-
def _set_value(self, channel):
220+
def _set_value(self, channel: "Channel") -> None:
212221

213222
channel_bytes = self._generate_bytes_with_flags(channel)
214223

@@ -222,7 +231,7 @@ def _set_value(self, channel):
222231
i2c.write(output_buffer)
223232

224233
@staticmethod
225-
def _generate_bytes_with_flags(channel):
234+
def _generate_bytes_with_flags(channel: "Channel") -> bytearray:
226235
buf = bytearray(2)
227236
pack_into(">H", buf, 0, channel.raw_value)
228237

@@ -232,12 +241,12 @@ def _generate_bytes_with_flags(channel):
232241
return buf
233242

234243
@staticmethod
235-
def _chunk(big_list, chunk_size):
244+
def _chunk(big_list: bytearray, chunk_size: int) -> Iterator[bytearray]:
236245
"""Divides a given list into `chunk_size` sized chunks"""
237246
for i in range(0, len(big_list), chunk_size):
238247
yield big_list[i : i + chunk_size]
239248

240-
def _general_call(self, byte_command):
249+
def _general_call(self, byte_command: int) -> None:
241250
buffer_list = [_MCP4728_GENERAL_CALL_ADDRESS]
242251
buffer_list += [byte_command]
243252

@@ -246,20 +255,20 @@ def _general_call(self, byte_command):
246255
with self.i2c_device as i2c:
247256
i2c.write(buf)
248257

249-
def reset(self):
258+
def reset(self) -> None:
250259
"""Internal Reset similar to a Power-on Reset (POR).
251260
The contents of the EEPROM are loaded into each DAC input
252261
and output registers immediately"""
253262

254263
self._general_call(_MCP4728_GENERAL_CALL_RESET_COMMAND)
255264

256-
def wakeup(self):
265+
def wakeup(self) -> None:
257266
"""Reset the Power-Down bits (PD1, PD0 = 0,0) and
258267
Resumes Normal Operation mode"""
259268

260269
self._general_call(_MCP4728_GENERAL_CALL_WAKEUP_COMMAND)
261270

262-
def soft_update(self):
271+
def soft_update(self) -> None:
263272
"""Updates all DAC analog outputs (VOUT) at the same time."""
264273

265274
self._general_call(_MCP4728_GENERAL_CALL_SOFTWARE_UPDATE_COMMAND)
@@ -281,59 +290,64 @@ class Channel:
281290
282291
"""
283292

284-
def __init__(self, dac_instance, cache_page, index):
293+
def __init__(
294+
self,
295+
dac_instance: Literal[0, 1, 2, 3],
296+
cache_page: Dict[str, int],
297+
index: int,
298+
) -> None:
285299
self._vref = cache_page["vref"]
286300
self._gain = cache_page["gain"]
287301
self._raw_value = cache_page["value"]
288302
self._dac = dac_instance
289303
self.channel_index = index
290304

291305
@property
292-
def normalized_value(self):
306+
def normalized_value(self) -> float:
293307
"""The DAC value as a floating point number in the range 0.0 to 1.0."""
294308
return self.raw_value / (2**12 - 1)
295309

296310
@normalized_value.setter
297-
def normalized_value(self, value):
311+
def normalized_value(self, value: float) -> None:
298312
if value < 0.0 or value > 1.0:
299313
raise AttributeError("`normalized_value` must be between 0.0 and 1.0")
300314

301315
self.raw_value = int(value * 4095.0)
302316

303317
@property
304-
def value(self):
318+
def value(self) -> int:
305319
"""The 16-bit scaled current value for the channel. Note that the MCP4728 is a 12-bit piece
306320
so quantization errors will occur"""
307321
return self.normalized_value * (2**16 - 1)
308322

309323
@value.setter
310-
def value(self, value):
324+
def value(self, value: int) -> None:
311325
if value < 0 or value > (2**16 - 1):
312326
raise AttributeError(
313-
"`value` must be a 16-bit integer between 0 and %s" % (2**16 - 1)
327+
f"`value` must be a 16-bit integer between 0 and {(2**16 - 1)}"
314328
)
315329

316330
# Scale from 16-bit to 12-bit value (quantization errors will occur!).
317331
self.raw_value = value >> 4
318332

319333
@property
320-
def raw_value(self):
334+
def raw_value(self) -> int:
321335
"""The native 12-bit value used by the DAC"""
322336
return self._raw_value
323337

324338
@raw_value.setter
325-
def raw_value(self, value):
339+
def raw_value(self, value: int) -> None:
326340
if value < 0 or value > (2**12 - 1):
327341
raise AttributeError(
328-
"`raw_value` must be a 12-bit integer between 0 and %s" % (2**12 - 1)
342+
f"`raw_value` must be a 12-bit integer between 0 and {(2**12 - 1)}"
329343
)
330344
self._raw_value = value
331345
# disabling the protected access warning here because making it public would be
332346
# more confusing
333347
self._dac._set_value(self) # pylint:disable=protected-access
334348

335349
@property
336-
def gain(self):
350+
def gain(self) -> Literal[1, 2]:
337351
"""Sets the gain of the channel if the Vref for the channel is ``Vref.INTERNAL``.
338352
**The gain setting has no effect if the Vref for the channel is `Vref.VDD`**.
339353
@@ -342,19 +356,19 @@ def gain(self):
342356
return self._gain
343357

344358
@gain.setter
345-
def gain(self, value):
359+
def gain(self, value: Literal[1, 2]) -> None:
346360
if not value in (1, 2):
347361
raise AttributeError("`gain` must be 1 or 2")
348362
self._gain = value - 1
349363
self._dac.sync_gains()
350364

351365
@property
352-
def vref(self):
366+
def vref(self) -> Literal[0, 1]:
353367
"""Sets the DAC's voltage reference source. Must be a ``VREF``"""
354368
return self._vref
355369

356370
@vref.setter
357-
def vref(self, value):
371+
def vref(self, value: Literal[0, 1]) -> None:
358372
if not Vref.is_valid(value):
359373
raise AttributeError("range must be a `Vref`")
360374
self._vref = value

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44

55
Adafruit-Blinka
66
adafruit-circuitpython-busdevice
7+
typing-extensions~=4.0

0 commit comments

Comments
 (0)