问题描述:
在增加icm20608的驱动程序后,iio子系统中不只有ap3216c一个iio设备,(之前是直接通过绝对路径的iio:device0这个路径进行索引),这时候需要更改应用程序来扫描iio设备文件夹下的所有iio设备的name来进行路径匹配。
基本思路就是在iio驱动设备的路径中挨个进入,匹配name是不是设置好的“ap3216c”,为了提高效率,需要跳过“.”和“..”目录。程序如下:
bool find_ap3216c_device() {
const char *base_path = "/sys/bus/iio/devices/";
DIR *dir = opendir(base_path);
if (dir == NULL) {
printf("Cannot open directory: %s\n", base_path);
return false;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
// 调试输出 d_type 的值
printf("Entry: %s, d_type: %d\n", entry->d_name, entry->d_type);
// 检查 d_type 是否为目录
if (entry->d_type == DT_DIR && strncmp(entry->d_name, "iio:device", 10) == 0) {
printf("Found iio:device directory: %s\n", entry->d_name);
// 构建name文件的路径
char name_file[256];
snprintf(name_file, sizeof(name_file), "%s%s/name", base_path, entry->d_name);
char name[50];
if (file_data_read(name_file, name, sizeof(name)) == 0) {
printf("Device found: %s\n", name); // 输出调试信息
if (strcmp(name, "ap3216c") == 0) {
// 找到设备,保存路径
snprintf(device_path, sizeof(device_path), "%s%s/", base_path, entry->d_name);
closedir(dir);
return true;
} else {
printf("name error: %s\n", name); // 打印不匹配的设备名
}
} else {
printf("name read error for %s!\n", name_file);
}
} else {
printf("Skipping non-directory or non-iio:device entry: %s\n", entry->d_name);
}
}
closedir(dir);
return false;
}
在匹配name的过程中,由于目标目录没有被成功识别为目录,导致一直无法进入构建name文件路径那一步,随后增加调试输出,在检查d_type是否正确前将d_type输出查看。
Entry: ., d_type: 4 Skipping non-directory or non-iio:device entry: . Entry: .., d_type: 4 Skipping non-directory or non-iio:device entry: .. Entry: iio:device0, d_type: 10 Skipping non-directory or non-iio:device entry: iio:device0 AP3216C device not found!
发现目标文件夹的类型为10,是符号链接 (DT_LNK),并不是我们设置的DT_DIR,导致原代码未能正确识别。
符号链接就类似于一个指针,它指向系统中的其他文件或目录。
问题解决:
解决就很简单了,可以使用stat函数来判断符号链接的指向是否为一个目录类型。
通过 stat 函数,可以获取文件或目录的元数据信息,包括文件的类型、大小、权限等。通过S_ISDIR(st.st_mode)这个宏,来判断 st_mode 字段中的文件类型信息是否表示目录。如果 stat 成功且目标是目录,S_ISDIR 将返回 true。另外无论是符号链接还是普通目录,stat 函数都可以用于判断文件或目录的类型,也就意味着如果目标文件是正常的目录stat函数也可以获得正确的结果。
正确代码:
bool find_ap3216c_device() {
const char *base_path = "/sys/bus/iio/devices/";
DIR *dir = opendir(base_path);
if (dir == NULL) {
printf("Cannot open directory: %s\n", base_path);
return false;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
// 调试输出 d_type 的值
printf("Entry: %s, d_type: %d\n", entry->d_name, entry->d_type);
// 检查 d_type 是否为目录
if (entry->d_type == DT_DIR && strncmp(entry->d_name, "iio:device", 10) == 0) {
printf("Found iio:device directory: %s\n", entry->d_name);
// 构建name文件的路径
char name_file[256];
snprintf(name_file, sizeof(name_file), "%s%s/name", base_path, entry->d_name);
char name[50];
if (file_data_read(name_file, name, sizeof(name)) == 0) {
printf("Device found: %s\n", name); // 输出调试信息
if (strcmp(name, "ap3216c") == 0) {
// 找到设备,保存路径
snprintf(device_path, sizeof(device_path), "%s%s/", base_path, entry->d_name);
closedir(dir);
return true;
} else {
printf("name error: %s\n", name); // 打印不匹配的设备名
}
} else {
printf("name read error for %s!\n", name_file);
}
} else {
printf("Skipping non-directory or non-iio:device entry: %s\n", entry->d_name);
}
}
closedir(dir);
return false;
}
更改后,应用就可以快速的匹配iio驱动,并跳过“.”和“..”目录:
Skipping non-directory or non-iio:device entry: .
Skipping non-directory or non-iio:device entry: ..
Device found: ap3216c