add some code

This commit is contained in:
2025-09-05 13:25:11 +08:00
parent 9ff0a99e7a
commit 3cf1229a85
8911 changed files with 2535396 additions and 0 deletions

View File

@@ -0,0 +1,99 @@
#ifndef _AT_MODEM_H_
#define _AT_MODEM_H_
#include <cstddef>
#include <string>
#include <vector>
#include <list>
#include <functional>
#include <mutex>
#include <memory>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <freertos/event_groups.h>
#include <driver/gpio.h>
#include <driver/uart.h>
#include "at_uart.h"
#include "network_interface.h"
#define AT_EVENT_PIN_ERROR BIT2
#define AT_EVENT_NETWORK_ERROR BIT3
#define AT_EVENT_NETWORK_READY BIT4
enum class NetworkStatus {
ErrorInsertPin = -1,
ErrorRegistrationDenied = -2,
ErrorTimeout = -3,
Ready = 0,
Error = 1,
};
struct CeregState {
int stat = 0; // <stat>
std::string tac; // <tac>
std::string ci; // <ci>
int AcT = -1; // <AcT>
std::string ToString() const {
std::string json = "{";
json += "\"stat\":" + std::to_string(stat);
if (!tac.empty()) json += ",\"tac\":\"" + tac + "\"";
if (!ci.empty()) json += ",\"ci\":\"" + ci + "\"";
if (AcT >= 0) json += ",\"AcT\":" + std::to_string(AcT);
json += "}";
return json;
}
};
class AtModem : public NetworkInterface {
public:
// 静态检测方法
static std::unique_ptr<AtModem> Detect(gpio_num_t tx_pin, gpio_num_t rx_pin, gpio_num_t dtr_pin = GPIO_NUM_NC, int baud_rate = 115200);
// 构造函数和析构函数
AtModem(std::shared_ptr<AtUart> at_uart);
virtual ~AtModem();
std::shared_ptr<AtUart> GetAtUart() { return at_uart_; }
void OnNetworkStateChanged(std::function<void(bool network_ready)> callback);
// 网络状态管理
virtual void Reboot();
virtual NetworkStatus WaitForNetworkReady(int timeout_ms = -1);
virtual bool SetSleepMode(bool enable, int delay_seconds=0);
virtual void SetFlightMode(bool enable);
// 模组信息获取
std::string GetImei();
std::string GetIccid();
std::string GetModuleRevision();
CeregState GetRegistrationState();
std::string GetCarrierName();
int GetCsq();
// 状态查询
bool pin_ready() const { return pin_ready_; }
bool network_ready() const { return network_ready_; }
protected:
std::shared_ptr<AtUart> at_uart_;
std::mutex mutex_;
std::string iccid_;
std::string imei_;
std::string carrier_name_;
std::string module_revision_;
int csq_ = -1;
bool pin_ready_ = true;
bool network_ready_ = false;
gpio_num_t dtr_pin_;
EventGroupHandle_t event_group_handle_ = nullptr;
CeregState cereg_state_;
virtual void HandleUrc(const std::string& command, const std::vector<AtArgumentValue>& arguments);
std::function<void(bool network_state)> on_network_state_changed_;
};
#endif // _AT_MODEM_H_

View File

