X-Git-Url: https://git.ayoreis.com/Adafruit_Blinka-hackapet.git/blobdiff_plain/f5efceca6644ed0e546ae4f3e559507bb87ae933..c2bc4a90827f28abb6b51eae659a1f80a65c0497:/src/adafruit_blinka/microcontroller/mcp2221/mcp2221.py diff --git a/src/adafruit_blinka/microcontroller/mcp2221/mcp2221.py b/src/adafruit_blinka/microcontroller/mcp2221/mcp2221.py index 7597ca6..2dcc539 100644 --- a/src/adafruit_blinka/microcontroller/mcp2221/mcp2221.py +++ b/src/adafruit_blinka/microcontroller/mcp2221/mcp2221.py @@ -1,18 +1,22 @@ +# SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries +# +# SPDX-License-Identifier: MIT """Chip Definition for MCP2221""" import os import time +import atexit + import hid # Here if you need it MCP2221_HID_DELAY = float(os.environ.get("BLINKA_MCP2221_HID_DELAY", 0)) -# Use to set delay between reset and device reopen +# Use to set delay between reset and device reopen. if negative, don't reset at all MCP2221_RESET_DELAY = float(os.environ.get("BLINKA_MCP2221_RESET_DELAY", 0.5)) # from the C driver # http://ww1.microchip.com/downloads/en/DeviceDoc/mcp2221_0_1.tar.gz # others (???) determined during driver developement -# pylint: disable=bad-whitespace RESP_ERR_NOERR = 0x00 RESP_ADDR_NACK = 0x25 RESP_READ_ERR = 0x7F @@ -35,7 +39,6 @@ RESP_I2C_WRITINGNOSTOP = 0x45 # ??? MCP2221_RETRY_MAX = 50 MCP2221_MAX_I2C_DATA_LEN = 60 MASK_ADDR_NACK = 0x40 -# pylint: enable=bad-whitespace class MCP2221: @@ -53,12 +56,23 @@ class MCP2221: def __init__(self): self._hid = hid.device() self._hid.open(MCP2221.VID, MCP2221.PID) - self._reset() + # make sure the device gets closed before exit + atexit.register(self.close) + if MCP2221_RESET_DELAY >= 0: + self._reset() self._gp_config = [0x07] * 4 # "don't care" initial value for pin in range(4): self.gp_set_mode(pin, self.GP_GPIO) # set to GPIO mode self.gpio_set_direction(pin, 1) # set to INPUT + def close(self): + """Close the hid device. Does nothing if the device is not open.""" + self._hid.close() + + def __del__(self): + # try to close the device before destroying the instance + self.close() + def _hid_xfer(self, report, response=True): """Perform HID Transfer""" # first byte is report ID, which =0 for MCP2221 @@ -119,6 +133,7 @@ class MCP2221: def _reset(self): self._hid_xfer(b"\x70\xAB\xCD\xEF", response=False) + self._hid.close() time.sleep(MCP2221_RESET_DELAY) start = time.monotonic() while time.monotonic() - start < 5: @@ -190,7 +205,7 @@ class MCP2221: # bus release will need "a few hundred microseconds" time.sleep(0.001) - # pylint: disable=too-many-arguments + # pylint: disable=too-many-arguments,too-many-branches def _i2c_write(self, cmd, address, buffer, start=0, end=None): if self._i2c_state() != 0x00: self._i2c_cancel() @@ -199,7 +214,7 @@ class MCP2221: length = end - start retries = 0 - while (end - start) > 0: + while (end - start) > 0 or not buffer: chunk = min(end - start, MCP2221_MAX_I2C_DATA_LEN) # write out current chunk resp = self._hid_xfer( @@ -224,6 +239,8 @@ class MCP2221: # yay chunk sent! while self._i2c_state() == RESP_I2C_PARTIALDATA: time.sleep(0.001) + if not buffer: + break start += chunk retries = 0 @@ -231,7 +248,7 @@ class MCP2221: for _ in range(MCP2221_RETRY_MAX): status = self._i2c_status() if status[20] & MASK_ADDR_NACK: - raise RuntimeError("I2C slave address was NACK'd") + raise OSError("I2C slave address was NACK'd") usb_cmd_status = status[8] if usb_cmd_status == 0: break @@ -268,7 +285,7 @@ class MCP2221: # and now the read part while (end - start) > 0: - for retry in range(MCP2221_RETRY_MAX): + for _ in range(MCP2221_RETRY_MAX): # the actual read resp = self._hid_xfer(b"\x40") # check for success @@ -286,6 +303,8 @@ class MCP2221: continue if resp[2] in (RESP_READ_COMPL, RESP_READ_PARTIAL): break + else: + raise RuntimeError("I2C read error: max retries reached.") # move data into buffer chunk = min(end - start, 60) @@ -295,7 +314,7 @@ class MCP2221: # pylint: enable=too-many-arguments - def i2c_configure(self, baudrate=100000): + def _i2c_configure(self, baudrate=100000): """Configure I2C""" self._hid_xfer( bytes( @@ -326,7 +345,7 @@ class MCP2221: out_start=0, out_end=None, in_start=0, - in_end=None + in_end=None, ): """Write data from buffer_out to an address and then read data from an address and into buffer_in @@ -341,7 +360,8 @@ class MCP2221: # try a write try: self.i2c_writeto(addr, b"\x00") - except RuntimeError: # no reply! + except OSError: # no reply! + # We got a NACK, which could be correct continue # store if success found.append(addr)