Skip to content

Commit ab67238

Browse files
authored
Merge pull request #1 from tannewt/lint
Linted
2 parents 187a239 + 67d442b commit ab67238

File tree

6 files changed

+125
-43
lines changed

6 files changed

+125
-43
lines changed

README.rst

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Dependencies
2828
=============
2929
This driver depends on:
3030

31-
* `Adafruit CircuitPython <https://github.com/adafruit/circuitpython>`_
31+
* `Adafruit CircuitPython 9.0.0 and later <https://github.com/adafruit/circuitpython>`_
3232

3333
Please ensure all dependencies are available on the CircuitPython filesystem.
3434
This is easily achieved by downloading
@@ -37,18 +37,8 @@ or individual libraries can be installed using
3737
`circup <https://github.com/adafruit/circup>`_.
3838

3939

40-
41-
.. todo:: Describe the Adafruit product this library works with. For PCBs, you can also add the
42-
image from the assets folder in the PCB's GitHub repo.
43-
44-
`Purchase one from the Adafruit shop <http://www.adafruit.com/products/>`_
45-
4640
Installing from PyPI
4741
=====================
48-
.. note:: This library is not available on PyPI yet. Install documentation is included
49-
as a standard element. Stay tuned for PyPI availability!
50-
51-
.. todo:: Remove the above note if PyPI version is/will be available at time of release.
5242

5343
On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from
5444
PyPI <https://pypi.org/project/adafruit-circuitpython-usb-host-mass-storage/>`_.
@@ -99,8 +89,51 @@ Or the following command to update an existing version:
9989
Usage Example
10090
=============
10191

102-
.. todo:: Add a quick, simple example. It and other examples should live in the
103-
examples folder and be included in docs/examples.rst.
92+
Print basic information about a device and its first (and usually only) configuration.
93+
94+
.. code-block:: python
95+
96+
import usb.core
97+
import os
98+
import storage
99+
import time
100+
101+
from adafruit_usb_host_descriptors import *
102+
103+
DIR_IN = 0x80
104+
105+
while True:
106+
print("searching for devices")
107+
for device in usb.core.find(find_all=True):
108+
print("pid", hex(device.idProduct))
109+
print("vid", hex(device.idVendor))
110+
print("man", device.manufacturer)
111+
print("product", device.product)
112+
print("serial", device.serial_number)
113+
print("config[0]:")
114+
config_descriptor = get_configuration_descriptor(device, 0)
115+
116+
i = 0
117+
while i < len(config_descriptor):
118+
descriptor_len = config_descriptor[i]
119+
descriptor_type = config_descriptor[i + 1]
120+
if descriptor_type == DESC_CONFIGURATION:
121+
config_value = config_descriptor[i + 5]
122+
print(f" value {config_value:d}")
123+
elif descriptor_type == DESC_INTERFACE:
124+
interface_number = config_descriptor[i + 2]
125+
interface_class = config_descriptor[i + 5]
126+
interface_subclass = config_descriptor[i + 6]
127+
print(f" interface[{interface_number:d}] class {interface_class:02x} subclass {interface_subclass:02x}")
128+
elif descriptor_type == DESC_ENDPOINT:
129+
endpoint_address = config_descriptor[i + 2]
130+
if endpoint_address & DIR_IN:
131+
print(f" IN {endpoint_address:02x}")
132+
else:
133+
print(f" OUT {endpoint_address:02x}")
134+
i += descriptor_len
135+
print()
136+
time.sleep(5)
104137
105138
Documentation
106139
=============

adafruit_usb_host_mass_storage.py

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@
1414

1515
import struct
1616
import time
17+
from typing import Optional
1718
import usb.core
1819
from micropython import const
19-
from adafruit_usb_host_descriptors import *
20+
import adafruit_usb_host_descriptors
2021

2122
__version__ = "0.0.0+auto.0"
22-
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_USB_Host_Mass_Storage.git"
23+
__repo__ = (
24+
"https://github.com/adafruit/Adafruit_CircuitPython_USB_Host_Mass_Storage.git"
25+
)
2326

2427
# USB defines
2528
_DIR_OUT = const(0x00)
@@ -32,27 +35,39 @@
3235
_MSC_REQ_GET_GET_MAX_LUN = const(254)
3336

