Skip to content

Add type annotations #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 55 additions & 21 deletions adafruit_sdcard.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@
from micropython import const
from adafruit_bus_device import spi_device

try:
from typing import Union, Optional
from busio import SPI
from digitalio import DigitalInOut
from circuitpython_typing import ReadableBuffer, WriteableBuffer
except ImportError:
pass

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_SD.git"

Expand Down Expand Up @@ -86,7 +94,7 @@ class SDCard:

"""

def __init__(self, spi, cs, baudrate=1320000):
def __init__(self, spi: SPI, cs: DigitalInOut, baudrate: int = 1320000) -> None:
# Create an SPIDevice running at a lower initialization baudrate first.
self._spi = spi_device.SPIDevice(spi, cs, baudrate=250000, extra_clocks=8)

Expand All @@ -102,7 +110,7 @@ def __init__(self, spi, cs, baudrate=1320000):
# Create a new SPIDevice with the (probably) higher operating baudrate.
self._spi = spi_device.SPIDevice(spi, cs, baudrate=baudrate, extra_clocks=8)

def _init_card(self, chip_select):
def _init_card(self, chip_select: DigitalInOut) -> None:
"""Initialize the card in SPI mode."""
# clock card at least 80 cycles with cs high
with self._spi as card:
Expand Down Expand Up @@ -152,7 +160,7 @@ def _init_card(self, chip_select):
if self._cmd(card, 16, 512, 0x15) != 0:
raise OSError("can't set 512 block size")

def _init_card_v1(self, card):
def _init_card_v1(self, card: SPI) -> None:
"""Initialize v1 SDCards which use byte addressing."""
for _ in range(_CMD_TIMEOUT):
self._cmd(card, 55, 0, 0)
Expand All @@ -161,7 +169,7 @@ def _init_card_v1(self, card):
return
raise OSError("timeout waiting for v1 card")

def _init_card_v2(self, card):
def _init_card_v2(self, card: SPI) -> None:
"""Initialize v2 SDCards which use 512-byte block addressing."""
ocr = bytearray(4)
for _ in range(_CMD_TIMEOUT):
Expand All @@ -180,7 +188,7 @@ def _init_card_v2(self, card):
return
raise OSError("timeout waiting for v2 card")

def _wait_for_ready(self, card, timeout=0.3):
def _wait_for_ready(self, card: SPI, timeout: float = 0.3) -> None:
"""
Wait for the card to clock out 0xff to indicate its ready.