@@ -0,0 +1,123 @@
#ifndef _AT_UART_H_
#define _AT_UART_H_
#include <string>
#include <vector>
#include <functional>
#include <mutex>
#include <list>
#include <cstdlib>
#include <memory>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <freertos/event_groups.h>
#include <driver/gpio.h>
#include <driver/uart.h>
// UART事件定义
#define AT_EVENT_DATA_AVAILABLE BIT1
#define AT_EVENT_COMMAND_DONE BIT2
#define AT_EVENT_COMMAND_ERROR BIT3
// 默认配置
#define UART_NUM UART_NUM_1
// AT命令参数值结构
struct AtArgumentValue {
enum class Type { String, Int, Double };
Type type;
std::string string_value;
int int_value;
double double_value;
std::string ToString() const {
switch (type) {
case Type::String:
return "\"" + string_value + "\"";
case Type::Int:
return std::to_string(int_value);
case Type::Double:
return std::to_string(double_value);
default:
return "";
}
}
};
// 数据接收回调函数类型
typedef std::function<void(const std::string& command, const std::vector<AtArgumentValue>& arguments)> UrcCallback;
class AtUart {
public:
// 构造函数
AtUart(gpio_num_t tx_pin, gpio_num_t rx_pin, gpio_num_t dtr_pin = GPIO_NUM_NC);
~AtUart();
// 初始化和配置
void Initialize();
// 波特率管理
bool SetBaudRate(int new_baud_rate);
int GetBaudRate() const { return baud_rate_; }
// 数据发送
bool SendCommand(const std::string& command, size_t timeout_ms = 1000, bool add_crlf = true);
bool SendCommandWithData(const std::string& command, size_t timeout_ms = 1000, bool add_crlf = true, const char* data = nullptr, size_t data_length = 0);
const std::string& GetResponse() const { return response_; }
int GetCmeErrorCode() const { return cme_error_code_; }
// 回调管理
std::list<UrcCallback>::iterator RegisterUrcCallback(UrcCallback callback);
void UnregisterUrcCallback(std::list<UrcCallback>::iterator iterator);
// 控制接口
void SetDtrPin(bool high);
bool IsInitialized() const { return initialized_; }
std::string EncodeHex(const std::string& data);
std::string DecodeHex(const std::string& data);
void EncodeHexAppend(std::string& dest, const char* data, size_t length);
void DecodeHexAppend(std::string& dest, const char* data, size_t length);
private:
// 配置参数
gpio_num_t tx_pin_;
gpio_num_t rx_pin_;
gpio_num_t dtr_pin_;
uart_port_t uart_num_;
int baud_rate_;
bool initialized_;
int cme_error_code_ = 0;
std::string response_;
bool wait_for_response_ = false;
std::mutex command_mutex_;
std::mutex mutex_;
// FreeRTOS 对象
TaskHandle_t event_task_handle_ = nullptr;
TaskHandle_t receive_task_handle_ = nullptr;
QueueHandle_t event_queue_handle_;
EventGroupHandle_t event_group_handle_;
std::string rx_buffer_;
// 回调函数
std::list<UrcCallback> urc_callbacks_;
// 内部方法
void EventTask();
void ReceiveTask();
bool ParseResponse();
bool DetectBaudRate();
// 处理 AT 命令
void HandleCommand(const char* command);
// 处理 URC
void HandleUrc(const std::string& command, const std::vector<AtArgumentValue>& arguments);
bool SendData(const char* data, size_t length);
// 静态任务函数
static void EventTaskWrapper(void* arg);
};
#endif // _AT_UART_H_

View File

@@ -0,0 +1,19 @@
#ifndef ESP_NETWORK_H
#define ESP_NETWORK_H
#include "network_interface.h"
class EspNetwork : public NetworkInterface {
public:
EspNetwork();
~EspNetwork();
std::unique_ptr<Http> CreateHttp(int connect_id = -1) override;
std::unique_ptr<Tcp> CreateTcp(int connect_id = -1) override;
std::unique_ptr<Tcp> CreateSsl(int connect_id = -1) override;
std::unique_ptr<Udp> CreateUdp(int connect_id = -1) override;
std::unique_ptr<Mqtt> CreateMqtt(int connect_id = -1) override;
std::unique_ptr<WebSocket> CreateWebSocket(int connect_id = -1) override;
};
#endif // ESP_NETWORK_H

View File

