添加读取IMEI的逻辑
This commit is contained in:
parent
97e9efb262
commit
882a0e0b51
5
include/serail_AT.hpp
Normal file
5
include/serail_AT.hpp
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "serial_port.h"
|
||||
|
||||
void init_serial_at(const std::string& device, int baudrate);
|
||||
54
include/serial_port.h
Normal file
54
include/serial_port.h
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "logger.hpp"
|
||||
|
||||
class SerialPort
|
||||
{
|
||||
public:
|
||||
using ReceiveCallback = std::function<void(const std::vector<uint8_t>&)>;
|
||||
using ReceiveStringCallback = std::function<void(const std::string&)>;
|
||||
|
||||
SerialPort(const std::string& id, const std::string& device, int baudrate, int retry_interval = 5);
|
||||
|
||||
~SerialPort();
|
||||
|
||||
void start(); // 启动串口(含自动重连)
|
||||
void stop(); // 停止串口
|
||||
|
||||
bool is_open() const;
|
||||
bool send_data(const std::vector<uint8_t>& data);
|
||||
bool send_data(const std::string& data);
|
||||
|
||||
void set_receive_callback(ReceiveCallback cb);
|
||||
void set_receive_callback(ReceiveStringCallback cb);
|
||||
|
||||
private:
|
||||
bool open_port();
|
||||
void close_port();
|
||||
void reader_loop();
|
||||
void reconnect_loop();
|
||||
bool configure_port(int fd);
|
||||
|
||||
private:
|
||||
std::string id_;
|
||||
std::string device_;
|
||||
int baudrate_;
|
||||
int fd_ = -1;
|
||||
|
||||
std::atomic<bool> running_{false};
|
||||
std::atomic<bool> stop_flag_{false};
|
||||
|
||||
std::thread reader_thread_;
|
||||
std::thread reconnect_thread_;
|
||||
std::mutex send_mutex_;
|
||||
|
||||
ReceiveCallback receive_callback_;
|
||||
int retry_interval_;
|
||||
};
|
||||
@ -11,6 +11,7 @@
|
||||
#include "mqtt_client_wrapper.hpp"
|
||||
#include "record_manager.hpp"
|
||||
#include "rtmp_manager.hpp"
|
||||
#include "serail_AT.hpp"
|
||||
|
||||
std::atomic<bool> g_running(true);
|
||||
|
||||
@ -51,6 +52,8 @@ int main()
|
||||
return -1;
|
||||
}
|
||||
|
||||
init_serial_at("/dev/ttyUSB3", 115200);
|
||||
|
||||
// ---------- 初始化 GStreamer ----------
|
||||
RTMPManager::init();
|
||||
|
||||
|
||||
133
src/serial_AT.cpp
Normal file
133
src/serial_AT.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "serail_AT.hpp"
|
||||
|
||||
// ================== 全局 IMEI ==================
|
||||
std::string IMEI = ""; // 一般 15 位
|
||||
|
||||
// ================== AT 任务结构 ==================
|
||||
struct AtTask
|
||||
{
|
||||
std::string cmd;
|
||||
int interval; // 周期,秒;0 表示一次性任务
|
||||
int max_retries; // -1 表示无限次
|
||||
int sent_count;
|
||||
std::chrono::steady_clock::time_point last_sent;
|
||||
};
|
||||
|
||||
static std::unique_ptr<SerialPort> serial_at;
|
||||
static std::thread serial_at_sender;
|
||||
|
||||
static std::mutex at_tasks_mutex;
|
||||
|
||||
// ================== AT 任务列表 ==================
|
||||
static std::vector<AtTask> at_tasks = {
|
||||
{"AT+GSN", 0, 3, 0, {}} // 查询 IMEI,最多重试 3 次
|
||||
};
|
||||
|
||||
// ================== 发送线程 ==================
|
||||
static void serial_at_send_loop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (serial_at && serial_at->is_open())
|
||||
{
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
std::lock_guard<std::mutex> lock(at_tasks_mutex);
|
||||
|
||||
for (auto it = at_tasks.begin(); it != at_tasks.end();)
|
||||
{
|
||||
auto& task = *it;
|
||||
bool should_send = false;
|
||||
|
||||
if (task.interval > 0)
|
||||
{
|
||||
if (task.last_sent.time_since_epoch().count() == 0 ||
|
||||
std::chrono::duration_cast<std::chrono::seconds>(now - task.last_sent).count() >= task.interval)
|
||||
{
|
||||
should_send = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((task.max_retries < 0 || task.sent_count < task.max_retries) &&
|
||||
(task.last_sent.time_since_epoch().count() == 0 ||
|
||||
std::chrono::duration_cast<std::chrono::seconds>(now - task.last_sent).count() >= 5))
|
||||
{
|
||||
should_send = true;
|
||||
}
|
||||
else if (task.max_retries > 0 && task.sent_count >= task.max_retries)
|
||||
{
|
||||
LOG_ERROR("[serial_at] AT+GSN reached max retries");
|
||||
|
||||
// IMEI 获取失败,仍继续初始化
|
||||
init_tcp_client_tbox_router(TboxConfigManager::instance().getPlatformIp(),
|
||||
TboxConfigManager::instance().getPlatformPort());
|
||||
|
||||
it = at_tasks.erase(it);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (should_send)
|
||||
{
|
||||
serial_at->send_data(task.cmd + "\r\n");
|
||||
task.sent_count++;
|
||||
task.last_sent = now;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
// ================== 接收处理 ==================
|
||||
static void handle_serial_at_data(const std::string& data)
|
||||
{
|
||||
// 拆行处理,避免粘包
|
||||
std::istringstream iss(data);
|
||||
std::string line;
|
||||
|
||||
while (std::getline(iss, line))
|
||||
{
|
||||
// 去空白
|
||||
line.erase(0, line.find_first_not_of(" \t\r\n"));
|
||||
line.erase(line.find_last_not_of(" \t\r\n") + 1);
|
||||
|
||||
// IMEI 通常是 15 位纯数字
|
||||
if (line.size() >= 14 && line.size() <= 17 && std::all_of(line.begin(), line.end(), ::isdigit))
|
||||
{
|
||||
IMEI = line;
|
||||
|
||||
LOG_INFO("[serial_at] Extracted IMEI = " + IMEI);
|
||||
|
||||
init_tcp_client_tbox_router(TboxConfigManager::instance().getPlatformIp(),
|
||||
TboxConfigManager::instance().getPlatformPort());
|
||||
|
||||
// 移除 AT+GSN 任务
|
||||
std::lock_guard<std::mutex> lock(at_tasks_mutex);
|
||||
at_tasks.erase(std::remove_if(at_tasks.begin(), at_tasks.end(),
|
||||
[](const AtTask& task) { return task.cmd == "AT+GSN"; }),
|
||||
at_tasks.end());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ================== 初始化接口 ==================
|
||||
void init_serial_at(const std::string& device, int baudrate)
|
||||
{
|
||||
serial_at = std::make_unique<SerialPort>("serial_at", device, baudrate, 5);
|
||||
|
||||
serial_at->set_receive_callback(handle_serial_at_data);
|
||||
serial_at->start();
|
||||
|
||||
serial_at_sender = std::thread(serial_at_send_loop);
|
||||
serial_at_sender.detach();
|
||||
}
|
||||
191
src/serial_port.cpp
Normal file
191
src/serial_port.cpp
Normal file
@ -0,0 +1,191 @@
|
||||
#include "serial_port.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
|
||||
// --------- 波特率映射 ---------
|
||||
static speed_t baud_to_speed(int baud)
|
||||
{
|
||||
switch (baud)
|
||||
{
|
||||
case 9600:
|
||||
return B9600;
|
||||
case 19200:
|
||||
return B19200;
|
||||
case 38400:
|
||||
return B38400;
|
||||
case 57600:
|
||||
return B57600;
|
||||
case 115200:
|
||||
return B115200;
|
||||
#ifdef B230400
|
||||
case 230400:
|
||||
return B230400;
|
||||
#endif
|
||||
default:
|
||||
return B115200;
|
||||
}
|
||||
}
|
||||
|
||||
SerialPort::SerialPort(const std::string& id, const std::string& device, int baudrate, int retry_interval)
|
||||
: id_(id), device_(device), baudrate_(baudrate), retry_interval_(retry_interval)
|
||||
{
|
||||
}
|
||||
|
||||
SerialPort::~SerialPort() { stop(); }
|
||||
|
||||
void SerialPort::start()
|
||||
{
|
||||
stop_flag_ = false;
|
||||
reconnect_thread_ = std::thread(&SerialPort::reconnect_loop, this);
|
||||
}
|
||||
|
||||
void SerialPort::stop()
|
||||
{
|
||||
stop_flag_ = true;
|
||||
running_ = false;
|
||||
|
||||
if (reader_thread_.joinable()) reader_thread_.join();
|
||||
|
||||
if (reconnect_thread_.joinable()) reconnect_thread_.join();
|
||||
|
||||
close_port();
|
||||
}
|
||||
|
||||
bool SerialPort::open_port()
|
||||
{
|
||||
fd_ = open(device_.c_str(), O_RDWR | O_NOCTTY | O_SYNC);
|
||||
if (fd_ < 0)
|
||||
{
|
||||
LOG_ERROR("[" + id_ + "] Failed to open " + device_ + ": " + strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!configure_port(fd_))
|
||||
{
|
||||
LOG_ERROR("[" + id_ + "] Failed to configure " + device_);
|
||||
close(fd_);
|
||||
fd_ = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
running_ = true;
|
||||
reader_thread_ = std::thread(&SerialPort::reader_loop, this);
|
||||
|
||||
LOG_INFO("[" + id_ + "] Opened serial port " + device_ + " at " + std::to_string(baudrate_) + " baud");
|
||||
return true;
|
||||
}
|
||||
|
||||
void SerialPort::close_port()
|
||||
{
|
||||
running_ = false;
|
||||
|
||||
if (fd_ >= 0)
|
||||
{
|
||||
close(fd_);
|
||||
fd_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool SerialPort::is_open() const { return fd_ >= 0; }
|
||||
|
||||
bool SerialPort::send_data(const std::vector<uint8_t>& data)
|
||||
{
|
||||
if (fd_ < 0) return false;
|
||||
|
||||
std::lock_guard<std::mutex> lock(send_mutex_);
|
||||
ssize_t n = write(fd_, data.data(), data.size());
|
||||
return n == static_cast<ssize_t>(data.size());
|
||||
}
|
||||
|
||||
bool SerialPort::send_data(const std::string& data)
|
||||
{
|
||||
return send_data(std::vector<uint8_t>(data.begin(), data.end()));
|
||||
}
|
||||
|
||||
void SerialPort::set_receive_callback(ReceiveCallback cb) { receive_callback_ = std::move(cb); }
|
||||
|
||||
void SerialPort::set_receive_callback(ReceiveStringCallback cb)
|
||||
{
|
||||
receive_callback_ = [cb](const std::vector<uint8_t>& data) { cb(std::string(data.begin(), data.end())); };
|
||||
}
|
||||
|
||||
void SerialPort::reader_loop()
|
||||
{
|
||||
std::vector<uint8_t> buffer(1024);
|
||||
|
||||
while (running_ && !stop_flag_)
|
||||
{
|
||||
int n = read(fd_, buffer.data(), buffer.size());
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
if (receive_callback_) receive_callback_({buffer.begin(), buffer.begin() + n});
|
||||
}
|
||||
else if (n < 0)
|
||||
{
|
||||
LOG_ERROR("[" + id_ + "] Read error: " + std::string(strerror(errno)));
|
||||
break;
|
||||
}
|
||||
// n == 0:超时,正常情况,继续读
|
||||
}
|
||||
|
||||
running_ = false;
|
||||
}
|
||||
|
||||
void SerialPort::reconnect_loop()
|
||||
{
|
||||
int current_interval = retry_interval_;
|
||||
const int max_interval = 300;
|
||||
|
||||
while (!stop_flag_)
|
||||
{
|
||||
if (open_port())
|
||||
{
|
||||
// 等待读线程结束
|
||||
if (reader_thread_.joinable()) reader_thread_.join();
|
||||
|
||||
close_port();
|
||||
LOG_WARN("[" + id_ + "] Port closed, will retry");
|
||||
|
||||
current_interval = retry_interval_;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_INFO("[" + id_ + "] Connect failed, retry in " + std::to_string(current_interval) + "s");
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(current_interval));
|
||||
current_interval = std::min(current_interval * 2, max_interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SerialPort::configure_port(int fd)
|
||||
{
|
||||
struct termios tty{};
|
||||
if (tcgetattr(fd, &tty) != 0) return false;
|
||||
|
||||
speed_t spd = baud_to_speed(baudrate_);
|
||||
cfsetospeed(&tty, spd);
|
||||
cfsetispeed(&tty, spd);
|
||||
|
||||
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
|
||||
tty.c_iflag &= ~IGNBRK;
|
||||
tty.c_lflag = 0;
|
||||
tty.c_oflag = 0;
|
||||
tty.c_cc[VMIN] = 1;
|
||||
tty.c_cc[VTIME] = 1;
|
||||
|
||||
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||
tty.c_cflag |= (CLOCAL | CREAD);
|
||||
tty.c_cflag &= ~(PARENB | PARODD);
|
||||
tty.c_cflag &= ~CSTOPB;
|
||||
tty.c_cflag &= ~CRTSCTS;
|
||||
|
||||
return tcsetattr(fd, TCSANOW, &tty) == 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user