3437
# SCSI commands
35-
_SCSI_CMD_TEST_UNIT_READY = const(0x00)
36-
"""The SCSI Test Unit Ready command is used to determine if a device is ready to transfer data (read/write), i.e. if a disk has spun up, if a tape is loaded and ready etc. The device does not perform a self-test operation."""
37-
_SCSI_CMD_INQUIRY = const(0x12)
38+
_SCSI_CMD_TEST_UNIT_READY = const(0x00)
39+
"""The SCSI Test Unit Ready command is used to determine if a device is ready to transfer data
40+
(read/write), i.e. if a disk has spun up, if a tape is loaded and ready etc. The device does not
41+
perform a self-test operation."""
42+
_SCSI_CMD_INQUIRY = const(0x12)
3843
"""The SCSI Inquiry command is used to obtain basic information from a target device."""
39-
_SCSI_CMD_READ_CAPACITY_10 = const(0x25)
40-
"""The SCSI Read Capacity command is used to obtain data capacity information from a target device."""
41-
_SCSI_CMD_REQUEST_SENSE = const(0x03)
42-
"""The SCSI Request Sense command is part of the SCSI computer protocol standard. This command is used to obtain sense data -- status/error information -- from a target device."""
43-
_SCSI_CMD_READ_10 = const(0x28)
44-
"""The READ (10) command requests that the device server read the specified logical block(s) and transfer them to the data-in buffer."""
45-
_SCSI_CMD_WRITE_10 = const(0x2A)
46-
"""The WRITE (10) command requests that the device server transfer the specified logical block(s) from the data-out buffer and write them."""
44+
_SCSI_CMD_READ_CAPACITY_10 = const(0x25)
45+
"""The SCSI Read Capacity command is used to obtain data capacity information from a target
46+
device."""
47+
_SCSI_CMD_REQUEST_SENSE = const(0x03)
48+
"""The SCSI Request Sense command is part of the SCSI computer protocol standard. This command is
49+
used to obtain sense data -- status/error information -- from a target device."""
50+
_SCSI_CMD_READ_10 = const(0x28)
51+
"""The READ (10) command requests that the device server read the specified logical block(s) and
52+
transfer them to the data-in buffer."""
53+
_SCSI_CMD_WRITE_10 = const(0x2A)
54+
"""The WRITE (10) command requests that the device server transfer the specified logical block(s)
55+
from the data-out buffer and write them."""
56+
4757

4858
class USBMassStorage:
59+
"""CircuitPython BlockDevice backed by a USB mass storage device (aka thumb drive)."""
60+
4961
def __init__(self, device: usb.core.Device, lun=0):
50-
config_descriptor = get_configuration_descriptor(device, 0)
62+
config_descriptor = adafruit_usb_host_descriptors.get_configuration_descriptor(
63+
device, 0
64+
)
5165

5266
self.in_ep = 0
5367
self.out_ep = 0
5468

5569
self.sector_count = None
70+
self.block_size = None
5671
# Look over each descriptor for mass storage interface and then the two
5772
# endpoints.
5873
in_msc_interface = False
@@ -62,16 +77,19 @@ def __init__(self, device: usb.core.Device, lun=0):
6277
while i < len(config_descriptor):
6378
descriptor_len = config_descriptor[i]
6479
descriptor_type = config_descriptor[i + 1]
65-
if descriptor_type == DESC_CONFIGURATION:
80+
if descriptor_type == adafruit_usb_host_descriptors.DESC_CONFIGURATION:
6681
config_value = config_descriptor[i + 5]
67-
elif descriptor_type == DESC_INTERFACE:
82+
elif descriptor_type == adafruit_usb_host_descriptors.DESC_INTERFACE:
6883
interface_number = config_descriptor[i + 2]
6984
interface_class = config_descriptor[i + 5]
7085
interface_subclass = config_descriptor[i + 6]
7186
in_msc_interface = interface_class == 8 and interface_subclass == 6
7287
if in_msc_interface:
7388
msc_interface = interface_number
74-
elif descriptor_type == DESC_ENDPOINT and in_msc_interface:
89+
elif (
90+
descriptor_type == adafruit_usb_host_descriptors.DESC_ENDPOINT
91+
and in_msc_interface
92+
):
7593
endpoint_address = config_descriptor[i + 2]
7694
if endpoint_address & _DIR_IN:
7795
self.in_ep = endpoint_address
@@ -89,7 +107,13 @@ def __init__(self, device: usb.core.Device, lun=0):
89107
# Get the max lun.
90108
max_lun = bytearray(1)
91109
try:
92-
device.ctrl_transfer(_REQ_RCPT_INTERFACE | _REQ_TYPE_CLASS | _DIR_IN, _MSC_REQ_GET_GET_MAX_LUN, 0, msc_interface, max_lun)
110+
device.ctrl_transfer(
111+
_REQ_RCPT_INTERFACE | _REQ_TYPE_CLASS | _DIR_IN,
112+
_MSC_REQ_GET_GET_MAX_LUN,
113+
0,
114+
msc_interface,
115+
max_lun,
116+
)
93117
max_lun = max_lun[0] + 1
94118
except usb.core.USBError:
95119
# Stall means 0.
@@ -108,8 +132,9 @@ def __init__(self, device: usb.core.Device, lun=0):
108132
self._wait_for_ready()
109133

