V2-202509

This commit is contained in:
tang1219
2026-06-12 16:54:32 +08:00
commit a821392ee4
121 changed files with 11161 additions and 0 deletions
+377
View File
@@ -0,0 +1,377 @@
#include <libudev.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <locale.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <ctype.h>
#define DEFAULT_POLL_INTERVAL 5 // 默认轮询间隔为5秒
#define MAX_RETRY_ATTEMPTS 3 // 最大重试次数
#define RETRY_DELAY 1 // 重试延迟(秒)
FILE *log_file = NULL; // 日志文件指针
// 函数提前声明
int write_file_content_with_retry(const char *file_path, int value);
void sigint_handler(int sig);
int is_touchscreen(struct udev_device *dev);
int read_file_content_with_retry(const char *file_path);
void monitor_usb_devices(const char *control_file_path, int poll_interval);
void print_usage(const char *program_name);
volatile sig_atomic_t keep_running = 1;
void sigint_handler(int sig) {
keep_running = 0;
}
// 日志函数
void log_message(const char *format, ...) {
va_list args;
va_start(args, format);
// 获取当前时间
time_t now = time(NULL);
struct tm *tm_info = localtime(&now);
char time_str[20];
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm_info);
// 输出到控制台
printf("[%s] usb_ds \t", time_str);
vprintf(format, args);
// 输出到文件
if (log_file) {
fprintf(log_file, "[%s] usb_ds \t", time_str);
vfprintf(log_file, format, args);
fflush(log_file); // 确保立即写入文件
}
va_end(args);
}
// 检查设备是否为触摸屏(简化版)
int is_touchscreen(struct udev_device *dev) {
const char *name = udev_device_get_property_value(dev, "NAME");
const char *id_input_touchscreen = udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN");
// 检查ID_INPUT_TOUCHSCREEN属性
if (id_input_touchscreen != NULL && strcmp(id_input_touchscreen, "1") == 0) {
return 1;
}
// 检查设备名称中是否包含"touch"相关关键词(不区分大小写)
if (name != NULL) {
// 转换为小写以进行不区分大小写的比较
char lower_name[256];
strncpy(lower_name, name, sizeof(lower_name) - 1);
lower_name[sizeof(lower_name) - 1] = '\0';
for (int i = 0; lower_name[i]; i++) {
lower_name[i] = tolower(lower_name[i]);
}
if (strstr(lower_name, "touchscreen") != NULL ||
strstr(lower_name, "touch") != NULL ||
strstr(lower_name, "tablet") != NULL) {
return 1;
}
}
return 0;
}
// 读取文件内容(带重试机制)
int read_file_content_with_retry(const char *file_path) {
int attempts = 0;
int content = -1;
while (attempts < MAX_RETRY_ATTEMPTS && keep_running) {
FILE *file = fopen(file_path, "r");
if (file == NULL) {
if (errno == ENOENT) {
// 文件不存在,创建并初始化为0
printf("控制文件不存在,创建文件并初始化为0\n");
if (write_file_content_with_retry(file_path, 0) == 0) {
content = 0;
break;
}
} else {
perror("打开文件失败");
}
} else {
if (fscanf(file, "%d", &content) == 1) {
fclose(file);
break;
} else {
fclose(file);
fprintf(stderr, "读取文件内容失败\n");
}
}
attempts++;
if (attempts < MAX_RETRY_ATTEMPTS) {
printf("重试读取文件(%d/%d)...\n", attempts, MAX_RETRY_ATTEMPTS);
sleep(RETRY_DELAY);
}
}
if (attempts >= MAX_RETRY_ATTEMPTS) {
fprintf(stderr, "达到最大重试次数,放弃读取文件\n");
}
return content;
}
// 写入文件内容(带重试机制)
int write_file_content_with_retry(const char *file_path, int value) {
int attempts = 0;
int success = -1;
while (attempts < MAX_RETRY_ATTEMPTS && keep_running) {
FILE *file = fopen(file_path, "w");
if (file == NULL) {
perror("打开文件失败");
} else {
if (fprintf(file, "%d", value) > 0) {
success = 0;
fclose(file);
break;
} else {
fclose(file);
fprintf(stderr, "写入文件内容失败\n");
}
}
attempts++;
if (attempts < MAX_RETRY_ATTEMPTS) {
printf("重试写入文件(%d/%d)...\n", attempts, MAX_RETRY_ATTEMPTS);
sleep(RETRY_DELAY);
}
}
if (attempts >= MAX_RETRY_ATTEMPTS) {
fprintf(stderr, "达到最大重试次数,放弃写入文件\n");
}
return success;
}
// 监控USB设备事件
void monitor_usb_devices(const char *control_file_path, int poll_interval) {
struct udev *udev;
struct udev_monitor *mon;
struct udev_device *dev;
int fd;
int use_control_file = 0;
// 检查是否使用控制文件
if (control_file_path != NULL) {
use_control_file = 1;
log_message("使用控制文件: %s\n", control_file_path);
// 初始化控制文件(如果不存在)
if (access(control_file_path, F_OK) != 0) {
printf("控制文件不存在,创建并初始化为0\n");
if (write_file_content_with_retry(control_file_path, 0) != 0) {
fprintf(stderr, "无法创建控制文件,禁用控制文件功能\n");
use_control_file = 0;
}
}
}
// 创建udev对象
udev = udev_new();
if (!udev) {
// fprintf(stderr, "无法创建udev对象\n");
exit(EXIT_FAILURE);
}
// 创建监控对象,监控USB设备
mon = udev_monitor_new_from_netlink(udev, "udev");
udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", NULL);
udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL);
udev_monitor_enable_receiving(mon);
// 获取监控文件描述符
fd = udev_monitor_get_fd(mon);
printf("开始监控USB设备...\n");
printf("轮询间隔: %d秒\n", poll_interval);
printf("按Ctrl+C退出\n\n");
// 主循环,监控设备事件
while (keep_running) {
fd_set fds;
struct timeval tv;
int ret;
int file_status = 0;
int touchscreen_detected = 0;
// 如果使用控制文件,在每轮查询开始前检查文件状态
if (use_control_file) {
file_status = read_file_content_with_retry(control_file_path);
if (file_status == -1) {
// 读取文件失败,继续监控但不处理事件
log_message("读取控制文件失败,继续监控但不处理事件\n");
sleep(poll_interval);
continue;
}
if (file_status != 0) {
// 文件状态不为0,不处理事件
printf("控制文件状态为%d,不处理事件\n", file_status);
sleep(poll_interval);
continue;
}
}
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = poll_interval;
tv.tv_usec = 0;
ret = select(fd+1, &fds, NULL, NULL, &tv);
if (ret > 0 && FD_ISSET(fd, &fds)) {
// 获取设备
dev = udev_monitor_receive_device(mon);
if (dev) {
const char *action = udev_device_get_action(dev);
const char *devpath = udev_device_get_devpath(dev);
const char *product = udev_device_get_property_value(dev, "ID_MODEL");
const char *vendor = udev_device_get_property_value(dev, "ID_VENDOR");
// 只处理添加设备的事件
if (action && strcmp(action, "add") == 0) {
log_message("检测到新设备:\n");
log_message(" 设备路径: %s, %s:%s\n", devpath, vendor ? vendor : "未知",product ? product : "未知");
// 检查是否为指针设备
const char *id_input_mouse = udev_device_get_property_value(dev, "ID_INPUT_MOUSE");
const char *id_input_touchpad = udev_device_get_property_value(dev, "ID_INPUT_TOUCHPAD");
const char *id_input_joystick = udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
const char *id_input_touchscreen = udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN");
if (id_input_mouse != NULL || id_input_touchpad != NULL || id_input_joystick != NULL || id_input_touchscreen != NULL) {
printf(" 类型: 指针设备\n");
// 检查是否为触摸屏
if (is_touchscreen(dev)) {
printf(" 子类型: 触摸屏\n");
touchscreen_detected = 1;
}
}
// printf("\n");
}
udev_device_unref(dev);
}
} else if (ret == 0) {
// 超时,没有事件发生
if (use_control_file) {
// 检查控制文件状态
int current_status = read_file_content_with_retry(control_file_path);
if (current_status == -1) {
printf("读取控制文件失败\n");
} else if (current_status != file_status) {
printf("控制文件状态已从%d变为%d\n", file_status, current_status);
}
}
}
// 一轮检测完成后,如果需要更新控制文件状态
if (use_control_file && touchscreen_detected) {
if (write_file_content_with_retry(control_file_path, 1) == 0) {
log_message("已更新控制文件状态为1\n");
// 等待文件状态恢复为0
printf("等待控制文件状态恢复为0...\n");
while (keep_running) {
int current_status = read_file_content_with_retry(control_file_path);
if (current_status == 0) {
printf("控制文件状态已恢复为0,继续监控\n");
break;
} else if (current_status == -1) {
printf("读取控制文件失败,等待%d秒后重试\n", poll_interval);
sleep(poll_interval);
} else {
printf("当前控制文件状态: %d,等待%d秒后检查\n", current_status, poll_interval);
sleep(poll_interval);
}
}
} else {
log_message("更新控制文件状态失败\n");
}
}
}
// 清理资源
udev_monitor_unref(mon);
udev_unref(udev);
}
void print_usage(const char *program_name) {
printf("用法: %s [控制文件路径] [轮询间隔(秒)]\n", program_name);
printf("选项:\n");
printf(" 控制文件路径: 用于控制监控的文件路径(如/tmp/usb_monitor.ctl)\n");
printf(" 轮询间隔: 检查间隔时间(秒),默认%d秒\n", DEFAULT_POLL_INTERVAL);
printf("示例:\n");
printf(" %s /tmp/usb_monitor.ctl 5\n", program_name);
printf(" %s\n", program_name);
}
int main(int argc, char *argv[]) {
setlocale(LC_ALL, "");
const char *control_file_path = NULL;
int poll_interval = DEFAULT_POLL_INTERVAL;
// 解析命令行参数
if (argc > 1) {
if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
print_usage(argv[0]);
return EXIT_SUCCESS;
}
control_file_path = argv[1];
}
if (argc > 2) {
poll_interval = atoi(argv[2]);
if (poll_interval <= 0) {
fprintf(stderr, "轮询间隔必须大于0\n");
return EXIT_FAILURE;
}
}
log_file = fopen("/opt/ktouch/sub_modules.log", "a");
if (!log_file) {
printf("无法打开日志文件,将只输出到控制台\n");
}
log_message("USB触摸屏设备检测程序\n");
printf("=====================\n");
// 设置信号处理
signal(SIGINT, sigint_handler);
signal(SIGTERM, sigint_handler);
// 启动监控
monitor_usb_devices(control_file_path, poll_interval);
log_message("程序已退出\n");
return EXIT_SUCCESS;
}