init
This commit is contained in:
364
DeviceActivate/src/main.cpp
Normal file
364
DeviceActivate/src/main.cpp
Normal file
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
本程序用于设备激活
|
||||
当检测配置文件发现设备未激活时,则系统阻塞
|
||||
进行激活,并保存密文
|
||||
当检测到设备已被激活后,启动验证程序,并退出本程序
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <mqtt/async_client.h> //和App进行MQTT数据交互
|
||||
#include <boost/process.hpp>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
#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); // 激活标志
|
||||
mutex envMutex; // 配置锁
|
||||
mutex runMutex;
|
||||
condition_variable runCv; // 条件变量,判断是否可以启动验证程序
|
||||
|
||||
mqtt::async_client client(mqtt_url, clientId);
|
||||
atomic<pid_t> g_soft_pid{0};
|
||||
|
||||
// 获取SIM卡号
|
||||
// 通过串口发送 AT+CCID 指令,读取并解析返回的ICCID号
|
||||
string GetSimICCID(const string &tty = "/dev/ttyUSB2");
|
||||
// 获取唯一标识码
|
||||
string GetqrCode();
|
||||
|
||||
// MQTT初始化
|
||||
void mqttInit();
|
||||
|
||||
// 连接成功的回调
|
||||
void connectCallback(const string &cause);
|
||||
|
||||
// 接受消息的回调
|
||||
void messageCallback(mqtt::const_message_ptr msg);
|
||||
|
||||
// 检测设备是否已进行初始化
|
||||
bool checkUUID();
|
||||
|
||||
// 退出程序,开始进行设备验证
|
||||
void StartCheck();
|
||||
|
||||
void forwardSigint(int);
|
||||
|
||||
int main()
|
||||
{
|
||||
if (checkUUID())
|
||||
{
|
||||
// 设备已被激活,调用验证程序,退出本程序
|
||||
cout << "设备已激活,开始验证" << endl;
|
||||
StartCheck();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 初始化MQTT
|
||||
mqttInit();
|
||||
|
||||
unique_lock<mutex> lk(runMutex);
|
||||
runCv.wait(lk, []()
|
||||
{ return !isRunning.load(); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
void forwardSigint(int)
|
||||
{
|
||||
pid_t gpid = g_soft_pid.load();
|
||||
if (gpid > 0)
|
||||
{
|
||||
kill(-gpid, SIGINT);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取唯一标识码
|
||||
string GetqrCode()
|
||||
{
|
||||
lock_guard<mutex> lk(envMutex);
|
||||
string UUID = "";
|
||||
ReadFile rf(envPath);
|
||||
rf.Open();
|
||||
auto lines = rf.ReadLines();
|
||||
for (auto &line : lines)
|
||||
{
|
||||
if (line.find("UUID:\"") != string::npos)
|
||||
{
|
||||
size_t start = sizeof("UUID:\"") - 1;
|
||||
size_t end = line.find_last_of("\"") - start;
|
||||
UUID = line.substr(start, end);
|
||||
}
|
||||
}
|
||||
rf.Close();
|
||||
return UUID;
|
||||
}
|
||||
|
||||
// 退出程序,开始进行设备验证
|
||||
void StartCheck()
|
||||
{
|
||||
namespace bp = boost::process;
|
||||
string cmd = "../../softWareInit/bin/verification ";
|
||||
cout << cmd << endl;
|
||||
try
|
||||
{
|
||||
bp::child c(cmd);
|
||||
g_soft_pid = c.id();
|
||||
signal(SIGINT, forwardSigint);
|
||||
c.wait(); // 等待子进程结束
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << e.what() << '\n';
|
||||
string sysCmd = cmd + " &";
|
||||
system(sysCmd.c_str());
|
||||
}
|
||||
|
||||
// 退出程序
|
||||
isRunning = false;
|
||||
runCv.notify_one();
|
||||
}
|
||||
|
||||
// 检测设备是否已经激活
|
||||
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 qrcode = GetqrCode();
|
||||
string deviceId = format(R"({"cardNo":"{}","qrcode":"{}"})", ICCID, qrcode);
|
||||
cout << "deviceId:" << 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 << "pass = " << pwd << endl;
|
||||
// 写入文件
|
||||
ReadFile rf(envPath);
|
||||
rf.Open();
|
||||
|
||||
auto lines = rf.ReadLines();
|
||||
|
||||
for (auto &ii : lines)
|
||||
{
|
||||
if (ii.find("ServerPwd:null") != string::npos)
|
||||
ii = format("ServerPwd:{}", pwd);
|
||||
}
|
||||
rf.Close();
|
||||
|
||||
thread([lines]()
|
||||
{
|
||||
lock_guard<mutex> lk(envMutex);
|
||||
|
||||
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);
|
||||
StartCheck(); })
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
|
||||
// 连接成功的回调
|
||||
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)
|
||||
{
|
||||
// 非阻塞打开,避免因 VMIN/VTIME 卡死
|
||||
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);
|
||||
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
|
||||
options.c_oflag &= ~OPOST;
|
||||
options.c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||
options.c_cc[VMIN] = 0;
|
||||
options.c_cc[VTIME] = 5; // 0.5s
|
||||
tcsetattr(fd, TCSANOW, &options);
|
||||
|
||||
auto send_and_read = [&](const char *cmd) -> std::string
|
||||
{
|
||||
// 清空缓冲并发送
|
||||
tcflush(fd, TCIOFLUSH);
|
||||
write(fd, cmd, strlen(cmd));
|
||||
std::string result;
|
||||
char buf[256] = {0};
|
||||
// 轮询读取,累计约2秒
|
||||
for (int i = 0; i < 20; ++i)
|
||||
{
|
||||
int n = read(fd, buf, sizeof(buf));
|
||||
if (n > 0)
|
||||
result.append(buf, n);
|
||||
usleep(100000);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// 先试 AT+QCCID,失败再试 AT+CCID
|
||||
std::string result = send_and_read("AT+QCCID\r\n");
|
||||
if (result.find("+QCCID") == std::string::npos)
|
||||
{
|
||||
std::string r2 = send_and_read("AT+CCID\r\n");
|
||||
if (!r2.empty())
|
||||
result += r2;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
// 打印原始回应便于调试
|
||||
std::string debug = result;
|
||||
// 清理换行
|
||||
debug.erase(std::remove_if(debug.begin(), debug.end(),
|
||||
[](unsigned char c)
|
||||
{ return c == '\r' || c == '\n'; }),
|
||||
debug.end());
|
||||
// std::cout << "ICCID原始回应: " << debug << std::endl;
|
||||
|
||||
// 错误重试
|
||||
if (result.find("ERROR") != std::string::npos)
|
||||
{
|
||||
retry++;
|
||||
usleep(200000);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 解析(支持字母数字)
|
||||
std::smatch m;
|
||||
// +QCCID 或 +CCID 后取字母数字
|
||||
std::regex reg(R"(\+(?:Q)?CCID:\s*([0-9A-Za-z]+))");
|
||||
if (std::regex_search(debug, m, reg))
|
||||
{
|
||||
std::string iccid = m[1];
|
||||
// 去掉尾部OK或非字母数字
|
||||
while (!iccid.empty() && !std::isalnum(static_cast<unsigned char>(iccid.back())))
|
||||
iccid.pop_back();
|
||||
if (iccid.size() >= 2 && iccid.substr(iccid.size() - 2) == "OK")
|
||||
iccid.erase(iccid.size() - 2);
|
||||
return iccid;
|
||||
}
|
||||
|
||||
// 兜底:19~22位的字母数字(如尾部含 D)
|
||||
std::regex reg2(R"(([0-9A-Za-z]{19,22}))");
|
||||
if (std::regex_search(debug, m, reg2))
|
||||
{
|
||||
std::string iccid = m[1];
|
||||
while (!iccid.empty() && !std::isalnum(static_cast<unsigned char>(iccid.back())))
|
||||
iccid.pop_back();
|
||||
if (iccid.size() >= 2 && iccid.substr(iccid.size() - 2) == "OK")
|
||||
iccid.erase(iccid.size() - 2);
|
||||
return iccid;
|
||||
}
|
||||
|
||||
// 进一步兜底:手工截取 +QCCID: / +CCID: 后的连续字母数字
|
||||
auto parse_after = [&](const std::string &s, const std::string &key) -> std::string
|
||||
{
|
||||
size_t pos = s.find(key);
|
||||
if (pos == std::string::npos)
|
||||
return "";
|
||||
pos += key.size();
|
||||
while (pos < s.size() && std::isspace(static_cast<unsigned char>(s[pos])))
|
||||
pos++;
|
||||
size_t start = pos;
|
||||
while (pos < s.size() && std::isalnum(static_cast<unsigned char>(s[pos])))
|
||||
pos++;
|
||||
std::string iccid = (pos > start) ? s.substr(start, pos - start) : "";
|
||||
if (iccid.size() >= 2 && iccid.substr(iccid.size() - 2) == "OK")
|
||||
iccid.erase(iccid.size() - 2);
|
||||
return iccid;
|
||||
};
|
||||
{
|
||||
std::string iccid = parse_after(debug, "+QCCID:");
|
||||
if (iccid.empty())
|
||||
iccid = parse_after(debug, "+CCID:");
|
||||
if (!iccid.empty())
|
||||
return iccid;
|
||||
}
|
||||
|
||||
retry++;
|
||||
usleep(200000);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
8
DeviceActivate/src/makefile
Normal file
8
DeviceActivate/src/makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
all:init
|
||||
|
||||
init:main.cpp
|
||||
g++ -g -o init main.cpp -lpaho-mqttpp3 -lpaho-mqtt3a -lpthread /home/orangepi/RKApp/DeviceActivate/NetraLib/src/Netra.cpp -I/home/orangepi/RKApp/DeviceActivate/NetraLib/include
|
||||
mv init ../bin/
|
||||
|
||||
clean:
|
||||
rm -rf ../bin/init
|
||||
Reference in New Issue
Block a user