在 Ubuntu 20.04 上使用 Python3 从 FTDI D2XX 设备读取
Reading from FTDI D2XX device using Python3 on Ubuntu 20.04
我正在使用 FTDI 设备,该设备具有适用于 Windows 的本机软件,但没有适用于 Linux 的软件。我正在尝试使用 pylibftdi
从设备读取数据。我想翻译设备制造商提供的 C# code
,据称可以工作(不清楚是否属实),但没有成功。到目前为止,我已经完成了以下工作:
基于这些 instructions 安装了 Linux D2XX 驱动程序。安装成功。
-
将 FTDI 设备插入 Linux 系统 USB 端口后:
$ lsusb
Bus 006 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 046d:c52b Logitech, Inc. Unifying Receiver
Bus 001 Device 002: ID 04f2:0833 Chicony Electronics Co., Ltd KU-0833 Keyboard
**Bus 001 Device 006: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC**
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
粗体设备 (Bus 001 Device 006: ID 0403:6001
) 是我想要阅读的设备。
- 然后安装
pylibftdi
并验证设备可通过 pylibftdi
API: 读取
$ python3
Python 3.9.5 (default, Jun 4 2021, 12:28:51)
[GCC 7.5.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys, pylibftdi as ftdi
>>> print(ftdi.Driver().list_devices())
[('FTDI', 'Cognionics Quick-20 20CH 1706Q20N', 'AI2SUN90')]
- 很明显,设备已连接并被识别。但是,当我尝试从设备读取时,我收到空数组:
>>> d = ftdi.Device()
>>> vars(d)
{'_opened': True, 'driver': <pylibftdi.driver.Driver object at 0x7fd819320910>, 'fdll': <CDLL 'libftdi.so.1', handle 557bc3ca6560 at 0x7fd8190aee80>, 'device_id': None, 'mode': 'b', 'encoding': 'latin1', 'encoder': <encodings.latin_1.IncrementalEncoder object at 0x7fd819320a60>, 'decoder': <encodings.latin_1.IncrementalDecoder object at 0x7fd8190aefd0>, '_baudrate': 9600, 'interface_select': None, 'device_index': 0, 'list_index': None, 'ctx': <ctypes.c_char_Array_1024 object at 0x7fd819342c40>}
>>> d.read(100)
b''
>>> d.read(100)
b''
>>> d.read(100)
b''
- 这个
C#
code(由制造商提供)据称有效,但我无法对其进行测试。看起来最简单的方法是将其转换为 python
但即使这样也具有挑战性,因为我不知道如何复制正在使用的常量和 ftdi
函数调用。提供的 C#
代码是:
UInt32 ftDevCount = 0;
ftStatus = ftDev.GetNumberOfDevices(ref ftDevCount);
ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftDevCount];
ftStatus = ftDev.GetDeviceList(ftdiDeviceList);
String[] deviceNames = new String[ftDevCount];
for (int c = 0; c < ftDevCount; c++)
{
deviceNames[c] = ftdiDeviceList[c].Description.ToString();
}
Connecting to a device and configuring the serial port settings
if (ftDev.OpenBySerialNumber(ftdiDeviceList[devID].SerialNumber) == FTDI.FT_STATUS.FT_OK)
{ ftDev.SetFlowControl(FTDI.FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11, 0x13);
ftDev.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
ftDev.SetLatency(2);
ftDev.SetBaudRate((uint)3000000);
connectedName = ftdiDeviceList[devID].Description.ToString();
return true;
}
else
{
return false; //failed to open!
}
public byte ReadByte()
{
UInt32 bytesRead = 0;
byte[] t_data = new byte[1];
ftDev.Read(t_data, 1, ref bytesRead);
return t_data[0];
}
public void WriteByte(byte dat)
{
UInt32 bytesWritten = 0;
byte[] data = new byte[1];
data[0] = dat;
ftDev.Write(data, 1, ref bytesWritten);
}
//wait for sync byte 0xFF
while (byteInterface.ReadByte() != 255) {};
//read packet counter
int packetCount = byteInterface.ReadByte();
//read the 20 EEG channels
int NumEEG = 20;
for (int c = 0; c < NumEEG; c++)
{
msb = byteInterface.ReadByte();
lsb2 = byteInterface.ReadByte();
lsb1 = byteInterface.ReadByte();
int tempEEG = (msb << 24) | (lsb2 << 17) | (lsb1 << 10);
}
int NumACC = 3;
//read the 3 ACC channels
for (int c = 0; c < NumACC; c++)
{
msb = byteInterface.ReadByte();
lsb2 = byteInterface.ReadByte();
lsb1 = byteInterface.ReadByte();
int tempACC = (msb << 24) | (lsb2 << 17) | (lsb1 << 10);
}
//read packet tail
int impStatus = byteInterface.ReadByte();
//read battery voltage
int batteryByte = byteInterface.ReadByte();
//read trigger
int trigger = (byteInterface.ReadByte()<<8) + byteInterface.ReadByte();
- 根据
pylibftdi
github 存储库中的文档,我可以找到一些包装器 function calls as well as a few constants,但我不知道如何只打开设置片段,例如:
ftDev.SetFlowControl(FTDI.FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11, 0x13);
ftDev.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
ftDev.SetLatency(2);
ftDev.SetBaudRate((uint)3000000);
进入 python
中的内容。我想我可以使用 d.baudrate = 3000000
重置波特率,我可以使用 d.ftdi_fn.ftdi_set_latency_timer(2)
更改延迟计时器,但我不知道如何设置数据特性,常量的含义(FTDI.FT_DATA_BITS.FT_BITS_8
,等),以及如何设置与 C#
代码相同的流量控制。
- 其他 SO 帖子也提到了找到的 D2XX 程序员指南 here 但没有找到将其应用于此问题的方法
如有任何建议,我们将不胜感激。
作为对评论的回应和后续答复:
我无法根据个人经验证实 D2XX 比 VCP 更可靠的说法,而第二种说法只是部分正确:例如,可以在大多数情况下使用 VID:PID 组合 IIRC.
我强烈建议坚持使用更简单的 VCP + pyserial 解决方案。但是如果你真的想(或需要)使用pylibftdi,你可以看看https://github.com/codedstructure/pylibftdi/blob/4662ebe069eefd5a89709d4165e3be808cad636c/docs/advanced_usage.rst - it describes how to access none exposed functionality directly. The naming is slightly different e.g. ftdi_setflowctrl instead of SetFlowControl but you will figure it out. Just check https://www.intra2net.com/en/developer/libftdi/documentation/ftdi_8c.html .
我正在使用 FTDI 设备,该设备具有适用于 Windows 的本机软件,但没有适用于 Linux 的软件。我正在尝试使用 pylibftdi
从设备读取数据。我想翻译设备制造商提供的 C# code
,据称可以工作(不清楚是否属实),但没有成功。到目前为止,我已经完成了以下工作:
基于这些 instructions 安装了 Linux D2XX 驱动程序。安装成功。
将 FTDI 设备插入 Linux 系统 USB 端口后:
$ lsusb
Bus 006 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 046d:c52b Logitech, Inc. Unifying Receiver
Bus 001 Device 002: ID 04f2:0833 Chicony Electronics Co., Ltd KU-0833 Keyboard
**Bus 001 Device 006: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC**
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
粗体设备 (Bus 001 Device 006: ID 0403:6001
) 是我想要阅读的设备。
- 然后安装
pylibftdi
并验证设备可通过pylibftdi
API: 读取
$ python3
Python 3.9.5 (default, Jun 4 2021, 12:28:51)
[GCC 7.5.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys, pylibftdi as ftdi
>>> print(ftdi.Driver().list_devices())
[('FTDI', 'Cognionics Quick-20 20CH 1706Q20N', 'AI2SUN90')]
- 很明显,设备已连接并被识别。但是,当我尝试从设备读取时,我收到空数组:
>>> d = ftdi.Device()
>>> vars(d)
{'_opened': True, 'driver': <pylibftdi.driver.Driver object at 0x7fd819320910>, 'fdll': <CDLL 'libftdi.so.1', handle 557bc3ca6560 at 0x7fd8190aee80>, 'device_id': None, 'mode': 'b', 'encoding': 'latin1', 'encoder': <encodings.latin_1.IncrementalEncoder object at 0x7fd819320a60>, 'decoder': <encodings.latin_1.IncrementalDecoder object at 0x7fd8190aefd0>, '_baudrate': 9600, 'interface_select': None, 'device_index': 0, 'list_index': None, 'ctx': <ctypes.c_char_Array_1024 object at 0x7fd819342c40>}
>>> d.read(100)
b''
>>> d.read(100)
b''
>>> d.read(100)
b''
- 这个
C#
code(由制造商提供)据称有效,但我无法对其进行测试。看起来最简单的方法是将其转换为python
但即使这样也具有挑战性,因为我不知道如何复制正在使用的常量和ftdi
函数调用。提供的C#
代码是:
UInt32 ftDevCount = 0;
ftStatus = ftDev.GetNumberOfDevices(ref ftDevCount);
ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftDevCount];
ftStatus = ftDev.GetDeviceList(ftdiDeviceList);
String[] deviceNames = new String[ftDevCount];
for (int c = 0; c < ftDevCount; c++)
{
deviceNames[c] = ftdiDeviceList[c].Description.ToString();
}
Connecting to a device and configuring the serial port settings
if (ftDev.OpenBySerialNumber(ftdiDeviceList[devID].SerialNumber) == FTDI.FT_STATUS.FT_OK)
{ ftDev.SetFlowControl(FTDI.FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11, 0x13);
ftDev.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
ftDev.SetLatency(2);
ftDev.SetBaudRate((uint)3000000);
connectedName = ftdiDeviceList[devID].Description.ToString();
return true;
}
else
{
return false; //failed to open!
}
public byte ReadByte()
{
UInt32 bytesRead = 0;
byte[] t_data = new byte[1];
ftDev.Read(t_data, 1, ref bytesRead);
return t_data[0];
}
public void WriteByte(byte dat)
{
UInt32 bytesWritten = 0;
byte[] data = new byte[1];
data[0] = dat;
ftDev.Write(data, 1, ref bytesWritten);
}
//wait for sync byte 0xFF
while (byteInterface.ReadByte() != 255) {};
//read packet counter
int packetCount = byteInterface.ReadByte();
//read the 20 EEG channels
int NumEEG = 20;
for (int c = 0; c < NumEEG; c++)
{
msb = byteInterface.ReadByte();
lsb2 = byteInterface.ReadByte();
lsb1 = byteInterface.ReadByte();
int tempEEG = (msb << 24) | (lsb2 << 17) | (lsb1 << 10);
}
int NumACC = 3;
//read the 3 ACC channels
for (int c = 0; c < NumACC; c++)
{
msb = byteInterface.ReadByte();
lsb2 = byteInterface.ReadByte();
lsb1 = byteInterface.ReadByte();
int tempACC = (msb << 24) | (lsb2 << 17) | (lsb1 << 10);
}
//read packet tail
int impStatus = byteInterface.ReadByte();
//read battery voltage
int batteryByte = byteInterface.ReadByte();
//read trigger
int trigger = (byteInterface.ReadByte()<<8) + byteInterface.ReadByte();
- 根据
pylibftdi
github 存储库中的文档,我可以找到一些包装器 function calls as well as a few constants,但我不知道如何只打开设置片段,例如:
ftDev.SetFlowControl(FTDI.FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11, 0x13);
ftDev.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
ftDev.SetLatency(2);
ftDev.SetBaudRate((uint)3000000);
进入 python
中的内容。我想我可以使用 d.baudrate = 3000000
重置波特率,我可以使用 d.ftdi_fn.ftdi_set_latency_timer(2)
更改延迟计时器,但我不知道如何设置数据特性,常量的含义(FTDI.FT_DATA_BITS.FT_BITS_8
,等),以及如何设置与 C#
代码相同的流量控制。
- 其他 SO 帖子也提到了找到的 D2XX 程序员指南 here 但没有找到将其应用于此问题的方法
如有任何建议,我们将不胜感激。
作为对评论的回应和后续答复:
我无法根据个人经验证实 D2XX 比 VCP 更可靠的说法,而第二种说法只是部分正确:例如,可以在大多数情况下使用 VID:PID 组合 IIRC.
我强烈建议坚持使用更简单的 VCP + pyserial 解决方案。但是如果你真的想(或需要)使用pylibftdi,你可以看看https://github.com/codedstructure/pylibftdi/blob/4662ebe069eefd5a89709d4165e3be808cad636c/docs/advanced_usage.rst - it describes how to access none exposed functionality directly. The naming is slightly different e.g. ftdi_setflowctrl instead of SetFlowControl but you will figure it out. Just check https://www.intra2net.com/en/developer/libftdi/documentation/ftdi_8c.html .