// main.cpp - 程序入口(模块化重构版) // 模块: config / json_utils / filter / io_utils / lidar_utils / count / detect / tcp_server #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #endif #include "config.h" #include "common.h" #include "io_utils.h" #include "lidar_utils.h" #include "detect.h" #include "tcp_server.h" // ==================== 日志目录清理:启动时 + 每天 log.clean_time ==================== static std::atomic g_cleanup_stop{ false }; static std::mutex g_cleanup_mtx; static std::condition_variable g_cleanup_cv; static std::thread g_cleanup_thread; // 启动清理线程:等下一个 01:00 执行一次清理后循环;等待可被 stop_daily_cleanup() 中断 static void start_daily_cleanup() { clean_expired_log_dirs(); // 启动清理一次 g_cleanup_stop = false; g_cleanup_thread = std::thread([]() { for (;;) { // 清理时刻来自配置(cfg.log.clean_hour/minute/sec),每轮读取:运行期发 config // 命令重载后,下一轮即按新时刻执行 int hour = cfg.log.clean_hour, minute = cfg.log.clean_minute, sec = cfg.log.clean_sec; time_t raw = std::time(nullptr); struct tm* t = std::localtime(&raw); std::tm next = *t; next.tm_hour = hour; next.tm_min = minute; next.tm_sec = sec; time_t next_t = std::mktime(&next); if (next_t <= raw) next_t += 86400; char buf[32]; std::snprintf(buf, sizeof(buf), "%02d:%02d:%02d", hour, minute, sec); std::cout << "[清理] 下次定时清理: 每天 " << buf << " (等待 " << (next_t - raw) / 60 << " 分钟)" << std::endl; // 可中断等待:wait_for 返回 true 表示 stop 标志已置位(程序退出) std::unique_lock lk(g_cleanup_mtx); if (g_cleanup_cv.wait_for(lk, std::chrono::seconds(next_t - raw), [] { return g_cleanup_stop.load(); })) return; // 程序正在退出 lk.unlock(); clean_expired_log_dirs(); } }); } // 主程序退出前调用:唤醒并等待清理线程结束, // 避免进程析构时后台线程仍在访问全局对象/标准输出导致崩溃(原 detach 版的崩退根因) static void stop_daily_cleanup() { g_cleanup_stop = true; g_cleanup_cv.notify_all(); if (g_cleanup_thread.joinable()) g_cleanup_thread.join(); } // ==================== exe 模式:自动做一次截面检测 ==================== // 启动统一后台扫描,采 cfg.scan.collect_duration_s 秒后自动停止,做截面检测并保存到 // data/日期/时间_ 目录(无 task_id)。 static int run_exe_check(pavo2::pavo2_driver& driver) { std::cout << "\n[exe] 自动检测开始: 采集 " << cfg.scan.collect_duration_s << " 秒 ..." << std::endl; ScanSession scan; scan.reset(); if (!scan.start(driver)) { std::cerr << "[错误] 启动扫描会话失败!" << std::endl; return -1; } std::this_thread::sleep_for(std::chrono::seconds(cfg.scan.collect_duration_s)); scan.stop(); std::vector pts = scan.snapshot(); scan.reset(); std::cout << "[exe] 采集结束, 点数=" << pts.size() << std::endl; std::string out_dir = make_task_dir(""); DetectResult res; detect_analyze_slices(pts, out_dir, &res); std::cout << "[exe] 检测完成: "; if (res.valid) { std::cout << "start白色占比=" << res.start_fill_pct << "%, end白色占比=" << res.end_fill_pct << "%"; } else { std::cout << "无有效结果"; } std::cout << ", 输出目录=" << out_dir << std::endl; return 0; } // ==================== 主入口 ==================== int main() { #ifdef _WIN32 WSADATA wsa; if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { std::cerr << "[错误] WSAStartup 失败!" << std::endl; return -1; } #endif load_config(); // 默认读取 ./config/config (JSON) reload_speed_profile(); // cfg.scan.z_speed_type=configuration 时加载 config/speed.txt start_daily_cleanup(); std::cout << "==================== 配置文件内容 ====================" << std::endl; std::cout << "雷达IP: " << cfg.radar.ip << " : " << cfg.radar.port << std::endl; std::cout << "运行模式: " << cfg.server.mode << " (tcp=TCP服务端, http=HTTP服务端, 其他=自动检测)" << std::endl; std::cout << "TCP/HTTP端口: " << cfg.server.port << std::endl; std::cout << "采集时长: " << cfg.scan.collect_duration_s << " 秒" << std::endl; std::cout << "Z轴模式: " << cfg.scan.z_speed_type << " (uniformSpeed=匀速, configuration=config/speed.txt变速)" << std::endl; std::cout << "移动速度: " << cfg.scan.z_speed << " cm/s (0=时间模式, >0=距离模式)" << std::endl; std::cout << "Z范围: " << cfg.detect.z_range_mm << " mm | Y范围: " << cfg.detect.y_range_mm << " mm | 雷达频率: " << cfg.radar.hz << " Hz" << std::endl; std::cout << "z空隙插值模式: " << cfg.count.z_interpolate_mode << std::endl; std::cout << "日志保留天数: " << cfg.log.retain_days << std::endl; std::cout << "======================================================" << std::endl; std::cout << "======================================================" << std::endl; std::cout << " Pavo2 Lidar 雷达数据采集程序 (模块化)" << std::endl; std::cout << "======================================================" << std::endl; pavo2::pavo2_driver driver; if (!connect_lidar(driver)) { stop_daily_cleanup(); // 提前退出也要先停掉后台清理线程 #ifdef _WIN32 WSACleanup(); #endif return -1; } std::cout << "\n[等待] 等待雷达数据稳定(2秒)..." << std::endl; std::this_thread::sleep_for(std::chrono::seconds(2)); int rc = 0; if (cfg.server.mode == "tcp") run_tcp_server(driver); else if (cfg.server.mode == "http") run_http_server(driver); else rc = run_exe_check(driver); stop_daily_cleanup(); // 通知后台清理线程退出并等待结束,防止崩退 std::cout << "\n[关闭] 正在断开雷达连接..." << std::endl; driver.pavo2_close(); #ifdef _WIN32 WSACleanup(); #endif std::cout << "[完成] 程序运行结束。" << std::endl; return rc; }