#ftdi #usb #api-bindings #ft60x

d3xx

Rust 对 FTDI D3XX 库的绑定

2 个版本

0.0.3 2023年11月27日
0.0.2 2023年11月27日
0.0.1 2023年11月25日

#1175硬件支持

每月 36 次下载

MIT 许可证

125KB
2K SLoC

国际未来技术设备公司(FTDI)生产FT60X系列芯片(例如FT601),这些芯片作为超速USB 3.0到FIFO桥。FTDI为这些芯片提供了一款专有驱动程序,称为D3XX,该驱动程序通过其DLL/共享库公开了与设备交互的底层API。

此包提供了FTDI的D3XX库的封装,使其更安全、更符合Rust的风格。

免责声明

此包是非官方的,与FTDI没有任何关联。

该包仍处于早期开发阶段,是不稳定/实验性的。欢迎反馈和贡献!

此包的功能

此包提供了D3XX库的几乎所有功能

  • 设备枚举
  • 读取设备配置
  • 管道I/O
  • GPIO控制
  • 通知
  • 重叠(异步)I/O

此包不提供配置设备的封装功能。如果认为有必要,可以直接调用不安全的FFI函数。然而,建议使用FT60X芯片配置程序来完成此目的。

要求

此包适用于Linux、Windows和macOS。尽管可以不安装它来构建此包,但为了与设备通信,必须在目标平台上安装D3XX驱动程序

构建此包需要安装Clang

背景

USB外设包含一系列编号的端点,这些端点是基本的数据缓冲区。每个端点可能包含一个或两个缓冲区,对应于数据流向的方向(IN或OUT)。D3XX设备有8个端点,每个端点有4个IN和OUT传输。端点的软件表示称为“管道”,它是单向的。

端点收集到“接口”中,这些接口是端点的逻辑分组,用于实现共同的目的。然后,这些接口收集到“配置”中,这些配置代表设备的完整功能集。设备可能有多个配置,但一次只能有一个配置是活动的。D3XX提供了一种与设备通信的方法,主要是通过端点的软件等效物“管道”。

D3XX限制

D3XX API 不提供关于驱动程序行为的许多保证。例如,当在传输过程中拔掉设备时会发生什么,或者任何函数是否线程安全,都没有保证。因为D3XX API的许多方面都没有明确定义或文档化,这个包有意实施额外的限制和假设,以确保其安全性。对该包设计影响最大的两个主要假设是

  1. 驱动程序不是线程安全的。
  2. 任何错误可能在任何时候出于任何原因发生。

由于缺乏明确的标准,不建议在安全关键应用中使用此包。在此类应用中使用此包的风险自负。

错误处理

此包中大多数函数返回的文档 Result<T, D3xxError> 未包含关于错误条件的说明。这是因为大多数情况下,D3XX 文档没有提供任何关于可能发生的错误以及在这些情况下发生的信息。由于没有错误规范,尝试以系统化方式处理特定错误是不明智的,因为错误条件可能会在 D3XX API 的未来版本中更改。相反,建议在大多数情况下使用一种通用的方法。

全局锁

关于线程安全性的假设的一个后果是,一些操作必须在持有驱动程序锁的情况下执行。例如,列出设备必须在持有锁的情况下完成,因为该操作由对驱动程序设备表的写入和读取组成,该表可能在任何时刻被另一个线程无效化。

获取锁的操作通过调用 with_global_lock 透明地执行。如果需要访问绑定,此函数也可供用户使用。在使用此函数时应注意避免死锁。

进一步阅读

建议阅读 D3XX 程序员指南 以获取有关 D3XX API 提供的功能的更多信息。D3XX 程序员指南中缺少的一些信息可以在 D3XX .NET 程序员指南 中找到。

简单示例

use std::io::{Read, Write};
use d3xx::{list_devices, Pipe};

// Scan for connected devices.
let all_devices = list_devices().expect("failed to list devices");

/// Open the first device found.
let device = all_devices[0].open().expect("failed to open device");

// Read 1024 bytes from input pipe 1
let mut buf = vec![0; 1024];
device
    .pipe(Pipe::In1)
    .read(&mut buf)
    .expect("failed to read from pipe");

// Write 1024 bytes to output pipe 2
device
    .pipe(Pipe::Out2)
    .write(&buf)
    .expect("failed to write to pipe");

依赖项

~38MB
~33K SLoC