242 lines
6.2 KiB
C++
242 lines
6.2 KiB
C++
/*
|
||
本程序用于设备激活
|
||
当检测配置文件发现设备未激活时,则系统阻塞
|
||
进行激活,并保存密文
|
||
当检测到设备已被激活后,启动验证程序,并退出本程序
|
||
*/
|
||
|
||
#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 ""; // 多次重试失败,返回空
|
||
} |