2025-10-24 16:56:35 +08:00
|
|
|
|
/*
|
|
|
|
|
|
本程序用于设备激活
|
|
|
|
|
|
当检测配置文件发现设备未激活时,则系统阻塞
|
|
|
|
|
|
进行激活,并保存密文
|
2025-11-07 15:04:34 +08:00
|
|
|
|
当检测到设备已被激活后,启动验证程序,并退出本程序
|
2025-10-24 16:56:35 +08:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#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";
|
2025-10-26 11:30:13 +08:00
|
|
|
|
const string TopicRecv = "/bsd_camera/cmd"; // 接收手机传来的信息
|
|
|
|
|
|
const string TopicSend = "/bsd_camera/init"; // 发送的话题
|
2025-10-24 16:56:35 +08:00
|
|
|
|
const int Qos = 1;
|
|
|
|
|
|
|
|
|
|
|
|
atomic<bool> isRunning(true);
|
2025-10-26 11:30:13 +08:00
|
|
|
|
atomic<bool> Deactivate(false); // 激活标志
|
2025-10-24 16:56:35 +08:00
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
2025-10-26 11:30:13 +08:00
|
|
|
|
// 退出程序,开始进行设备验证
|
|
|
|
|
|
void StartCheck();
|
|
|
|
|
|
|
2025-10-24 16:56:35 +08:00
|
|
|
|
int main()
|
|
|
|
|
|
{
|
2025-10-26 11:30:13 +08:00
|
|
|
|
Deactivate = checkUUID(); // 判断是否已被激活
|
|
|
|
|
|
if (Deactivate)
|
2025-10-24 16:56:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 设备已被激活,调用验证程序,退出本程序
|
2025-10-26 11:30:13 +08:00
|
|
|
|
cout << "设备已激活,开始验证" << endl;
|
|
|
|
|
|
StartCheck();
|
2025-10-24 16:56:35 +08:00
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化MQTT
|
|
|
|
|
|
mqttInit();
|
|
|
|
|
|
|
|
|
|
|
|
while (isRunning)
|
|
|
|
|
|
{
|
|
|
|
|
|
this_thread::sleep_for(1s); // 防止系统占用过高
|
|
|
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-26 11:30:13 +08:00
|
|
|
|
// 退出程序,开始进行设备验证
|
|
|
|
|
|
void StartCheck()
|
|
|
|
|
|
{
|
|
|
|
|
|
isRunning = false; // 退出程序
|
|
|
|
|
|
string cmd = "../../softWareInit/bin/wifi ";
|
|
|
|
|
|
system(cmd.c_str());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-24 16:56:35 +08:00
|
|
|
|
// 检测设备是否已经激活
|
|
|
|
|
|
bool checkUUID()
|
|
|
|
|
|
{
|
|
|
|
|
|
bool flag = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 读取文件
|
2025-10-24 17:25:57 +08:00
|
|
|
|
ReadFile rf(envPath);
|
|
|
|
|
|
if (rf.Open() == false)
|
2025-10-24 16:56:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
cerr << "文件打开失败" << endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 读取文本每一行
|
2025-10-24 17:25:57 +08:00
|
|
|
|
auto lines = rf.ReadLines();
|
2025-10-24 16:56:35 +08:00
|
|
|
|
for (auto &ii : lines)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ii.find("ServerPwd:null") != string::npos)
|
|
|
|
|
|
{
|
|
|
|
|
|
flag = false;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
flag = true;
|
|
|
|
|
|
}
|
2025-10-24 17:25:57 +08:00
|
|
|
|
|
|
|
|
|
|
rf.Close();
|
2025-10-24 16:56:35 +08:00
|
|
|
|
return flag;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 接受消息的回调
|
|
|
|
|
|
void messageCallback(mqtt::const_message_ptr msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 接受App传来的密文,并保存在配置文件中
|
|
|
|
|
|
auto buffer = msg->to_string();
|
2025-10-26 11:30:13 +08:00
|
|
|
|
// cout << "Topic:" << msg->get_topic() << ",msg:" << buffer << endl;
|
2025-10-24 16:56:35 +08:00
|
|
|
|
if (buffer.find("Activate") != string::npos)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 接受请求,发送SIM卡号
|
|
|
|
|
|
string ICCID = GetSimICCID();
|
2025-10-26 11:30:13 +08:00
|
|
|
|
string deviceId = format("{\"deviceUid\":\"{}\"}", ICCID);
|
|
|
|
|
|
// cout << "ICCID:" << deviceId << endl;
|
|
|
|
|
|
client.publish(TopicSend, deviceId, Qos, false); // 不保存
|
2025-10-24 16:56:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
else if (buffer.find("ServerPwd") != string::npos)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 接受UUID,保存至配置文件中,退出程序,调用设备验证程序
|
|
|
|
|
|
auto res = nlohmann::json::parse(buffer); // 准备解析接受到的秘钥
|
2025-10-26 11:30:13 +08:00
|
|
|
|
auto pwd = res["Data"];
|
|
|
|
|
|
// cout << pwd << endl;
|
2025-10-24 17:25:57 +08:00
|
|
|
|
// 写入文件
|
|
|
|
|
|
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;
|
2025-10-26 11:30:13 +08:00
|
|
|
|
out.reserve(1024);
|
2025-10-24 17:25:57 +08:00
|
|
|
|
for (size_t i = 0; i < lines.size(); ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
out += lines[i];
|
|
|
|
|
|
if (i + 1 < lines.size())
|
|
|
|
|
|
out += "\n";
|
|
|
|
|
|
}
|
2025-10-26 11:30:13 +08:00
|
|
|
|
wf.overwriteText(out);
|
|
|
|
|
|
|
|
|
|
|
|
Deactivate =true; })
|
2025-10-24 17:25:57 +08:00
|
|
|
|
.detach();
|
2025-10-24 16:56:35 +08:00
|
|
|
|
}
|
2025-10-26 11:30:13 +08:00
|
|
|
|
|
|
|
|
|
|
if (Deactivate)
|
|
|
|
|
|
{ // 已激活
|
|
|
|
|
|
StartCheck();
|
|
|
|
|
|
}
|
2025-10-24 16:56:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 连接成功的回调
|
|
|
|
|
|
void connectCallback(const string &cause)
|
|
|
|
|
|
{
|
|
|
|
|
|
cout << "连接成功" << endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void mqttInit()
|
|
|
|
|
|
{
|
|
|
|
|
|
client.set_message_callback(messageCallback);
|
|
|
|
|
|
client.set_connected_handler(connectCallback);
|
|
|
|
|
|
|
2025-10-26 11:30:13 +08:00
|
|
|
|
client.connect()->wait(); // 进行连接
|
|
|
|
|
|
client.subscribe(TopicRecv, Qos)->wait(); // 订阅话题
|
2025-10-24 16:56:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取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 ""; // 多次重试失败,返回空
|
|
|
|
|
|
}
|