目录
[1. 获取版本信息](#1. 获取版本信息)
[2. 创建上下文对象](#2. 创建上下文对象)
[3. 查找FTDI设备](#3. 查找FTDI设备)
[4. 获取字符串描述符](#4. 获取字符串描述符)
[5. 指定接口](#5. 指定接口)
[6. 打开设备](#6. 打开设备)
[6.1 指定VID/PID的方式](#6.1 指定VID/PID的方式)
[6.2 指定描述符的方式](#6.2 指定描述符的方式)
[6.3 指定描述符和设备索引的方式](#6.3 指定描述符和设备索引的方式)
[6.4 其他方式](#6.4 其他方式)
[7. 关闭设备](#7. 关闭设备)
libftdi1是一个升级版本的库(旧的版本是libftdi),用于与FTDI芯片进行通信。在Ubuntu系统中可以先安装好ibftdi1库。
bash
sudo apt-get install libftdi1-dev
其他系统可以下载源代码编译安装。
下载一个通用makefile。
bash
####################################################
# Generic makefile - 万能Makefile
# for compiling and linking C++ projects on Linux
# Author: George Foot Modified:Jackie Lee
####################################################
### Customising
#
# Adjust the following if necessary; EXECUTABLE is the target
# executable's filename, and LIBS is a list of libraries to link in
# (e.g. alleg, stdcx, iostr, etc). You can override these on make's
# command line of course, if you prefer to do it that way.
#
#
# 可执行文件名
EXECUTABLE :=
# 静态库目录
LIBDIR:=
# 静态库 文 件 名
LIBS :=
# 头文件目录
INCLUDES:=
# 除了当前目录外,其他的源代码文件目录
SRCDIR:=
#
# # Now alter any implicit rules' variables if you like, e.g.:
CC:=gcc
CPP:=g++
CFLAGS := -g -Wall -O3
CPPFLAGS := $(CFLAGS)
CPPFLAGS += $(addprefix -I,$(INCLUDES))
CPPFLAGS += -MMD
#
# # The next bit checks to see whether rm is in your djgpp bin
# # directory; if not it uses del instead, but this can cause (harmless)
# # `File not found' error messages. If you are not using DOS at all,
# # set the variable to something which will unquestioningly remove
# # files.
#
RM-F := rm -f
# # You shouldn't need to change anything below this point.
#
SRCS_CPP = $(wildcard *.cpp) $(wildcard $(addsuffix /*.cpp, $(SRCDIR)))
SRCS_C := $(wildcard *.c) $(wildcard $(addsuffix /*.c, $(SRCDIR)))
OBJS_C := $(patsubst %.c,%.o,$(SRCS_C))
OBJS_CPP := $(patsubst %.cpp,%.o,$(SRCS_CPP))
DEPS := $(patsubst %.o,%.d,$(OBJS_C)) $(patsubst %.o,%.d,$(OBJS_CPP))
MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))
MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.cpp,$(MISSING_DEPS)))
.PHONY : all deps objs clean veryclean rebuild info
all: $(EXECUTABLE)
deps : $(DEPS)
clean :
@$(RM-F) *.o
@$(RM-F) *.d
veryclean: clean
@$(RM-F) $(EXECUTABLE)
rebuild: veryclean all
ifneq ($(MISSING_DEPS),)
$(MISSING_DEPS) :
@$(RM-F) $(patsubst %.d,%.o,$@)
endif
-include $(DEPS)
$(EXECUTABLE) : $(OBJS_CPP) $(OBJS_C)
$(CC) -o $(EXECUTABLE) $(OBJS_CPP) $(OBJS_C) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS)) -lstdc++
info:
@echo $(SRCS_CPP)
@echo $(SRCS_C)
@echo $(OBJS_CPP)
@echo $(OBJS_C)
@echo $(DEPS)
@echo $(MISSING_DEPS)
@echo $(MISSING_DEPS_SOURCES)
新建一个libftdi1-example的文件夹,然后在该文件夹内创建上面的makefile和main.c。编辑makefile文件:
bash
EXECUTABLE := libftdi1-example
# 静态库目录
LIBDIR:= /usr/lib/x86_64-linux-gnu/
# 静态库 文 件 名
LIBS := ftdi1
下载libftdi1的源代码,找到ftdi.h文件,拷贝到当前文件夹。编辑main.c
cpp
#include <stdio.h>
#include <stdlib.h>
#include "ftdi.h"
int main(void)
{
return -1;
}
运行make编译,此时应该可以编译通过。
bash
libftdi-example$ make
gcc -o libftdi1-example main.o -L/usr/lib/x86_64-linux-gnu/ -lftdi1 -lstdc++
1. 获取版本信息
可以通过函数ftdi_get_library_version获取库的版本信息。
cpp
struct ftdi_version_info version;
version = ftdi_get_library_version();
fprintf(stdout, "version:%d.%d.%d, %s\n",
version.major, version.minor, version.micro, version.version_str);
运行结果:
bash
libftdi-example$ ./libftdi1-example
version:1.5.0, 1.5
2. 创建上下文对象
在使用libftdi1的API函数前,需要先创建一个FTDI的上下文对象。
cpp
struct ftdi_context *ftdi_new(void)
使用结束后需要通过ftdi_free释放该对象。
cpp
void ftdi_free(struct ftdi_context *ftdi)
参考例程:
cpp
struct ftdi_context *ftdi;
if ((ftdi = ftdi_new()) == 0)
{
fprintf(stderr, "ftdi_new failed\n");
return EXIT_FAILURE;
}
ftdi_free(ftdi);
3. 查找FTDI设备
查找USB总线上指定VID:PID的所有ftdi设备。注意,使用后需要由ftdi_list_free()释放。
cpp
int ftdi_usb_find_all(struct ftdi_context *ftdi, struct ftdi_device_list **devlist, int vendor, int product)
参数说明:
- ftdi - 上下文对象,即ftdi_new的返回值。
- devlist - 保存找到的设备列表
- vendor, product - 指定设备的VID和PID,如果为0则表示查找所有的FTDI设备。
返回值表示找到的设备数。
参考例程:
cpp
struct ftdi_device_list *devlist;
int devnum = 0;
if ((devnum = ftdi_usb_find_all(ftdi, &devlist, 0, 0)) < 0)
{
fprintf(stderr, "ftdi_usb_find_all failed: %d (%s)\n", ftdi_get_error_string(ftdi));
ftdi_free(ftdi);
return EXIT_FAILURE;
}
ftdi_list_free(&devlist);
4. 获取字符串描述符
获取设备的制造商、产品描述和序列号。
cpp
int ftdi_usb_get_strings(struct ftdi_context *ftdi,
struct libusb_device *dev,
char *manufacturer, int mnf_len,
char *description, int desc_len,
char *serial, int serial_len)
- ftdi - 上下文对象,即ftdi_new的返回值。
- dev - USB设备对象
- manufacturer/mnf_len - 制造商字符串缓存及长度
- description/desc_len - 产品字符串缓存及长度
- serial/serial_len - 序列号缓存及长度
注意,这个函数必须放在ftdi_usb_find_all后执行,因为使用后关闭了内部"usb_dev"。
如果manufacturer、description和serial设置为NULL则表示不读取该字符串。
参考例程:
bash
struct ftdi_device_list *curdev;
char manufacturer[128], description[128], serial[128];
int i;
printf("Number of FTDI devices found: %d\n", devnum);
curdev = devlist;
for(i = 0; i < devnum; i++)
{
if (ftdi_usb_get_strings(ftdi, curdev->dev, manufacturer, 128, description, 128, serial, 128) < 0)
{
fprintf(stderr, "ftdi_usb_get_strings failed: (%s)\n", ftdi_get_error_string(ftdi));
ftdi_list_free(&devlist);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
printf("Manufacturer: %s, Description: %s, Serial: %s\n\n", manufacturer, description, serial);
curdev = curdev->next;
}
注意,运行这个例程时需要管理员权限(sudo ./libftd1i-example),否则会报
bash
ftdi_usb_get_strings failed: (libusb_open() failed)
运行结果:
bash
libftdi-example$ sudo ./libftdi1-example
version:1.5.0, 1.5
Number of FTDI devices found: 1
Manufacturer: FTDI, Description: FT4232H MiniModule, Serial: FT8NZV77
5. 指定接口
对于多接口的设备(例如FT2232H/FT4232H),可以指定不同的接口(例如FT2232H支持2路接口,而FT4232H支持4路)。
cpp
int ftdi_set_interface(struct ftdi_context *ftdi, enum ftdi_interface interface)
参数说明:
- ftdi - 上下文对象,即ftdi_new的返回值。
- interface - 指定的接口。INTERFACE_ANY表示第一个
cpp
enum ftdi_interface
{
INTERFACE_ANY = 0,
INTERFACE_A = 1,
INTERFACE_B = 2,
INTERFACE_C = 3,
INTERFACE_D = 4
};
返回值说明:
- 0 - 指定成功
- -1 - 指定的接口不支持
- -2 - 无效的USB设备
- -3 - 设备已经打开,不能再指定接口
参考例程:
cpp
ftdi_set_interface(ftdi, INTERFACE_A);
6. 打开设备
6.1 指定VID/PID的方式
cpp
int ftdi_usb_open(struct ftdi_context *ftdi, int vendor, int product)
该函数实际上是调用ftdi_usb_open_desc,其中字符串描述符参数部分为NULL
6.2 指定描述符的方式
cpp
int ftdi_usb_open_desc(struct ftdi_context *ftdi, int vendor, int product,
const char* description, const char* serial)
该函数实际上是调用ftdi_usb_open_desc_index,其中设备索引参数部分为0
6.3 指定描述符和设备索引的方式
cpp
int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product,
const char* description, const char* serial, unsigned int index)
参数说明:
- 其他略
- index - 设备索引值,一般为0,当有多个相同设备(PID、VID、描述符都相同)时才有意义。
注意参数vendor和product必须指定,不能设置为0。
返回值说明:
- 0 - 打开设备成功
- -1 - 调用底层usb_find_busses()失败
- -2 - 调用底层usb_find_devices()失败
- -3 - 没找到对应设备
- -4 - 打开设备失败
- -5 - 无法声明设备
- -6 - 复位失败
- -7 - 设置波特率失败
- -8 - 获取产品描述符失败
- -9 - 获取序列号失败
- -10 - 无法关闭设备
- -11 - ftdi上下文对象无效
- -12 - 调用底层libusb_get_device_list()失败
参考例程:
cpp
int ret;
ret = ftdi_usb_open_desc_index(ftdi, 0x0403, 0x6011, NULL, NULL, 0);
if(ret < 0)
{
printf("Open device Fail: %d\n", ret);
ftdi_list_free(&devlist);
ftdi_free(ftdi);
return EXIT_FAILURE;
}
printf("Open device OK: %d\n", ret);
ftdi_usb_close(ftdi);
运行结果:
cpp
libftdi-example$ sudo ./libftdi1-example
version:1.5.0, 1.5
Number of FTDI devices found: 1
Manufacturer: FTDI, Description: FT4232H MiniModule, Serial: FT8NZV77
Open device OK: 0
6.4 其他方式
略过,包括ftdi_usb_open_bus_addr、ftdi_usb_open_string、ftdi_usb_open_dev
7. 关闭设备
cpp
int ftdi_usb_close(struct ftdi_context *ftdi)
在ftdi_free前要关闭设备。