/* 本程序主要用于初始化网络配置,使4g模块可以正常上网 */ #include #include #include #include #include #include #include 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(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); }