diff --git a/ApCreate/NetraLib/src/Netra.cpp b/ApCreate/NetraLib/src/Netra.cpp index 51b7379..a67282c 100644 --- a/ApCreate/NetraLib/src/Netra.cpp +++ b/ApCreate/NetraLib/src/Netra.cpp @@ -535,7 +535,7 @@ namespace QCL // } // return lines; - std::lock_guard lock(mtx_); + // std::lock_guard lock(mtx_); if (!file_.is_open()) { file_.open(filename_, std::ios::in | std::ios::binary); if (!file_.is_open()) return {}; diff --git a/ApCreate/bin/ap b/ApCreate/bin/ap new file mode 100755 index 0000000..0fa4f86 Binary files /dev/null and b/ApCreate/bin/ap differ diff --git a/ApCreate/bin/wifi b/ApCreate/bin/wifi index 1f50a7a..b969880 100755 Binary files a/ApCreate/bin/wifi and b/ApCreate/bin/wifi differ diff --git a/ApCreate/src/createAp.cpp b/ApCreate/src/createAp.cpp new file mode 100644 index 0000000..3566d8a --- /dev/null +++ b/ApCreate/src/createAp.cpp @@ -0,0 +1,10 @@ +#include +#include + +using namespace std; + +int main() +{ + string cmd = "echo 'orangepi' | sudo -S create_ap wlan0 enP4p65s0 orangepi 12345678"; + thread([cmd](){ system(cmd.c_str()); }).detach(); +} \ No newline at end of file diff --git a/ApCreate/src/main.cpp b/ApCreate/src/main.cpp index 28952ad..14fdc4c 100644 --- a/ApCreate/src/main.cpp +++ b/ApCreate/src/main.cpp @@ -24,11 +24,11 @@ using namespace std; using namespace QCL; using namespace ntq; using namespace encrypt; +using namespace chrono_literals; namespace bp = boost::process; bp::child rtsp_proc; // 服务器进程 bp::child video_proc; // 视频推流进程 -bp::child ap_proc; // 创建热点进程 bp::child net_proc; // 开启网络进程 // 文件设置路径 @@ -40,7 +40,7 @@ string passwd = "/home/orangepi/InitAuth/pwd/.env"; const string url = "http://116.147.36.110:8095/device/validateDevice"; const string mqtt_url = "tcp://192.168.12.1:1883"; const string clientId = "RK3588_SubTest"; -const string Topic = "/Test"; +const string Topic = "/bsd_camera/cmd"; const int Qos = 1; std::atomic isRunning(true); // 全局运行标志 @@ -61,8 +61,6 @@ struct OutSignal bool inPutMode; // 触发输入模式 true--高电平,false -- 低电平 } algor{}; -mqtt::async_client client(mqtt_url, clientId); - // 确认是否已经进行过认证 bool ConfirmInit(); @@ -73,7 +71,7 @@ string GetCardInfo(); string GetSimICCID(const string &tty = "/dev/ttyUSB2"); // 发送cpu序列号和SIM卡号 -void SendCardInfo(TcpServer *MyServer); +void SendCardInfo(mqtt::async_client &client); // 进行验证 bool verification(); @@ -83,7 +81,9 @@ template void CalculateInfo(T &conf, const string &json); // 创建服务器 -TcpServer *MyServer; +// TcpServer *MyServer; +// mqtt client +mqtt::async_client client(mqtt_url, clientId); // 打开RSTP服务器 void OpenRTSP(); @@ -91,9 +91,6 @@ void OpenRTSP(); // 视频推流 void VideoStream(); -// 接收数据 -void ReceiveData(); - // 退出信号捕捉 void Exit(int sig); @@ -128,20 +125,11 @@ int main(int argc, char *argv[]) // 初始化mqtt服务器 mqttInit(); - while (1) - { - this_thread::sleep_for(chrono::seconds(1)); - } - - // 开启服务器 - MyServer = new TcpServer(8848); - - MyServer->start(); // 不会阻塞 - + // // 开启服务器 // 如果没有进行过初始化,发送物联网卡信息进行认证 if (ConfirmInit() == false) { - SendCardInfo(MyServer); + SendCardInfo(client); } else { @@ -156,29 +144,30 @@ int main(int argc, char *argv[]) thread(StartService).detach(); thread Rtsp(OpenRTSP); + // OpenRTSP(); std::this_thread::sleep_for(chrono::seconds(2)); // 等待RTSP服务器启动 // 进行RTSP视频推流 thread video(VideoStream); - // 作为服务端进行数据的收发 - thread Processing(ReceiveData); + while (isRunning) + { + this_thread::sleep_for(1s); + } - // 等待热点创建线程结束 - Processing.join(); + // Processing.join(); video.join(); Rtsp.join(); return 0; } +// 初始化MQTT void mqttInit() { client.set_connected_handler([](const string &cause) - { - cout << cause << endl; - cout << "Connected Successed!\n"; }); + { cout << "Connected Successed!\n"; }); client.set_message_callback(getMsgCallback); // 连接服务器 @@ -189,17 +178,144 @@ void mqttInit() // 接收消息回调 void getMsgCallback(mqtt::const_message_ptr msg) { - cout << "收到消息" << endl; - cout << "recv:" << msg->to_string() << endl; + // 立即拷贝负载,避免在回调里做大量工作 + std::string payload = msg->to_string(); + + cout << "Recv:" << payload << endl; + + std::thread([payload]() + { + try + { + string buffer = payload; + if (buffer.empty()) + return; + + // Pass: 更新 Init 标志并写入密码文件 + if (buffer.find("Pass:") != string::npos) + { + WriteFile wf(filepath); + string str = "yse\n"; + wf.overwriteAtPos(str, wf.countBytesPattern("InitOrNot:", true), str.size()); + + WriteFile wf2(passwd); + wf2.overwriteText(buffer.substr(5)); + return; + } + + // SET_DISTANCES: 解析 JSON 并更新 cameraPath 文件 + if (buffer.find("SET_DISTANCES") != string::npos) + { + auto res = nlohmann::json::parse(buffer); + auto &danger_json = res["params"]["danger_distance"]; + auto &warning_json = res["params"]["warning_distance"]; + auto &safe_json = res["params"]["safe_distance"]; + + auto toDouble = [](const nlohmann::json &jv) -> double { + if (jv.is_number()) return jv.get(); + if (jv.is_string()) { + try { return std::stod(jv.get()); } + catch (...) { return 0.0; } + } + return 0.0; + }; + + double danger = toDouble(danger_json); + double warn = toDouble(warning_json); + double safe = toDouble(safe_json); + + ReadFile rf(cameraPath); + if (!rf.Open()) { + cerr << "文件打开失败: " << cameraPath << "\n"; + } else { + auto lines = rf.ReadLines(); + for (auto &line : lines) { + if (line.rfind("NEAR_THRESHOLD=", 0) == 0) line = format("NEAR_THRESHOLD={}", danger); + else if (line.rfind("MID_THRESHOLD=", 0) == 0) line = format("MID_THRESHOLD={}", warn); + else if (line.rfind("MAX_DISTANCE=", 0) == 0) line = format("MAX_DISTANCE={}", safe); + } + string out; + out.reserve(4096); + for (size_t i = 0; i < lines.size(); ++i) { + out += lines[i]; + if (i + 1 < lines.size()) out += "\n"; + } + WriteFile wf(cameraPath); + wf.overwriteText(out); + } + return; + } + + // media: 更新 cameraPath 的 MEDIA_* 设置 + if (buffer.find("media") != string::npos) + { + CalculateInfo(media, buffer); + ReadFile rf(cameraPath); + if (!rf.Open()) { + cerr << "文件打开失败: " << cameraPath << "\n"; + } else { + auto lines = rf.ReadLines(); + for (auto &line : lines) { + if (line.rfind("MEDIA_MIRROR=", 0) == 0) line = format("MEDIA_MIRROR={}", media.mirror ? "true" : "false"); + else if (line.rfind("MEDIA_FLIP=", 0) == 0) line = format("MEDIA_FLIP={}", media.flip ? "true" : "false"); + else if (line.rfind("MEDIA_OCCLUSION=", 0) == 0) line = format("MEDIA_OCCLUSION={}", media.occlusion ? "true" : "false"); + } + string out; + out.reserve(4096); + for (size_t i = 0; i < lines.size(); ++i) { + out += lines[i]; + if (i + 1 < lines.size()) out += "\n"; + } + WriteFile wf(cameraPath); + wf.overwriteText(out); + } + return; + } + + // algorithm: 更新 filepath 中的 outPutMode/inPutMode + if (buffer.find("algorithm") != string::npos) + { + CalculateInfo(algor, buffer); + ReadFile rf2(filepath); + if (!rf2.Open()) { + cerr << "文件打开失败: " << filepath << "\n"; + } else { + auto lines = rf2.ReadLines(); + for (auto &line : lines) { + if (line.rfind("outPutMode:", 0) == 0) line = format("outPutMode:{}", algor.outPutMode ? "true" : "false"); + else if (line.rfind("inPutMode:", 0) == 0) line = format("inPutMode:{}", algor.inPutMode ? "true" : "false"); + } + string out; + out.reserve(4096); + for (size_t i = 0; i < lines.size(); ++i) { + out += lines[i]; + if (i + 1 < lines.size()) out += "\n"; + } + WriteFile wf2(filepath); + wf2.overwriteText(out); + } + return; + } + } + catch (const std::exception &e) + { + std::cerr << "处理 MQTT 消息异常: " << e.what() << std::endl; + } + catch (...) + { + std::cerr << "处理 MQTT 消息时发生未知错误\n"; + } }) + .detach(); } -// 开启服务 +// 开启服务:fastApi,pub void StartService() { string commnd = "echo 'orangepi' | sudo -S ../../StartService/bin/start start"; system(commnd.c_str()); } +// 开启网络 void StartNet() { string commd = "../../GetNet/bin/setNet"; @@ -279,210 +395,19 @@ void Exit(int sig) { cout << "Exiting..." << endl; isRunning = false; - confirm = false; - MyServer->stop(); + // confirm = false; + // MyServer->stop(); - system("sudo killall create_ap"); + cout << "System Quit" << endl; + + // system("sudo killall create_ap"); // 杀死后台 RTSP 和 ffmpeg 进程 - if (rtsp_proc.running()) - rtsp_proc.terminate(); - if (video_proc.running()) - video_proc.terminate(); - if (ap_proc.running()) - ap_proc.terminate(); - if (net_proc.running()) - net_proc.terminate(); -} - -// 接收数据 -void ReceiveData() -{ - string buffer = ""; - while (isRunning) - { - std::vector client = MyServer->getClientSockets(); - if (client.empty()) - { - this_thread::sleep_for(chrono::milliseconds(100)); - continue; - } - int index = client.size(); - // cout << "index: " << index << endl; - for (int ii = 0; ii < index; ++ii) // 从新到旧,优先处理新连接 - { - buffer = MyServer->receiveFromClient(client[ii], false); // 非阻塞模式接受数据 - // cout << buffer << endl; - if (buffer.empty() == false) - { - cout << "已收到" << buffer << endl; - // 处理数据 - if (buffer.find("Pass:") != string::npos) - { - cout << "已收到" << buffer << endl; - // 验证秘钥 - WriteFile wf(filepath); - string str = "yse\n"; - wf.overwriteAtPos(str, wf.countBytesPattern("InitOrNot:", true), str.size()); - cout << "已更新" << endl; - // 将秘钥写入配置文件: - WriteFile wf2(passwd); - wf2.overwriteText(buffer.substr(5)); - } - else if (buffer.find("SET_DISTANCES") != string::npos) - { // 接收距离参数 - auto res = nlohmann::json::parse(buffer); - // 读取值并兼容 number/string - auto &danger_json = res["params"]["danger_distance"]; - auto &warning_json = res["params"]["warning_distance"]; - auto &safe_json = res["params"]["safe_distance"]; - - auto toDouble = [](const nlohmann::json &jv) -> double - { - if (jv.is_number()) - return jv.get(); - if (jv.is_string()) - { - try - { - return std::stod(jv.get()); - } - catch (...) - { - return 0.0; - } - } - return 0.0; - }; - - double danger = toDouble(danger_json); - double warn = toDouble(warning_json); - double safe = toDouble(safe_json); - - // 整文件读取,逐行替换,保持注释不变 - ReadFile *rf = new ReadFile(cameraPath); - if (!rf->Open()) - { - cerr << "文件打开失败: " << cameraPath << "\n"; - } - else - { - auto lines = rf->ReadLines(); - delete rf; - for (auto &line : lines) - { - if (line.rfind("NEAR_THRESHOLD=", 0) == 0) - { - line = format("NEAR_THRESHOLD={}", danger); - } - else if (line.rfind("MID_THRESHOLD=", 0) == 0) - { - line = format("MID_THRESHOLD={}", warn); - } - else if (line.rfind("MAX_DISTANCE=", 0) == 0) - { - line = format("MAX_DISTANCE={}", safe); - } - } - - // 重新拼接并整体写回 - string out; - out.reserve(4096); - for (size_t i = 0; i < lines.size(); ++i) - { - out += lines[i]; - if (i + 1 < lines.size()) - out += "\n"; - } - WriteFile *wf = new WriteFile(cameraPath); - wf->overwriteText(out); - delete wf; - } - } - else if (buffer.find("media") != string::npos) - { - // 写摄像头参数(与距离相同方式: 整体读取-逐行替换-整体写回) - cout << buffer << endl; - CalculateInfo(media, buffer); - ReadFile *rf = new ReadFile(cameraPath); - if (!rf->Open()) - { - cerr << "文件打开失败: " << cameraPath << "\n"; - } - else - { - auto lines = rf->ReadLines(); - delete rf; - for (auto &line : lines) - { - if (line.rfind("MEDIA_MIRROR=", 0) == 0) - { - line = format("MEDIA_MIRROR={}", media.mirror ? "true" : "false"); - } - else if (line.rfind("MEDIA_FLIP=", 0) == 0) - { - line = format("MEDIA_FLIP={}", media.flip ? "true" : "false"); - } - else if (line.rfind("MEDIA_OCCLUSION=", 0) == 0) - { - line = format("MEDIA_OCCLUSION={}", media.occlusion ? "true" : "false"); - } - } - - string out; - out.reserve(4096); - for (size_t i = 0; i < lines.size(); ++i) - { - out += lines[i]; - if (i + 1 < lines.size()) - out += "\n"; - } - WriteFile *wf = new WriteFile(cameraPath); - wf->overwriteText(out); - delete wf; - } - } - else if (buffer.find("algorithm") != string::npos) - { - // 写输入输出参数(与距离相同方式: 整体读取-逐行替换-整体写回) - CalculateInfo(algor, buffer); - ReadFile *rf2 = new ReadFile(filepath); - if (!rf2->Open()) - { - cerr << "文件打开失败: " << filepath << "\n"; - } - else - { - auto lines = rf2->ReadLines(); - delete rf2; - for (auto &line : lines) - { - if (line.rfind("outPutMode:", 0) == 0) - { - line = format("outPutMode:{}", algor.outPutMode ? "true" : "false"); - } - else if (line.rfind("inPutMode:", 0) == 0) - { - line = format("inPutMode:{}", algor.inPutMode ? "true" : "false"); - } - } - - string out; - out.reserve(4096); - for (size_t i = 0; i < lines.size(); ++i) - { - out += lines[i]; - if (i + 1 < lines.size()) - out += "\n"; - } - WriteFile *wf2 = new WriteFile(filepath); - wf2->overwriteText(out); - delete wf2; - } - } - } - } - this_thread::sleep_for(chrono::milliseconds(100)); // 避免过于频繁的循环 - } + // if (rtsp_proc.running()) + // rtsp_proc.terminate(); + // if (video_proc.running()) + // video_proc.terminate(); + // if (net_proc.running()) + // net_proc.terminate(); } // 打开RSTP服务器 @@ -610,30 +535,14 @@ string GetSimICCID(const string &tty) } // 发送cpu序列号和SIM卡号 -void SendCardInfo(TcpServer *MyServer) +void SendCardInfo(mqtt::async_client &client) { string CardID = GetCardInfo(); string SIMID = GetSimICCID(); string info = CardID + SIMID; - while (confirm) - { - std::vector client = MyServer->getClientSockets(); - if (client.empty()) - continue; - cout << "有了客户端连接" << endl; - size_t index = client.size(); - - for (int ii = 0; ii < index; ii++) - { - if (MyServer->receiveFromClient(client[ii]) == "GET_ID") - { - cout << info << endl; - MyServer->sendToClient(client[ii], info + " "); - } - } - break; - } + // 发送信息 + client.publish(Topic, info, Qos, false); } // 解析接收的数据 diff --git a/ApCreate/src/main.cpp.bak b/ApCreate/src/main.cpp.bak new file mode 100644 index 0000000..3918d25 --- /dev/null +++ b/ApCreate/src/main.cpp.bak @@ -0,0 +1,577 @@ +/* +本程序提供以下功能: +1.开启4G模块,允许上网 +2.进行RTSP推流 +3.初始化验证->启动系统服务 +*/ + +#include +#include +#include +#include + +#include + +#include + +#include + +#include "Netra.hpp" +#include "NetRequest.hpp" +#include "encrypt.hpp" + +using namespace std; +using namespace QCL; +using namespace ntq; +using namespace encrypt; +using namespace chrono_literals; +namespace bp = boost::process; + +bp::child rtsp_proc; // 服务器进程 +bp::child video_proc; // 视频推流进程 +bp::child net_proc; // 开启网络进程 + +// 文件设置路径 +string filepath = "/home/orangepi/InitAuth/conf/.env"; +string cameraPath = "/opt/rknn-yolov11/.env"; +string passwd = "/home/orangepi/InitAuth/pwd/.env"; + +// 云端Web认证接口 +const string url = "http://116.147.36.110:8095/device/validateDevice"; +const string mqtt_url = "tcp://192.168.12.1:1883"; +const string clientId = "RK3588_SubTest"; +const string Topic = "/bsd_camera/cmd"; +const int Qos = 1; + +std::atomic isRunning(true); // 全局运行标志 +std::atomic confirm(true); // 发送卡和ID + +// 媒体对象 +struct Media +{ + bool mirror; // 镜像 + bool flip; // 翻转 + bool occlusion; // 遮挡 +} media{}; + +// 输入输出对象 +struct OutSignal +{ + bool outPutMode; // 警报输出电平 true--高电平,false -- 低电平 + bool inPutMode; // 触发输入模式 true--高电平,false -- 低电平 +} algor{}; + +// 确认是否已经进行过认证 +bool ConfirmInit(); + +// 获取cpu序列号和SIM卡号 +string GetCardInfo(); + +// 获取SIM卡号 +string GetSimICCID(const string &tty = "/dev/ttyUSB2"); + +// 发送cpu序列号和SIM卡号 +void SendCardInfo(mqtt::async_client &client); + +// 进行验证 +bool verification(); + +// 解析接收的数据 +template +void CalculateInfo(T &conf, const string &json); + +// 创建服务器 +// TcpServer *MyServer; +// mqtt client +mqtt::async_client client(mqtt_url, clientId); + +// 打开RSTP服务器 +void OpenRTSP(); + +// 视频推流 +void VideoStream(); + +// 退出信号捕捉 +void Exit(int sig); + +// 开启网络(4G模块) +void StartNet(); + +// 开启服务 +void StartService(); + +// mqtt初始化 +void mqttInit(); + +// 接收消息回调 +void getMsgCallback(mqtt::const_message_ptr msg); + +/* +parames: +argv[1] - SSID of the WiFi network to connect to +argv[2] - Password for the WiFi network (if applicable) +*/ +int main(int argc, char *argv[]) +{ + // 开启4G模块 + StartNet(); + + this_thread::sleep_for(chrono::seconds(2)); + + // 关闭全部信号 + blockAllSignals(); + signal(SIGINT, Exit); // 捕获Ctrl+C信号 + + // 初始化mqtt服务器 + mqttInit(); + + // // 开启服务器 + // 如果没有进行过初始化,发送物联网卡信息进行认证 + if (ConfirmInit() == false) + { + SendCardInfo(client); + } + else + { + if (verification() == false) + { + cerr << "验证失败" << endl; + return 0; + } + } + + // 开启服务 + thread(StartService).detach(); + + thread Rtsp(OpenRTSP); + std::this_thread::sleep_for(chrono::seconds(2)); // 等待RTSP服务器启动 + + // 进行RTSP视频推流 + thread video(VideoStream); + + while (isRunning) + { + this_thread::sleep_for(1s); + } + + // Processing.join(); + video.join(); + Rtsp.join(); + + return 0; +} + +// 初始化MQTT +void mqttInit() +{ + + client.set_connected_handler([](const string &cause) + { cout << "Connected Successed!\n"; }); + client.set_message_callback(getMsgCallback); + + // 连接服务器 + client.connect()->wait(); + client.subscribe(Topic, Qos)->wait(); +} + +// 接收消息回调 +void getMsgCallback(mqtt::const_message_ptr msg) +{ + // 立即拷贝负载,避免在回调里做大量工作 + std::string payload = msg->to_string(); + + cout << "Recv:" << payload << endl; + + std::thread([payload]() + { + try + { + string buffer = payload; + if (buffer.empty()) + return; + + // Pass: 更新 Init 标志并写入密码文件 + if (buffer.find("Pass:") != string::npos) + { + WriteFile wf(filepath); + string str = "yse\n"; + wf.overwriteAtPos(str, wf.countBytesPattern("InitOrNot:", true), str.size()); + + WriteFile wf2(passwd); + wf2.overwriteText(buffer.substr(5)); + return; + } + + // SET_DISTANCES: 解析 JSON 并更新 cameraPath 文件 + if (buffer.find("SET_DISTANCES") != string::npos) + { + auto res = nlohmann::json::parse(buffer); + auto &danger_json = res["params"]["danger_distance"]; + auto &warning_json = res["params"]["warning_distance"]; + auto &safe_json = res["params"]["safe_distance"]; + + auto toDouble = [](const nlohmann::json &jv) -> double { + if (jv.is_number()) return jv.get(); + if (jv.is_string()) { + try { return std::stod(jv.get()); } + catch (...) { return 0.0; } + } + return 0.0; + }; + + double danger = toDouble(danger_json); + double warn = toDouble(warning_json); + double safe = toDouble(safe_json); + + ReadFile rf(cameraPath); + if (!rf.Open()) { + cerr << "文件打开失败: " << cameraPath << "\n"; + } else { + auto lines = rf.ReadLines(); + for (auto &line : lines) { + if (line.rfind("NEAR_THRESHOLD=", 0) == 0) line = format("NEAR_THRESHOLD={}", danger); + else if (line.rfind("MID_THRESHOLD=", 0) == 0) line = format("MID_THRESHOLD={}", warn); + else if (line.rfind("MAX_DISTANCE=", 0) == 0) line = format("MAX_DISTANCE={}", safe); + } + string out; + out.reserve(4096); + for (size_t i = 0; i < lines.size(); ++i) { + out += lines[i]; + if (i + 1 < lines.size()) out += "\n"; + } + WriteFile wf(cameraPath); + wf.overwriteText(out); + } + return; + } + + // media: 更新 cameraPath 的 MEDIA_* 设置 + if (buffer.find("media") != string::npos) + { + CalculateInfo(media, buffer); + ReadFile rf(cameraPath); + if (!rf.Open()) { + cerr << "文件打开失败: " << cameraPath << "\n"; + } else { + auto lines = rf.ReadLines(); + for (auto &line : lines) { + if (line.rfind("MEDIA_MIRROR=", 0) == 0) line = format("MEDIA_MIRROR={}", media.mirror ? "true" : "false"); + else if (line.rfind("MEDIA_FLIP=", 0) == 0) line = format("MEDIA_FLIP={}", media.flip ? "true" : "false"); + else if (line.rfind("MEDIA_OCCLUSION=", 0) == 0) line = format("MEDIA_OCCLUSION={}", media.occlusion ? "true" : "false"); + } + string out; + out.reserve(4096); + for (size_t i = 0; i < lines.size(); ++i) { + out += lines[i]; + if (i + 1 < lines.size()) out += "\n"; + } + WriteFile wf(cameraPath); + wf.overwriteText(out); + } + return; + } + + // algorithm: 更新 filepath 中的 outPutMode/inPutMode + if (buffer.find("algorithm") != string::npos) + { + CalculateInfo(algor, buffer); + ReadFile rf2(filepath); + if (!rf2.Open()) { + cerr << "文件打开失败: " << filepath << "\n"; + } else { + auto lines = rf2.ReadLines(); + for (auto &line : lines) { + if (line.rfind("outPutMode:", 0) == 0) line = format("outPutMode:{}", algor.outPutMode ? "true" : "false"); + else if (line.rfind("inPutMode:", 0) == 0) line = format("inPutMode:{}", algor.inPutMode ? "true" : "false"); + } + string out; + out.reserve(4096); + for (size_t i = 0; i < lines.size(); ++i) { + out += lines[i]; + if (i + 1 < lines.size()) out += "\n"; + } + WriteFile wf2(filepath); + wf2.overwriteText(out); + } + return; + } + } + catch (const std::exception &e) + { + std::cerr << "处理 MQTT 消息异常: " << e.what() << std::endl; + } + catch (...) + { + std::cerr << "处理 MQTT 消息时发生未知错误\n"; + } }) + .detach(); +} + +// 开启服务:fastApi,pub +void StartService() +{ + string commnd = "echo 'orangepi' | sudo -S ../../StartService/bin/start start"; + system(commnd.c_str()); +} + +// 开启网络 +void StartNet() +{ + string commd = "../../GetNet/bin/setNet"; + net_proc = bp::child("/bin/bash", bp::args = {"-c", commd}); +} + +// 进行验证 +bool verification() +{ + // 读取文件密文 + ReadFile *rf = new ReadFile(passwd); + bool flag = false; + auto pass = rf->ReadLines(); + // 若为空:改写初始化标志位false,重认证 + if (pass.empty()) + { + WriteFile *wf = new WriteFile(filepath); + wf->overwriteAtPos("no", wf->countBytesPattern("InitOrNot:", true), 3); + return 0; + } + + for (auto &ii : pass) + { + // 不为空,线上发送密文开始认证 + auto pos = format(R"({{"cardNo":"{}"}})", ii); + + auto res = NetRequest::QuickPostJson(url, pos); + + int code = -1; + if (res) + { + try + { + code = nlohmann::json::parse(res->body).value("code", -1); + } + catch (const std::exception &e) + { + std::cerr << "JSON解析失败: " << e.what() << std::endl; + } + } + + if (res && code == 200) + { + cout << "线上:认证成功" << endl; + flag = true; + } + else + { + try + { + // 进行线下认证 + // 获取cpu序列号和SIM卡号 + string CardID = GetCardInfo(); + string SIMID = GetSimICCID(); + string info = CardID + SIMID; + // 进行MD5加密 + string md5 = MD5(info); + cout << md5 << endl; + if (md5.compare(ii) == 0) + { + cout << "线下:认证成功" << endl; + flag = true; + } + } + catch (const std::exception &e) + { + std::cerr << e.what() << '\n'; + } + } + } + cout << "结束" << endl; + return flag; +} + +// 退出信号 +void Exit(int sig) +{ + cout << "Exiting..." << endl; + isRunning = false; + confirm = false; + // MyServer->stop(); + + system("sudo killall create_ap"); + // 杀死后台 RTSP 和 ffmpeg 进程 + if (rtsp_proc.running()) + rtsp_proc.terminate(); + if (video_proc.running()) + video_proc.terminate(); + if (net_proc.running()) + net_proc.terminate(); +} + +// 打开RSTP服务器 +void OpenRTSP() +{ + string commnd = "../RTSPServer/mediamtx ../RTSPServer/mediamtx.yml"; + rtsp_proc = bp::child("/bin/bash", bp::args = {"-c", commnd}); +} + +// 视频推流 +void VideoStream() +{ + // 静音ffmpeg的统计输出,保留错误;避免污染日志 + string commnd = "ffmpeg -nostats -hide_banner -loglevel error -f v4l2 -i /dev/video0 -c:v h264_rkmpp -rtsp_transport tcp -f rtsp rtsp://192.168.12.1:8554/stream 2>/dev/null"; + video_proc = bp::child("/bin/bash", bp::args = {"-c", commnd}); +} + +// 确认是否已经进行过认证 +bool ConfirmInit() +{ + ReadFile *rf = new ReadFile(filepath); + if (rf->Open() == false) + { + cerr << "文件打开失败\n"; + return false; + } + + auto vct = rf->ReadLines(); + for (auto &ii : vct) + { + if (ii.find("InitOrNot:no") != string::npos) + return false; + } + return true; +} + +// 获取cpu序列号和SIM卡号 +string GetCardInfo() +{ + ReadFile *rf = new ReadFile("/proc/cpuinfo"); + if (rf->Open() == false) + { + cerr << "文件打开失败\n"; + return ""; + } + + auto lines = rf->ReadLines(); + string res = ""; + for (auto &ii : lines) + { + if (ii.find("Serial") != string::npos) + { + auto pos = ii.find(":"); + if (pos != string::npos) + { + res = ii.substr(pos + 1); + break; + } + } + } + + return LRtrim(res); +} + +// 获取SIM卡号 +// 通过串口发送 AT+CCID 指令,读取并解析返回的ICCID号 +string GetSimICCID(const string &tty) +{ + int retry = 0; // 重试次数 + while (retry < 5) // 最多重试5次 + { + int fd = open(tty.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); // 打开串口 + if (fd < 0) + { + std::cerr << "无法打开串口: " << tty << std::endl; + return ""; + } + + // 配置串口参数 + struct termios options; + tcgetattr(fd, &options); + cfsetispeed(&options, B115200); + cfsetospeed(&options, B115200); + options.c_cflag |= (CLOCAL | CREAD); + tcsetattr(fd, TCSANOW, &options); + + // 发送 AT+CCID 指令 + write(fd, "AT+CCID\r\n", 9); + + std::string result; + char buf[256] = {0}; + // 循环多次读取,拼接内容,防止数据分包 + for (int i = 0; i < 10; ++i) + { + usleep(100000); // 每次等待100ms + int n = read(fd, buf, sizeof(buf) - 1); + if (n > 0) + result.append(buf, n); + } + close(fd); // 关闭串口 + + // 检查是否有ERROR,若有则重试 + if (result.find("ERROR") != std::string::npos) + { + retry++; + usleep(200000); // 等待200ms再重试 + continue; + } + + // 用正则提取ICCID(+CCID: 后面的数字) + std::smatch m; + std::regex reg(R"(\+CCID:\s*([0-9]+))"); + if (std::regex_search(result, m, reg)) + return m[1]; + + // 兜底:直接找19~22位数字(兼容不同长度的ICCID) + std::regex reg2(R"((\d{19,22}))"); + if (std::regex_search(result, m, reg2)) + return m[1]; + + // 没有ERROR但也没读到ICCID,直接退出循环 + break; + } + return ""; // 多次重试失败,返回空 +} + +// 发送cpu序列号和SIM卡号 +void SendCardInfo(mqtt::async_client &client) +{ + string CardID = GetCardInfo(); + string SIMID = GetSimICCID(); + string info = CardID + SIMID; + + // 发送信息 + client.publish(Topic, info, Qos, false); +} + +// 解析接收的数据 +template +void CalculateInfo(T &conf, const string &json) +{ + try + { + /* code */ + auto j = nlohmann::json::parse(json); + if (j.contains("params") && j["params"].contains("media")) + { + auto conf = j["params"]["media"]; + if (conf.contains("mirror")) + media.mirror = conf["mirror"].get(); + if (conf.contains("flip")) + media.flip = conf["mirror"].get(); + if (conf.contains("occlusion")) + media.occlusion = conf["occlusion"].get(); + } + else if (j.contains("params") && j["params"].contains("algorithm")) + { + auto conf = j["params"]["algorithm"]; + if (conf.contains("alarm_output_mode")) + algor.outPutMode = (conf["alarm_output_mode"].get().find("高电平") != string::npos) ? true : false; + + if (conf.contains("trigger_input_mode")) + algor.inPutMode = (conf["trigger_input_mode"].get().find("高电平") != string::npos) ? true : false; + } + } + catch (const std::exception &e) + { + std::cerr << e.what() << '\n'; + } +} diff --git a/PyApp/upload.log b/PyApp/upload.log index 4a92a5f..4fa8c1e 100644 --- a/PyApp/upload.log +++ b/PyApp/upload.log @@ -1479,3 +1479,5 @@ 2025-10-13 10:28:15 - 使用经纬度上传: lon=1201, lat=3129 2025-10-13 10:28:16 - 数据库插入成功 2025-10-13 10:28:16 - 上传线程结束: /mnt/save/warning/warning_20251013_102811.jpg: 成功! +2025-10-21 12:02:47 - 开始上传图片: /mnt/save/warning/warning_20251021_120245.jpg +2025-10-21 12:02:48 - 使用经纬度上传: lon=1201, lat=3129