Files
RkApp/DeviceActivate/src/main.cpp
2025-10-26 11:30:13 +08:00

241 lines
6.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
本程序用于设备激活
当检测配置文件发现设备未激活时,则系统阻塞
进行激活,并保存密文
*/
#include <iostream>
#include <mqtt/async_client.h> //和App进行MQTT数据交互
#include <boost/process.hpp>
#include <nlohmann/json.hpp> //用于操作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<bool> isRunning(true);
atomic<bool> 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 ""; // 多次重试失败,返回空
}