Files
RkApp/GetNet/src/GetNet.cpp
2025-10-15 12:12:21 +08:00

229 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.

/*
本程序主要用于初始化网络配置,使4g模块可以正常上网
*/
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <poll.h>
#include <cstring>
#include <thread>
using namespace std;
// 串口设备
string Serious = "/dev/ttyUSB2";
// 设置网络
void SetNet();
int main(int argc, char *argv[])
{
this_thread::sleep_for(chrono::seconds(3));
SetNet();
return 0;
}
// 设置网络
void SetNet()
{
auto configure_serial = [](int fd) -> bool
{
struct termios options;
if (tcgetattr(fd, &options) != 0)
return false;
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB; // 无校验
options.c_cflag &= ~CSTOPB; // 1 位停止位
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8; // 8 位数据位
options.c_cflag &= ~CRTSCTS; // 关闭硬件流控
options.c_iflag &= ~(IXON | IXOFF | IXANY); // 关闭软件流控
options.c_iflag &= ~(INLCR | ICRNL);
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 原始模式
options.c_oflag &= ~OPOST; // 原始输出
options.c_cc[VMIN] = 0; // 非阻塞读取
options.c_cc[VTIME] = 10; // 1.0s 读超时
if (tcsetattr(fd, TCSANOW, &options) != 0)
return false;
tcflush(fd, TCIOFLUSH);
return true;
};
auto write_all = [](int fd, const std::string &data) -> bool
{
const char *p = data.c_str();
size_t left = data.size();
while (left > 0)
{
ssize_t n = write(fd, p, left);
if (n < 0)
{
if (errno == EINTR)
continue;
return false;
}
left -= static_cast<size_t>(n);
p += n;
}
return true;
};
auto send_at = [&](int fd, const std::string &cmd, std::string &resp, int timeout_ms = 3000) -> bool
{
std::string line = cmd + "\r\n";
if (!write_all(fd, line))
return false;
resp.clear();
char buf[256];
int elapsed = 0;
while (elapsed < timeout_ms)
{
struct pollfd pfd{fd, POLLIN, 0};
int pr = poll(&pfd, 1, 200);
if (pr > 0 && (pfd.revents & POLLIN))
{
ssize_t n = read(fd, buf, sizeof(buf));
if (n > 0)
{
resp.append(buf, buf + n);
if (resp.find("\r\nOK\r\n") != std::string::npos ||
resp.find("\nOK\n") != std::string::npos ||
resp.find("OK") != std::string::npos)
return true;
if (resp.find("ERROR") != std::string::npos)
return false;
}
}
elapsed += 200;
}
return false; // 超时
};
int fd = open(Serious.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd < 0)
{
std::cerr << "无法打开串口: " << Serious << "\n";
return;
}
// 设为阻塞
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
if (!configure_serial(fd))
{
std::cerr << "串口参数配置失败\n";
close(fd);
return;
}
std::string resp;
// 0) 连续握手,确保 AT 可用(最多 10 次)
{
bool ok = false;
for (int i = 1; i <= 10; ++i)
{
if (send_at(fd, "AT", resp, 500))
{
ok = true;
break;
}
usleep(500 * 1000);
}
if (!ok)
{
std::cerr << "AT 握手失败,模块未响应\n";
close(fd);
return;
}
}
// 1) 打开功能
if (!send_at(fd, "AT+CFUN=1", resp))
{
std::cerr << "AT+CFUN=1 失败: " << resp << "\n";
}
else
{
std::cout << "AT+CFUN=1 OK\n";
}
// 1.1) 等 SIM 就绪AT+CPIN? 返回 READY最多 30 秒)
{
bool ready = false;
for (int i = 0; i < 60; ++i)
{
if (send_at(fd, "AT+CPIN?", resp, 500) && resp.find("READY") != std::string::npos)
{
ready = true;
break;
}
usleep(500 * 1000);
}
if (!ready)
std::cerr << "SIM 未就绪,后续可能失败\n";
}
// 2) 设置 PDP 上下文APN = ipn请按运营商实际 APN 调整)
if (!send_at(fd, "AT+CGDCONT=1,\"IP\",\"ipn\"", resp))
{
std::cerr << "AT+CGDCONT 设置失败: " << resp << "\n";
}
else
{
std::cout << "AT+CGDCONT OK\n";
}
// 2.1) 等驻网AT+CEREG? 返回 ,1 或 ,5最多 60 秒)
{
auto registered = [](const std::string &s)
{ return s.find(",1") != std::string::npos || s.find(",5") != std::string::npos; };
bool ok = false;
for (int i = 0; i < 60; ++i)
{
if (send_at(fd, "AT+CEREG?", resp, 500) && registered(resp))
{
ok = true;
break;
}
usleep(1000 * 1000);
}
if (!ok)
std::cerr << "未驻网,继续尝试拨号但成功率较低\n";
}
// 3) 打开网卡/拨号Quectel 私有指令示例)- 失败重试 5 次
{
bool ok = false;
for (int attempt = 1; attempt <= 5; ++attempt)
{
resp.clear();
if (send_at(fd, "AT+QNETDEVCTL=1,1,1", resp))
{
std::cout << "AT+QNETDEVCTL OK (attempt " << attempt << ")\n";
ok = true;
break;
}
std::cerr << "AT+QNETDEVCTL 失败 (attempt " << attempt << "/5): " << resp << "\n";
usleep(1000 * 1000); // 1s 间隔
}
if (!ok)
{
std::cerr << "AT+QNETDEVCTL 连续 5 次失败,退出本步骤\n";
}
}
close(fd);
}