Expand All @@ -196,17 +204,25 @@ def _wait_for_ready(self, card, timeout=0.3):
# pylint: disable=no-member
# no-member disable should be reconsidered when it can be tested
def _cmd(
self, card, cmd, arg=0, crc=0, response_buf=None, data_block=True, wait=True
):
self,
card: SPI,
cmd: int,
arg: Union[int, ReadableBuffer] = 0,
crc: int = 0,
response_buf: Optional[WriteableBuffer] = None,
data_block: bool = True,
wait: bool = True,
) -> int:
"""
Issue a command to the card and read an optional data response.

:param busio.SPI card: The locked SPI bus.
:param int cmd: The command number.
:param int|buf(4) arg: The command argument
:param int crc: The crc to allow the card to verify the command and argument.
:param bytearray response_buf: Buffer to read a data block response into.
:param WriteableBuffer response_buf: Buffer to read a data block response into.
:param bool data_block: True if the response data is in a data block.
:param bool wait: True if the command should wait until the card is ready
"""
# create and send the command
buf = self._cmdbuf
Expand Down Expand Up @@ -252,14 +268,22 @@ def _cmd(
# pylint: enable-msg=too-many-arguments

# pylint: disable-msg=too-many-arguments
def _block_cmd(self, card, cmd, block, crc, response_buf=None):
def _block_cmd(
self,
card: SPI,
cmd: int,
block: int,
crc: int,
response_buf: Optional[WriteableBuffer] = None,
) -> int:
"""
Issue a command to the card with a block argument.

:param busio.SPI card: The locked SPI bus.
:param int cmd: The command number.
:param int block: The relevant block.
:param int crc: The crc to allow the card to verify the command and argument.
:param WriteableBuffer response_buf: Buffer to read a data block response into.
"""
if self._cdv == 1:
return self._cmd(card, cmd, block, crc, response_buf=response_buf)
Expand Down Expand Up @@ -301,12 +325,13 @@ def _block_cmd(self, card, cmd, block, crc, response_buf=None):

# pylint: enable-msg=too-many-arguments

def _cmd_nodata(self, card, cmd, response=0xFF):
def _cmd_nodata(self, card: SPI, cmd: int, response: int = 0xFF) -> int:
"""
Issue a command to the card with no argument.

:param busio.SPI card: The locked SPI bus.
:param int cmd: The command number.
:param int response: The expected response, default is ``0xFF``
"""
buf = self._cmdbuf
buf[0] = cmd
Expand All @@ -319,12 +344,14 @@ def _cmd_nodata(self, card, cmd, response=0xFF):
return 0 # OK
return 1 # timeout

def _readinto(self, card, buf, start=0, end=None):
def _readinto(
self, card: SPI, buf: WriteableBuffer, start: int = 0, end: Optional[int] = None
) -> None:
"""
Read a data block into buf.

:param busio.SPI card: The locked SPI bus.
:param bytearray buf: The buffer to write into
:param WriteableBuffer buf: The buffer to write into
:param int start: The first index to write data at
:param int end: The index after the last byte to write to.
"""
Expand All @@ -342,13 +369,20 @@ def _readinto(self, card, buf, start=0, end=None):
card.readinto(self._cmdbuf, end=2, write_value=0xFF)

# pylint: disable-msg=too-many-arguments
def _write(self, card, token, buf, start=0, end=None):
def _write(
self,
card: SPI,
token: int,
buf: ReadableBuffer,
start: int = 0,
end: Optional[int] = None,
) -> int:
"""
Write a data block to the card.

:param busio.SPI card: The locked SPI bus.
:param int token: The start token
:param bytearray buf: The buffer to write from
:param ReadableBuffer buf: The buffer to write from
:param int start: The first index to read data from
:param int end: The index after the last byte to read from.
"""
Expand Down Expand Up @@ -386,7 +420,7 @@ def _write(self, card, token, buf, start=0, end=None):

# pylint: enable-msg=too-many-arguments

def count(self):
def count(self) -> int:
"""
Returns the total number of sectors.

Expand All @@ -395,12 +429,12 @@ def count(self):
"""
return self._sectors

def readblocks(self, start_block, buf):
def readblocks(self, start_block: int, buf: WriteableBuffer) -> int:
"""
Read one or more blocks from the card

:param int start_block: The block to start reading from
:param bytearray buf: The buffer to write into. Length must be multiple of 512.
:param WriteableBuffer buf: The buffer to write into. Length must be multiple of 512.
"""
nblocks, err = divmod(len(buf), 512)
assert nblocks and not err, "Buffer length is invalid"
Expand Down Expand Up @@ -429,12 +463,12 @@ def readblocks(self, start_block, buf):
ret = self._single_byte[0]
return 0

def writeblocks(self, start_block, buf):
def writeblocks(self, start_block: int, buf: ReadableBuffer) -> int:
"""
Write one or more blocks to the card

:param int start_block: The block to start writing to
:param bytearray buf: The buffer to write into. Length must be multiple of 512.
:param ReadableBuffer buf: The buffer to write into. Length must be multiple of 512.
"""
nblocks, err = divmod(len(buf), 512)
assert nblocks and not err, "Buffer length is invalid"
Expand Down Expand Up @@ -462,7 +496,7 @@ def writeblocks(self, start_block, buf):
return 0


def _calculate_crc_table():
def _calculate_crc_table() -> bytearray:
"""Precompute the table used in calculate_crc."""
# Code converted from https://github.com/hazelnusse/crc7/blob/master/crc7.cc by devoh747
# With permission from Dale Lukas Peterson <hazelnusse@gmail.com>
Expand All @@ -487,7 +521,7 @@ def _calculate_crc_table():
CRC_TABLE = _calculate_crc_table()


def calculate_crc(message):
def calculate_crc(message: ReadableBuffer) -> int:
"""
Calculate the CRC of message[0:5], using a precomputed table in CRC_TABLE.

Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
#
# SPDX-License-Identifier: Unlicense

Adafruit-Blinka
Adafruit-Blinka>=7.0.0
adafruit-circuitpython-busdevice
adafruit-circuitpython-typing
6 changes: 5 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@
# Author details
author="Adafruit Industries",
author_email="circuitpython@adafruit.com",
install_requires=["Adafruit-Blinka", "adafruit-circuitpython-busdevice"],
install_requires=[
"Adafruit-Blinka>=7.0.0",
"adafruit-circuitpython-busdevice",
"adafruit-circuitpython-typing",
],
# Choose your license
license="MIT",
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
Expand Down