@@ -0,0 +1,46 @@
#ifndef HTTP_H
#define HTTP_H
#include <string>
#include <map>
#include <functional>
class Http {
public:
virtual ~Http() = default;
// Set timeout
virtual void SetTimeout(int timeout_ms) = 0;
// 设置 HTTP 请求头
virtual void SetHeader(const std::string& key, const std::string& value) = 0;
// 设置 HTTP Content
virtual void SetContent(std::string&& content) = 0;
// 打开 HTTP 连接并发送请求
virtual bool Open(const std::string& method, const std::string& url) = 0;
// 关闭 HTTP 连接
virtual void Close() = 0;
// 读取 HTTP 响应数据
virtual int Read(char* buffer, size_t buffer_size) = 0;
// 写入 HTTP 请求数据
virtual int Write(const char* buffer, size_t buffer_size) = 0;
// 获取 HTTP 响应状态码
virtual int GetStatusCode() = 0;
// 获取指定 key 的 HTTP 响应头
virtual std::string GetResponseHeader(const std::string& key) const = 0;
// 获取 HTTP 响应体长度
virtual size_t GetBodyLength() = 0;
// 获取 HTTP 响应体
virtual std::string ReadAll() = 0;
};
#endif // HTTP_H

View File

@@ -0,0 +1,156 @@
#ifndef HTTP_CLIENT_H
#define HTTP_CLIENT_H
#include "http.h"
#include "tcp.h"
#include <freertos/FreeRTOS.h>
#include <freertos/event_groups.h>
#include <map>
#include <string>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <optional>
#include <memory>
#include <deque>
#include <cstring>
#define EC801E_HTTP_EVENT_HEADERS_RECEIVED (1 << 0)
#define EC801E_HTTP_EVENT_BODY_RECEIVED (1 << 1)
#define EC801E_HTTP_EVENT_ERROR (1 << 2)
#define EC801E_HTTP_EVENT_COMPLETE (1 << 3)
class NetworkInterface;
class HttpClient : public Http {
public:
HttpClient(NetworkInterface* network, int connect_id = 0);
~HttpClient();
void SetTimeout(int timeout_ms) override;
void SetHeader(const std::string& key, const std::string& value) override;
void SetContent(std::string&& content) override;
bool Open(const std::string& method, const std::string& url) override;
void Close() override;
int Read(char* buffer, size_t buffer_size) override;
int Write(const char* buffer, size_t buffer_size) override;
int GetStatusCode() override;
std::string GetResponseHeader(const std::string& key) const override;
size_t GetBodyLength() override;
std::string ReadAll() override;
private:
// 数据块结构,用于队列缓冲
struct DataChunk {
std::string data;
size_t offset = 0; // 当前读取偏移
// 使用移动构造函数避免拷贝
DataChunk(std::string&& d) : data(std::move(d)), offset(0) {}
DataChunk(const std::string& d) : data(d), offset(0) {}
size_t available() const {
return data.size() - offset;
}
size_t read(char* buffer, size_t size) {
size_t bytes_to_read = std::min(size, available());
if (bytes_to_read > 0) {
memcpy(buffer, data.data() + offset, bytes_to_read);
offset += bytes_to_read;
}
return bytes_to_read;
}
bool empty() const {
return offset >= data.size();
}
};
// 头部条目结构体,用于高效存储和查找
struct HeaderEntry {
std::string original_key; // 保留原始大小写的key用于输出HTTP头部
std::string value; // 头部值
HeaderEntry() = default;
HeaderEntry(const std::string& key, const std::string& val)
: original_key(key), value(val) {}
};
NetworkInterface* network_;
int connect_id_;
std::unique_ptr<Tcp> tcp_;
EventGroupHandle_t event_group_handle_;
std::mutex mutex_;
std::condition_variable cv_;
// 用于读取操作的专门锁和缓冲区队列
std::mutex read_mutex_;
std::deque<DataChunk> body_chunks_;
std::condition_variable write_cv_;
const size_t MAX_BODY_CHUNKS_SIZE = 8192;
int status_code_ = -1;
int timeout_ms_ = 30000;
std::string rx_buffer_;
std::map<std::string, HeaderEntry> headers_; // key为小写用于快速查找
std::string url_;
std::string method_;
std::string protocol_;
std::string host_;
std::string path_;
int port_ = 80;
std::optional<std::string> content_ = std::nullopt;
std::map<std::string, HeaderEntry> response_headers_; // key为小写用于快速查找
// 移除原来的 body_ 变量,现在使用 body_chunks_ 队列
size_t body_offset_ = 0;
size_t content_length_ = 0;
size_t total_body_received_ = 0; // 总共接收的响应体字节数
bool eof_ = false;
bool connected_ = false;
bool headers_received_ = false;
bool request_chunked_ = false;
bool response_chunked_ = false;
bool connection_error_ = false; // 新增:标记连接是否异常断开
// HTTP 协议解析状态
enum class ParseState {
STATUS_LINE,
HEADERS,
BODY,
CHUNK_SIZE,
CHUNK_DATA,
CHUNK_TRAILER,
COMPLETE
};
ParseState parse_state_ = ParseState::STATUS_LINE;
size_t chunk_size_ = 0;
size_t chunk_received_ = 0;
// 私有方法
bool ParseUrl(const std::string& url);
std::string BuildHttpRequest();
void OnTcpData(const std::string& data);
void OnTcpDisconnected();
void ProcessReceivedData();
bool ParseStatusLine(const std::string& line);
bool ParseHeaderLine(const std::string& line);
void ParseChunkedBody(const std::string& data);
void ParseRegularBody(const std::string& data);
size_t ParseChunkSize(const std::string& chunk_size_line);
std::string GetNextLine(std::string& buffer);
bool HasCompleteLine(const std::string& buffer);
void SetError();
// 新增:向读取队列添加数据的方法
void AddBodyData(const std::string& data);
void AddBodyData(std::string&& data); // 移动版本
// 新增:检查数据是否完整接收
bool IsDataComplete() const;
};
#endif