110134
def _scsi_command(self, direction, command, data) -> None:
135+
"""Do a SCSI command over USB. Reads or writes to data depending on direction."""
111136
struct.pack_into("<IBxB", self.cbw, 8, len(data), direction, len(command))
112-
self.cbw[15:15+len(command)] = command
137+
self.cbw[15 : 15 + len(command)] = command
113138
# Write out the command.
114139
self.device.write(self.out_ep, self.cbw)
115140
# Depending on the direction, read or write the data.
@@ -123,6 +148,7 @@ def _scsi_command(self, direction, command, data) -> None:
123148
self.device.read(self.in_ep, self.csw)
124149

125150
def _wait_for_ready(self, tries=100):
151+
"""Waits for the device to be ready."""
126152
status = 12
127153
self.csw[status] = 1
128154
test_ready = bytearray(6)
@@ -145,36 +171,62 @@ def _wait_for_ready(self, tries=100):
145171
raise RuntimeError("Out of tries")
146172

147173
def _inquire(self) -> None:
174+
"""Run inquiry command"""
148175
response = bytearray(36)
149176
command = bytearray(6)
150177
command[0] = _SCSI_CMD_INQUIRY
151178
command[4] = len(response)
152179
self._scsi_command(_DIR_IN, command, response)
153180

154181
def _read_capacity(self) -> None:
182+
"""Read the device's capacity and store it in the object"""
155183
command = bytearray(10)
156184
command[0] = _SCSI_CMD_READ_CAPACITY_10
157185
response = bytearray(8)
158186

159187
self._scsi_command(_DIR_IN, command, response)
160188

161189
self.sector_count, self.block_size = struct.unpack(">II", response)
162-
self.sector_count += 1 # Response has the last valid number. Count is one greater.
190+
self.sector_count += (
191+
1 # Response has the last valid number. Count is one greater.
192+
)
163193

164194
def readblocks(self, block_num: int, buf: bytearray) -> None:
195+
"""Read data from block_num into buf"""
165196
command = bytearray(10)
166-
struct.pack_into(">BBIxH", command, 0, _SCSI_CMD_READ_10, self.lun, block_num, len(buf) // 512)
197+
struct.pack_into(
198+
">BBIxH",
199+
command,
200+
0,
201+
_SCSI_CMD_READ_10,
202+
self.lun,
203+
block_num,
204+
len(buf) // 512,
205+
)
167206

168207
self._scsi_command(_DIR_IN, command, buf)
169208

170209
def writeblocks(self, block_num: int, buf: bytearray) -> None:
210+
"""Write data to block_num from buf"""
171211
command = bytearray(10)
172-
struct.pack_into(">BBIxH", command, 0, _SCSI_CMD_WRITE_10, self.lun, block_num, len(buf) // 512)
212+
struct.pack_into(
213+
">BBIxH",
214+
command,
215+
0,
216+
_SCSI_CMD_WRITE_10,
217+
self.lun,
218+
block_num,
219+
len(buf) // 512,
220+
)
173221

174222
self._scsi_command(_DIR_OUT, command, buf)
175223

176224
def ioctl(self, operation: int, arg: Optional[int] = None) -> Optional[int]:
225+
"""Perform an IOCTL operation"""
226+
# This is a standard interface so we need to take arg even though we ignore it.
227+
# pylint: disable=unused-argument
177228
if operation == _MP_BLOCKDEV_IOCTL_BLOCK_COUNT:
178229
if not self.sector_count:
179230
self._read_capacity()
180231
return self.sector_count
232+
return None

docs/examples.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Simple test
22
------------
33

4-
Ensure your device works with this simple test.
4+
Mount a USB mass storage device to ``/usb_device`` in CircuitPython.
55

66
.. literalinclude:: ../examples/usb_host_mass_storage_simpletest.py
77
:caption: examples/usb_host_mass_storage_simpletest.py

docs/index.rst

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,10 @@ Table of Contents
2424
.. toctree::
2525
:caption: Tutorials
2626

27-
.. todo:: Add any Learn guide links here. If there are none, then simply delete this todo and leave
28-
the toctree above for use later.
29-
3027
.. toctree::
3128
:caption: Related Products
3229

33-
.. todo:: Add any product links here. If there are none, then simply delete this todo and leave
34-
the toctree above for use later.
30+
Adafruit Feather RP2040 USB Host <https://www.adafruit.com/product/5723>
3531

3632
.. toctree::
3733
:caption: Other Links

examples/usb_host_mass_storage_simpletest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
#
44
# SPDX-License-Identifier: Unlicense
55

6-
import usb.core
6+
import time
77
import os
88
import storage
9-
import time
9+
import usb.core
1010

1111
import adafruit_usb_host_mass_storage
1212

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
# SPDX-License-Identifier: MIT
55

66
Adafruit-Blinka
7+
adafruit-circuitpython-usb-host-descriptors

0 commit comments

Comments
 (0)