#include "serial_AT.hpp" #include #include #include #include #include #include #include "httplib.h" #include "logger.hpp" #include "nlohmann/json.hpp" #include "serial_port.h" // ================== 全局 IMEI ================== std::string IMEI; std::mutex imei_mutex; // ================== 运行控制 ================== static std::atomic serial_at_running{false}; // ================== AT 任务结构 ================== struct AtTask { std::string cmd; int max_retries; int sent_count; std::chrono::steady_clock::time_point last_sent; }; static std::unique_ptr serial_at; static std::thread serial_at_sender; static std::mutex at_tasks_mutex; static std::unique_ptr http_server; static std::thread http_thread; static bool is_imei_ready() { std::lock_guard lock(imei_mutex); return !IMEI.empty(); } static std::string get_imei() { std::lock_guard lock(imei_mutex); return IMEI; } void start_http_server(int port) { http_server = std::make_unique(); http_server->Post("/api/v1/device/register", [](const httplib::Request& req, httplib::Response& res) { LOG_INFO("[http] /device/register called"); // 解析 A 的信息(可选,先简单点) LOG_INFO("[http] payload: " + req.body); if (!is_imei_ready()) { res.status = 503; res.set_content(R"({"ok":false,"error":"imei_not_ready"})", "application/json"); return; } std::string imei = get_imei(); nlohmann::json j; j["ok"] = true; j["server"] = {{"device_type", "tbox"}, {"imei", imei}, {"fw", "b-v2.1.0"}}; res.set_content(j.dump(-1), "application/json"); }); http_thread = std::thread( [port]() { LOG_INFO("[http] Server listening on port " + std::to_string(port)); http_server->listen("0.0.0.0", port); }); } void stop_http_server() { if (http_server) { http_server->stop(); } if (http_thread.joinable()) { http_thread.join(); } http_server.reset(); } // 只保留一个任务:AT+GSN static std::vector at_tasks = {{"AT+GSN", 3, 0, {}}}; // ================== 发送线程 ================== static void serial_at_send_loop() { LOG_INFO("[serial_at] Sender thread started"); while (serial_at_running.load(std::memory_order_relaxed)) { if (!serial_at || !serial_at->is_open()) { std::this_thread::sleep_for(std::chrono::seconds(1)); continue; } auto now = std::chrono::steady_clock::now(); { std::lock_guard lock(at_tasks_mutex); for (auto it = at_tasks.begin(); it != at_tasks.end();) { auto& task = *it; if (task.sent_count >= task.max_retries) { it = at_tasks.erase(it); continue; } if (task.last_sent.time_since_epoch().count() == 0 || std::chrono::duration_cast(now - task.last_sent).count() >= 5) { serial_at->send_data(task.cmd + "\r\n"); task.sent_count++; task.last_sent = now; } ++it; } } std::this_thread::sleep_for(std::chrono::seconds(1)); } LOG_INFO("[serial_at] Sender thread exiting"); } // ================== 接收处理 ================== static void handle_serial_at_data(const std::string& data) { std::istringstream iss(data); std::string line; while (std::getline(iss, line)) { // trim line.erase(0, line.find_first_not_of(" \t\r\n")); line.erase(line.find_last_not_of(" \t\r\n") + 1); // IMEI:14~17 位纯数字 if (line.size() >= 14 && line.size() <= 17 && std::all_of(line.begin(), line.end(), ::isdigit)) { { std::lock_guard lock(imei_mutex); IMEI = line; } LOG_INFO("[serial_at] IMEI = " + line); std::lock_guard lock(at_tasks_mutex); at_tasks.clear(); return; } } } // ================== 初始化 ================== void init_serial_at(const std::string& device, int baudrate) { if (serial_at_running.load()) { LOG_WARN("[serial_at] Already running"); return; } serial_at_running.store(true, std::memory_order_relaxed); serial_at = std::make_unique("serial_at", device, baudrate, 5); serial_at->set_receive_callback(handle_serial_at_data); serial_at->start(); serial_at_sender = std::thread(serial_at_send_loop); } // ================== 停止 ================== void stop_serial_at() { if (!serial_at_running.load()) return; LOG_INFO("[serial_at] Stopping..."); serial_at_running.store(false, std::memory_order_relaxed); if (serial_at) { serial_at->stop(); // 关闭串口,解除阻塞 } if (serial_at_sender.joinable()) { serial_at_sender.join(); } serial_at.reset(); LOG_INFO("[serial_at] Stopped cleanly"); }