USB¤
Prerequisites¤
Before communicating with a USB device, a libusb-compatible driver must be installed and the directory to the libusb library must be available on the PATH environment variable.
The following instructions are intended to be a starting point if you are having issues communicating with a USB device.
Windows¤
Download the latest libusb library from the repository.
Tip
Here, version 1.0.29 is downloaded. Update this value in the following command if there is a new release.
Invoke-WebRequest -Uri https://github.com/libusb/libusb/releases/download/v1.0.29/libusb-1.0.29.7z -OutFile libusb.7z
Use 7zip to extract the zip file. First, install 7zip if it's not already.
winget install 7zip.7zip
Then extract the library file and copy the appropriate (i.e., x86 or x64, VS or MinGW) libusb-1.0.dll file to a directory that is on your PATH environment variable. The following command extracts the 64-bit library file that was built with Visual Studio 2022 to the C:\Windows\System32 directory, but you may choose to extract a different DLL file to a different directory.
& 'C:\Program Files\7-Zip\7z' e libusb.7z -oC:\Windows\System32 VS2022\MS64\dll\libusb-1.0.dll
Finally, install the Zadig application
winget install akeo.ie.Zadig
then run Zadig (you must open a new administrative terminal to run the following command)
zadig
to install a driver (WinUSB is recommended) for the USB device — follow the Zadig User Guide.
See How to use libusb on Windows for additional information.
Debian/Ubuntu¤
Install the libusb-1.0-0 package.
sudo apt install libusb-1.0-0
To access a USB device without root privilege you should create a udev configuration file. There are many ways to configure udev, here is a typical setup.
# /etc/udev/rules.d/10-custom.rules
SUBSYSTEM=="usb", ATTR{idVendor}=="03eb", ATTR{idProduct}=="2107", GROUP="plugdev", MODE="0664"
SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="6001", GROUP="plugdev", MODE="0664"
SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="faf0", GROUP="plugdev", MODE="0664"
You need to unplug / plug back the USB device once this file has been created so that udev loads the rules for the matching device, or alternatively, inform the udev daemon about the changes.
sudo udevadm control --reload-rules
sudo udevadm trigger
With this setup, be sure to add users that want to access the USB device(s) to the plugdev group.
sudo adduser $USER plugdev
Remember that you need to log out / log in to get the above command effective, or start a subshell.
newgrp plugdev
macOS¤
Install the libusb package.
brew install libusb
Endpoint
dataclass
¤
Information about a USB Endpoint.
Attributes:
| Name | Type | Description |
|---|---|---|
address |
int
|
The |
max_packet_size |
int
|
The |
interface_number |
int
|
The |
USB
(MessageBased)
¤
USB(equipment: Equipment)
Base class for (raw) USB communication.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
equipment
|
Equipment
|
An Equipment instance. |
required |
A Connection instance supports the following properties for the USB communication protocol, as well as the properties defined in MessageBased.
Connection Properties:
| Name | Type | Description |
|---|---|---|
bAlternateSetting |
int
|
The value of |
bConfigurationValue |
int | None
|
The value of |
buffer_size |
int
|
The maximum number of bytes to read at a time. Default: |
usb_backend |
Literal['libusb1', 'libusb0', 'openusb'] | None
|
The PyUSB backend library to use
for the connection. If |
Source code in src/msl/equipment/interfaces/usb.py
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | |
device_version
property
¤
device_version: int
Returns the device version (release) number.
Corresponds to the bcdDevice field in the Device Descriptor.
intr_in_endpoint
property
¤
intr_in_endpoint: Endpoint | None
Information about the Interrupt-IN endpoint.
intr_out_endpoint
property
¤
intr_out_endpoint: Endpoint | None
Information about the Interrupt-OUT endpoint.
build_request_type
staticmethod
¤
build_request_type(
direction: CtrlDirection, type: CtrlType, recipient: CtrlRecipient
) -> int
Build a bmRequestType field for a control request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
direction
|
CtrlDirection
|
Transfer direction. |
required |
type
|
CtrlType
|
Transfer type. |
required |
recipient
|
CtrlRecipient
|
Recipient of the transfer. |
required |
Returns:
| Type | Description |
|---|---|
int
|
The |
Source code in src/msl/equipment/interfaces/usb.py
471 472 473 474 475 476 477 478 479 480 481 482 483 484 | |
clear_halt
¤
clear_halt(endpoint: Endpoint) -> None
Clear the halt/stall condition for an endpoint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
endpoint
|
Endpoint
|
The endpoint to clear. |
required |
Source code in src/msl/equipment/interfaces/usb.py
496 497 498 499 500 501 502 503 504 505 506 | |
ctrl_transfer
¤
ctrl_transfer(
request_type: int,
request: int,
value: int = ...,
index: int = ...,
data_or_length: None = None,
) -> int | array[int]
ctrl_transfer(
request_type: int,
request: int,
value: int = 0,
index: int = 0,
data_or_length: int | array[int] | bytes | bytearray | str | None = None,
) -> int | array[int]
Perform a control transfer on Endpoint 0.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request_type
|
int
|
The bmRequestType field of the request. The bitmap value defines the direction (OUT or IN) of the request, the type of request and the designated recipient. See build_request_type. |
required |
request
|
int
|
The bRequest field of the request. |
required |
value
|
int
|
The wValue field of the request. |
0
|
index
|
int
|
The wIndex field of the request. |
0
|
data_or_length
|
int | array[int] | bytes | bytearray | str | None
|
Either the data payload for an OUT request, an array buffer to receive data for an IN request, or the number of bytes to read for an IN request. |
None
|
Returns:
| Type | Description |
|---|---|
int | array[int]
|
Source code in src/msl/equipment/interfaces/usb.py
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | |
disconnect
¤
disconnect() -> None
Disconnect from the USB device.
Source code in src/msl/equipment/interfaces/usb.py
600 601 602 603 604 605 606 607 608 609 610 611 612 613 | |
query
¤
query(
message: bytes | str,
*,
delay: float = 0.0,
decode: Literal[True] = True,
dtype: None = None,
fmt: MessageFormat = ...,
size: int | None = ...
) -> str
query(
message: bytes | str,
*,
delay: float = 0.0,
decode: Literal[False] = False,
dtype: None = None,
fmt: MessageFormat = ...,
size: int | None = ...
) -> bytes
query(
message: bytes | str,
*,
delay: float = 0.0,
decode: bool = ...,
dtype: MessageDataType = ...,
fmt: MessageFormat = ...,
size: int | None = ...
) -> NumpyArray1D
query(
message: bytes | str,
*,
delay: float = 0.0,
decode: bool = True,
dtype: MessageDataType | None = None,
fmt: MessageFormat = None,
size: int | None = None
) -> bytes | str | NumpyArray1D
Convenience method for performing a write followed by a read.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
bytes | str
|
The message to write to the equipment. |
required |
delay
|
float
|
Time delay, in seconds, to wait between the write and read operations. |
0.0
|
decode
|
bool
|
True
|
|
dtype
|
MessageDataType | None
|
The data type of the elements in the returned message. Can be any object that numpy
dtype supports. For messages that are of scalar type (i.e., a single number)
it is more efficient to not specify |
None
|
fmt
|
MessageFormat
|
The format that the returned message data is in. Ignored if |
None
|
size
|
int | None
|
The number of bytes to read. Ignored if the value is |
None
|
Returns:
| Type | Description |
|---|---|
bytes | str | NumpyArray1D
|
Source code in src/msl/equipment/interfaces/message_based.py
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | |
read
¤
read(
*,
decode: Literal[True] = True,
dtype: None = None,
fmt: MessageFormat = ...,
size: int | None = ...
) -> str
read(
*,
decode: Literal[False] = False,
dtype: None = None,
fmt: MessageFormat = ...,
size: int | None = ...
) -> bytes
read(
*,
decode: bool = ...,
dtype: MessageDataType = ...,
fmt: MessageFormat = ...,
size: int | None = ...
) -> NumpyArray1D
read(
*,
decode: bool = True,
dtype: MessageDataType | None = None,
fmt: MessageFormat = None,
size: int | None = None
) -> bytes | str | NumpyArray1D
Read a message from the equipment.
This method will block until one of the following conditions is fulfilled:
sizebytes have been received — only ifsizeis notNone.- the read_termination
byte(s) is(are) received — only if
read_termination
is not
None. - a timeout occurs — only if timeout
is not
None. If a timeout occurs, an MSLTimeoutError is raised. - max_read_size bytes have been received. If the maximum number of bytes have been read, an MSLConnectionError is raised.
Tip
You may also want to set the rstrip value for the class instance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
decode
|
bool
|
True
|
|
dtype
|
MessageDataType | None
|
The data type of the elements in the returned message. Can be any object that numpy
dtype supports. For messages that are of scalar type (i.e., a single number)
it is more efficient to not specify |
None
|
fmt
|
MessageFormat
|
The format that the returned message data is in. Ignored if |
None
|
size
|
int | None
|
The number of bytes to read. Ignored if the value is |
None
|
Returns:
| Type | Description |
|---|---|
bytes | str | NumpyArray1D
|
Source code in src/msl/equipment/interfaces/message_based.py
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | |
reset_device
¤
reset_device() -> None
Perform a USB port reset for the device.
If your program has to call this method, the reset will cause the device state to change (e.g., register values may be reset).
Source code in src/msl/equipment/interfaces/usb.py
625 626 627 628 629 630 631 632 | |
write
¤
write(
message: bytes | str,
*,
data: Sequence1D | None = None,
dtype: MessageDataType = "<f",
fmt: MessageFormat = "ieee"
) -> int
Write a message to the equipment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
bytes | str
|
The message to write to the equipment. |
required |
data
|
Sequence1D | None
|
The data to append to |
None
|
dtype
|
MessageDataType
|
The data type to use to convert each element in |
'<f'
|
fmt
|
MessageFormat
|
The format to use to convert |
'ieee'
|
Returns:
| Type | Description |
|---|---|
int
|
The number of bytes written. |
Source code in src/msl/equipment/interfaces/message_based.py
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | |