/* 本程序用于设备激活 当检测配置文件发现设备未激活时,则系统阻塞 进行激活,并保存密文 */ #include #include //和App进行MQTT数据交互 #include #include //用于操作JSON文件 #include "Netra.hpp" using namespace std; using namespace QCL; using namespace chrono_literals; // 配置相对路径 const string envPath = "/home/orangepi/RKApp/InitAuth/conf/.env"; // MQTT相关配置 const string mqtt_url = "tcp://192.168.12.1:1883"; const string clientId = "RK3588_SubTest"; const string TopicRecv = "/bsd_camera/cmd"; // 接收手机传来的信息 const string TopicSend = "/bsd_camera/init"; // 发送的话题 const int Qos = 1; atomic isRunning(true); atomic Deactivate(false); // 激活标志 mqtt::async_client client(mqtt_url, clientId); // 获取SIM卡号 // 通过串口发送 AT+CCID 指令,读取并解析返回的ICCID号 string GetSimICCID(const string &tty = "/dev/ttyUSB2"); // MQTT初始化 void mqttInit(); // 连接成功的回调 void connectCallback(const string &cause); // 接受消息的回调 void messageCallback(mqtt::const_message_ptr msg); // 检测设备是否已进行初始化 bool checkUUID(); // 退出程序,开始进行设备验证 void StartCheck(); int main() { Deactivate = checkUUID(); // 判断是否已被激活 if (Deactivate) { // 设备已被激活,调用验证程序,退出本程序 cout << "设备已激活,开始验证" << endl; StartCheck(); return 0; } // 初始化MQTT mqttInit(); while (isRunning) { this_thread::sleep_for(1s); // 防止系统占用过高 } return 0; } // 退出程序,开始进行设备验证 void StartCheck() { isRunning = false; // 退出程序 string cmd = "../../softWareInit/bin/wifi "; system(cmd.c_str()); } // 检测设备是否已经激活 bool checkUUID() { bool flag = false; // 读取文件 ReadFile rf(envPath); if (rf.Open() == false) { cerr << "文件打开失败" << endl; } // 读取文本每一行 auto lines = rf.ReadLines(); for (auto &ii : lines) { if (ii.find("ServerPwd:null") != string::npos) { flag = false; break; } else flag = true; } rf.Close(); return flag; } // 接受消息的回调 void messageCallback(mqtt::const_message_ptr msg) { // 接受App传来的密文,并保存在配置文件中 auto buffer = msg->to_string(); // cout << "Topic:" << msg->get_topic() << ",msg:" << buffer << endl; if (buffer.find("Activate") != string::npos) { // 接受请求,发送SIM卡号 string ICCID = GetSimICCID(); string deviceId = format("{\"deviceUid\":\"{}\"}", ICCID); // cout << "ICCID:" << deviceId << endl; client.publish(TopicSend, deviceId, Qos, false); // 不保存 } else if (buffer.find("ServerPwd") != string::npos) { // 接受UUID,保存至配置文件中,退出程序,调用设备验证程序 auto res = nlohmann::json::parse(buffer); // 准备解析接受到的秘钥 auto pwd = res["Data"]; // cout << pwd << endl; // 写入文件 ReadFile rf(envPath); auto lines = rf.ReadLines(); for (auto &ii : lines) { if (ii.find("ServerPwd:null") != string::npos) ii = format("ServerPwd:{}", pwd); } rf.Close(); thread([lines]() { WriteFile wf(envPath); string out; out.reserve(1024); for (size_t i = 0; i < lines.size(); ++i) { out += lines[i]; if (i + 1 < lines.size()) out += "\n"; } wf.overwriteText(out); Deactivate =true; }) .detach(); } if (Deactivate) { // 已激活 StartCheck(); } } // 连接成功的回调 void connectCallback(const string &cause) { cout << "连接成功" << endl; } void mqttInit() { client.set_message_callback(messageCallback); client.set_connected_handler(connectCallback); client.connect()->wait(); // 进行连接 client.subscribe(TopicRecv, Qos)->wait(); // 订阅话题 } // 获取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 ""; // 多次重试失败,返回空 }