View File

@@ -0,0 +1,32 @@
#ifndef MQTT_INTERFACE_H
#define MQTT_INTERFACE_H
#include <string>
#include <functional>
class Mqtt {
public:
virtual ~Mqtt() {}
void SetKeepAlive(int keep_alive_seconds) { keep_alive_seconds_ = keep_alive_seconds; }
virtual bool Connect(const std::string broker_address, int broker_port, const std::string client_id, const std::string username, const std::string password) = 0;
virtual void Disconnect() = 0;
virtual bool Publish(const std::string topic, const std::string payload, int qos = 0) = 0;
virtual bool Subscribe(const std::string topic, int qos = 0) = 0;
virtual bool Unsubscribe(const std::string topic) = 0;
virtual bool IsConnected() = 0;
virtual void OnConnected(std::function<void()> callback) { on_connected_callback_ = std::move(callback); }
virtual void OnDisconnected(std::function<void()> callback) { on_disconnected_callback_ = std::move(callback); }
virtual void OnMessage(std::function<void(const std::string& topic, const std::string& payload)> callback) { on_message_callback_ = std::move(callback); }
virtual void OnError(std::function<void(const std::string& error)> callback) { on_error_callback_ = std::move(callback); }
protected:
int keep_alive_seconds_ = 120;
std::function<void(const std::string& topic, const std::string& payload)> on_message_callback_;
std::function<void()> on_connected_callback_;
std::function<void()> on_disconnected_callback_;
std::function<void(const std::string& error)> on_error_callback_;
};
#endif // MQTT_INTERFACE_H

View File

@@ -0,0 +1,24 @@
#ifndef NETWORK_INTERFACE_H
#define NETWORK_INTERFACE_H
#include <memory>
#include "http.h"
#include "tcp.h"
#include "udp.h"
#include "mqtt.h"
#include "web_socket.h"
class NetworkInterface {
public:
virtual ~NetworkInterface() = default;
// 连接创建接口(纯虚函数,由子类实现)
virtual std::unique_ptr<Http> CreateHttp(int connect_id = -1) = 0;
virtual std::unique_ptr<Tcp> CreateTcp(int connect_id = -1) = 0;
virtual std::unique_ptr<Tcp> CreateSsl(int connect_id = -1) = 0;
virtual std::unique_ptr<Udp> CreateUdp(int connect_id = -1) = 0;
virtual std::unique_ptr<Mqtt> CreateMqtt(int connect_id = -1) = 0;
virtual std::unique_ptr<WebSocket> CreateWebSocket(int connect_id = -1) = 0;
};
#endif // NETWORK_INTERFACE_H

View File

@@ -0,0 +1,34 @@
#ifndef TCP_H
#define TCP_H
#include <string>
#include <functional>
class Tcp {
public:
virtual ~Tcp() = default;
virtual bool Connect(const std::string& host, int port) = 0;
virtual void Disconnect() = 0;
virtual int Send(const std::string& data) = 0;
virtual void OnStream(std::function<void(const std::string& data)> callback) {
stream_callback_ = callback;
}
virtual void OnDisconnected(std::function<void()> callback) {
disconnect_callback_ = callback;
}
// 连接状态查询
bool connected() const { return connected_; }
protected:
std::function<void(const std::string& data)> stream_callback_;
std::function<void()> disconnect_callback_;
// 连接状态管理
bool connected_ = false; // 是否可以正常读写数据
};
#endif // TCP_H

View File

@@ -0,0 +1,25 @@
#ifndef UDP_H
#define UDP_H
#include <string>
#include <functional>
class Udp {
public:
virtual ~Udp() = default;
virtual bool Connect(const std::string& host, int port) = 0;
virtual void Disconnect() = 0;
virtual int Send(const std::string& data) = 0;
virtual void OnMessage(std::function<void(const std::string& data)> callback) {
message_callback_ = std::move(callback);
}
bool connected() const { return connected_; }
protected:
std::function<void(const std::string& data)> message_callback_;
bool connected_ = false;
};
#endif // UDP_H

View File

@@ -0,0 +1,59 @@
#ifndef WEBSOCKET_H
#define WEBSOCKET_H
#include <functional>
#include <string>
#include <map>
#include <thread>
#include <freertos/FreeRTOS.h>
#include <freertos/event_groups.h>
#include "tcp.h"
class NetworkInterface;
class WebSocket {
public:
WebSocket(NetworkInterface* network, int connect_id);
~WebSocket();
void SetHeader(const char* key, const char* value);
void SetReceiveBufferSize(size_t size);
bool IsConnected() const;
bool Connect(const char* uri);
bool Send(const std::string& data);
bool Send(const void* data, size_t len, bool binary = false, bool fin = true);
void Ping();
void Close();
void OnConnected(std::function<void()> callback);
void OnDisconnected(std::function<void()> callback);
void OnData(std::function<void(const char*, size_t, bool binary)> callback);
void OnError(std::function<void(int)> callback);
private:
NetworkInterface* network_;
int connect_id_;
std::unique_ptr<Tcp> tcp_;
bool continuation_ = false;
size_t receive_buffer_size_ = 2048;
std::string receive_buffer_;
bool handshake_completed_ = false;
bool connected_ = false;
// FreeRTOS 事件组用于同步握手
EventGroupHandle_t handshake_event_group_;
static const EventBits_t HANDSHAKE_SUCCESS_BIT = BIT0;
static const EventBits_t HANDSHAKE_FAILED_BIT = BIT1;
std::map<std::string, std::string> headers_;
std::function<void(const char*, size_t, bool binary)> on_data_;
std::function<void(int)> on_error_;
std::function<void()> on_connected_;
std::function<void()> on_disconnected_;
void OnTcpData(const std::string& data);
bool SendControlFrame(uint8_t opcode, const void* data, size_t len);
};
#endif // WEBSOCKET_H