Skip to content

11.esp8266面向对象的封装

约 2214 字大约 7 分钟

2025-08-20


/* ============================================================================
 * ESP8266面向对象封装 - 头文件
 * 文件: esp8266_oop.h
 * ============================================================================ */
#ifndef __ESP8266_OOP_H__
#define __ESP8266_OOP_H__

#include <stdint.h>
#include <stdbool.h>
#include <string.h>

/* 常量定义 */
#define ESP8266_SSID_MAX_LEN        32
#define ESP8266_PASSWORD_MAX_LEN    64
#define ESP8266_IP_STR_LEN          16
#define ESP8266_MAC_STR_LEN         18
#define ESP8266_BUFFER_SIZE         256

/* 枚举定义 */
typedef enum {
    ESP8266_OK = 0,
    ESP8266_ERROR,
    ESP8266_TIMEOUT,
    ESP8266_INVALID_PARAM,
    ESP8266_NOT_INITIALIZED,
    ESP8266_WIFI_NOT_CONNECTED,
    ESP8266_MEMORY_ERROR
} ESP8266_Result_t;

typedef enum {
    ESP8266_MODE_STA = 1,
    ESP8266_MODE_AP = 2,
    ESP8266_MODE_STA_AP = 3
} ESP8266_Mode_t;

typedef enum {
    ESP8266_WIFI_DISCONNECTED = 0,
    ESP8266_WIFI_CONNECTED = 1,
    ESP8266_WIFI_CONNECTING = 2,
    ESP8266_WIFI_ERROR = 3
} ESP8266_WiFi_Status_t;

typedef enum {
    ESP8266_ENCRYPT_OPEN = 0,
    ESP8266_ENCRYPT_WEP,
    ESP8266_ENCRYPT_WPA_PSK,
    ESP8266_ENCRYPT_WPA2_PSK,
    ESP8266_ENCRYPT_WPA_WPA2_PSK
} ESP8266_Encrypt_t;

/* 前向声明 */
typedef struct ESP8266_Class ESP8266_t;

/* WiFi信息结构体 */
typedef struct {
    char ssid[ESP8266_SSID_MAX_LEN];
    char password[ESP8266_PASSWORD_MAX_LEN];
    ESP8266_Encrypt_t encryption;
    int8_t rssi;
} ESP8266_WiFi_Info_t;

/* 网络信息结构体 */
typedef struct {
    char ip[ESP8266_IP_STR_LEN];
    char gateway[ESP8266_IP_STR_LEN];
    char netmask[ESP8266_IP_STR_LEN];
    char mac[ESP8266_MAC_STR_LEN];
} ESP8266_Network_Info_t;

/* 虚函数表(接口定义) */
typedef struct {
    /* 基础操作 - 纯虚函数 */
    ESP8266_Result_t (*init)(ESP8266_t *this);
    ESP8266_Result_t (*deinit)(ESP8266_t *this);
    ESP8266_Result_t (*reset)(ESP8266_t *this);
    ESP8266_Result_t (*send_cmd)(ESP8266_t *this, const char *cmd, char *response, uint32_t timeout);
    
    /* WiFi操作 */
    ESP8266_Result_t (*set_mode)(ESP8266_t *this, ESP8266_Mode_t mode);
    ESP8266_Mode_t (*get_mode)(ESP8266_t *this);
    ESP8266_Result_t (*connect_wifi)(ESP8266_t *this, const char *ssid, const char *password);
    ESP8266_Result_t (*disconnect_wifi)(ESP8266_t *this);
    ESP8266_WiFi_Status_t (*get_wifi_status)(ESP8266_t *this);
    ESP8266_Result_t (*scan_wifi)(ESP8266_t *this, ESP8266_WiFi_Info_t *wifi_list, uint8_t *count);
    
    /* 网络操作 */
    ESP8266_Result_t (*get_network_info)(ESP8266_t *this, ESP8266_Network_Info_t *info);
    ESP8266_Result_t (*create_tcp_server)(ESP8266_t *this, uint16_t port);
    ESP8266_Result_t (*create_tcp_client)(ESP8266_t *this, const char *host, uint16_t port);
    ESP8266_Result_t (*send_data)(ESP8266_t *this, const uint8_t *data, uint16_t len);
    ESP8266_Result_t (*receive_data)(ESP8266_t *this, uint8_t *data, uint16_t *len, uint32_t timeout);
    
    /* HTTP操作 */
    ESP8266_Result_t (*http_get)(ESP8266_t *this, const char *url, char *response, uint16_t *len);
    ESP8266_Result_t (*http_post)(ESP8266_t *this, const char *url, const char *data, char *response, uint16_t *len);
} ESP8266_VTable_t;

/* ESP8266基类 */
struct ESP8266_Class {
    /* 虚函数表指针 */
    const ESP8266_VTable_t *vtable;
    
    /* 私有数据成员 */
    ESP8266_Mode_t mode;
    ESP8266_WiFi_Status_t wifi_status;
    ESP8266_WiFi_Info_t current_wifi;
    ESP8266_Network_Info_t network_info;
    
    /* 状态标志 */
    bool initialized;
    bool connected;
    
    /* 缓冲区 */
    char cmd_buffer[ESP8266_BUFFER_SIZE];
    char response_buffer[ESP8266_BUFFER_SIZE];
    
    /* 硬件抽象层接口(需要子类实现) */
    void (*hw_send_byte)(uint8_t data);
    uint8_t (*hw_receive_byte)(void);
    bool (*hw_data_available)(void);
    void (*hw_delay_ms)(uint32_t ms);
    uint32_t (*hw_get_tick)(void);
};

/* ============================================================================
 * 公共接口函数 - 面向对象方法调用
 * ============================================================================ */

/* 构造函数 */
ESP8266_Result_t ESP8266_Construct(ESP8266_t *this, const ESP8266_VTable_t *vtable);

/* 析构函数 */
void ESP8266_Destruct(ESP8266_t *this);

/* 基础操作方法 */
static inline ESP8266_Result_t ESP8266_Init(ESP8266_t *this) {
    return this->vtable->init(this);
}

static inline ESP8266_Result_t ESP8266_Deinit(ESP8266_t *this) {
    return this->vtable->deinit(this);
}

static inline ESP8266_Result_t ESP8266_Reset(ESP8266_t *this) {
    return this->vtable->reset(this);
}

/* WiFi操作方法 */
static inline ESP8266_Result_t ESP8266_SetMode(ESP8266_t *this, ESP8266_Mode_t mode) {
    return this->vtable->set_mode(this, mode);
}

static inline ESP8266_Mode_t ESP8266_GetMode(ESP8266_t *this) {
    return this->vtable->get_mode(this);
}

static inline ESP8266_Result_t ESP8266_ConnectWiFi(ESP8266_t *this, const char *ssid, const char *password) {
    return this->vtable->connect_wifi(this, ssid, password);
}

static inline ESP8266_Result_t ESP8266_DisconnectWiFi(ESP8266_t *this) {
    return this->vtable->disconnect_wifi(this);
}

static inline ESP8266_WiFi_Status_t ESP8266_GetWiFiStatus(ESP8266_t *this) {
    return this->vtable->get_wifi_status(this);
}

/* 网络操作方法 */
static inline ESP8266_Result_t ESP8266_GetNetworkInfo(ESP8266_t *this, ESP8266_Network_Info_t *info) {
    return this->vtable->get_network_info(this, info);
}

static inline ESP8266_Result_t ESP8266_CreateTCPServer(ESP8266_t *this, uint16_t port) {
    return this->vtable->create_tcp_server(this, port);
}

static inline ESP8266_Result_t ESP8266_CreateTCPClient(ESP8266_t *this, const char *host, uint16_t port) {
    return this->vtable->create_tcp_client(this, host, port);
}

static inline ESP8266_Result_t ESP8266_SendData(ESP8266_t *this, const uint8_t *data, uint16_t len) {
    return this->vtable->send_data(this, data, len);
}

static inline ESP8266_Result_t ESP8266_ReceiveData(ESP8266_t *this, uint8_t *data, uint16_t *len, uint32_t timeout) {
    return this->vtable->receive_data(this, data, len, timeout);
}

/* HTTP操作方法 */
static inline ESP8266_Result_t ESP8266_HttpGet(ESP8266_t *this, const char *url, char *response, uint16_t *len) {
    return this->vtable->http_get(this, url, response, len);
}

static inline ESP8266_Result_t ESP8266_HttpPost(ESP8266_t *this, const char *url, const char *data, char *response, uint16_t *len) {
    return this->vtable->http_post(this, url, data, response, len);
}

/* ============================================================================
 * 辅助函数
 * ============================================================================ */
const char* ESP8266_GetResultString(ESP8266_Result_t result);
const char* ESP8266_GetModeString(ESP8266_Mode_t mode);
const char* ESP8266_GetWiFiStatusString(ESP8266_WiFi_Status_t status);

#endif /* __ESP8266_OOP_H__ */

/* ============================================================================
 * ESP8266面向对象封装 - 实现文件
 * 文件: esp8266_oop.c
 * ============================================================================ */

#include "esp8266_oop.h"
#include <stdio.h>
#include <stdlib.h>

/* ============================================================================
 * 基类实现
 * ============================================================================ */

/* 构造函数实现 */
ESP8266_Result_t ESP8266_Construct(ESP8266_t *this, const ESP8266_VTable_t *vtable) {
    if (this == NULL || vtable == NULL) {
        return ESP8266_INVALID_PARAM;
    }
    
    /* 初始化虚函数表 */
    this->vtable = vtable;
    
    /* 初始化成员变量 */
    this->mode = ESP8266_MODE_STA;
    this->wifi_status = ESP8266_WIFI_DISCONNECTED;
    this->initialized = false;
    this->connected = false;
    
    /* 清空结构体 */
    memset(&this->current_wifi, 0, sizeof(ESP8266_WiFi_Info_t));
    memset(&this->network_info, 0, sizeof(ESP8266_Network_Info_t));
    memset(this->cmd_buffer, 0, ESP8266_BUFFER_SIZE);
    memset(this->response_buffer, 0, ESP8266_BUFFER_SIZE);
    
    /* 硬件接口指针初始化为NULL(需要子类设置) */
    this->hw_send_byte = NULL;
    this->hw_receive_byte = NULL;
    this->hw_data_available = NULL;
    this->hw_delay_ms = NULL;
    this->hw_get_tick = NULL;
    
    return ESP8266_OK;
}

/* 析构函数实现 */
void ESP8266_Destruct(ESP8266_t *this) {
    if (this != NULL && this->initialized) {
        /* 调用析构函数 */
        if (this->vtable && this->vtable->deinit) {
            this->vtable->deinit(this);
        }
        
        /* 清理资源 */
        this->initialized = false;
        this->connected = false;
        this->vtable = NULL;
    }
}

/* ============================================================================
 * 辅助函数实现
 * ============================================================================ */

const char* ESP8266_GetResultString(ESP8266_Result_t result) {
    switch (result) {
        case ESP8266_OK: return "OK";
        case ESP8266_ERROR: return "ERROR";
        case ESP8266_TIMEOUT: return "TIMEOUT";
        case ESP8266_INVALID_PARAM: return "INVALID_PARAM";
        case ESP8266_NOT_INITIALIZED: return "NOT_INITIALIZED";
        case ESP8266_WIFI_NOT_CONNECTED: return "WIFI_NOT_CONNECTED";
        case ESP8266_MEMORY_ERROR: return "MEMORY_ERROR";
        default: return "UNKNOWN";
    }
}

const char* ESP8266_GetModeString(ESP8266_Mode_t mode) {
    switch (mode) {
        case ESP8266_MODE_STA: return "STA";
        case ESP8266_MODE_AP: return "AP";
        case ESP8266_MODE_STA_AP: return "STA+AP";
        default: return "UNKNOWN";
    }
}

const char* ESP8266_GetWiFiStatusString(ESP8266_WiFi_Status_t status) {
    switch (status) {
        case ESP8266_WIFI_DISCONNECTED: return "DISCONNECTED";
        case ESP8266_WIFI_CONNECTED: return "CONNECTED";
        case ESP8266_WIFI_CONNECTING: return "CONNECTING";
        case ESP8266_WIFI_ERROR: return "ERROR";
        default: return "UNKNOWN";
    }
}

/* ============================================================================
 * 具体实现类示例 - ESP8266 AT命令实现
 * 文件: esp8266_at.c
 * ============================================================================ */

/* AT命令实现的虚函数表 */
static ESP8266_Result_t ESP8266_AT_Init(ESP8266_t *this);
static ESP8266_Result_t ESP8266_AT_Deinit(ESP8266_t *this);
static ESP8266_Result_t ESP8266_AT_Reset(ESP8266_t *this);
static ESP8266_Result_t ESP8266_AT_SendCmd(ESP8266_t *this, const char *cmd, char *response, uint32_t timeout);
static ESP8266_Result_t ESP8266_AT_SetMode(ESP8266_t *this, ESP8266_Mode_t mode);
static ESP8266_Mode_t ESP8266_AT_GetMode(ESP8266_t *this);
static ESP8266_Result_t ESP8266_AT_ConnectWiFi(ESP8266_t *this, const char *ssid, const char *password);
static ESP8266_Result_t ESP8266_AT_DisconnectWiFi(ESP8266_t *this);
static ESP8266_WiFi_Status_t ESP8266_AT_GetWiFiStatus(ESP8266_t *this);
static ESP8266_Result_t ESP8266_AT_GetNetworkInfo(ESP8266_t *this, ESP8266_Network_Info_t *info);

/* AT命令实现的虚函数表定义 */
const ESP8266_VTable_t ESP8266_AT_VTable = {
    .init = ESP8266_AT_Init,
    .deinit = ESP8266_AT_Deinit,
    .reset = ESP8266_AT_Reset,
    .send_cmd = ESP8266_AT_SendCmd,
    .set_mode = ESP8266_AT_SetMode,
    .get_mode = ESP8266_AT_GetMode,
    .connect_wifi = ESP8266_AT_ConnectWiFi,
    .disconnect_wifi = ESP8266_AT_DisconnectWiFi,
    .get_wifi_status = ESP8266_AT_GetWiFiStatus,
    .get_network_info = ESP8266_AT_GetNetworkInfo,
    /* 其他函数可以设置为NULL或实现 */
    .scan_wifi = NULL,
    .create_tcp_server = NULL,
    .create_tcp_client = NULL,
    .send_data = NULL,
    .receive_data = NULL,
    .http_get = NULL,
    .http_post = NULL
};

/* AT命令实现的具体函数 */
static ESP8266_Result_t ESP8266_AT_Init(ESP8266_t *this) {
    if (this == NULL) return ESP8266_INVALID_PARAM;
    
    /* 检查硬件接口是否已设置 */
    if (!this->hw_send_byte || !this->hw_receive_byte || 
        !this->hw_data_available || !this->hw_delay_ms) {
        return ESP8266_NOT_INITIALIZED;
    }
    
    /* 发送AT测试命令 */
    ESP8266_Result_t result = ESP8266_AT_SendCmd(this, "AT", this->response_buffer, 1000);
    if (result == ESP8266_OK) {
        this->initialized = true;
    }
    
    return result;
}

static ESP8266_Result_t ESP8266_AT_SendCmd(ESP8266_t *this, const char *cmd, char *response, uint32_t timeout) {
    if (!this || !cmd) return ESP8266_INVALID_PARAM;
    
    /* 发送命令 */
    const char *p = cmd;
    while (*p) {
        this->hw_send_byte(*p++);
    }
    this->hw_send_byte('\r');
    this->hw_send_byte('\n');
    
    /* 接收响应 */
    uint32_t start_time = this->hw_get_tick();
    uint16_t idx = 0;
    
    while ((this->hw_get_tick() - start_time) < timeout) {
        if (this->hw_data_available()) {
            uint8_t data = this->hw_receive_byte();
            if (response && idx < ESP8266_BUFFER_SIZE - 1) {
                response[idx++] = data;
            }
            
            /* 检查是否收到OK或ERROR */
            if (strstr(response, "OK")) {
                response[idx] = '\0';
                return ESP8266_OK;
            }
            if (strstr(response, "ERROR")) {
                response[idx] = '\0';
                return ESP8266_ERROR;
            }
        }
        this->hw_delay_ms(1);
    }
    
    return ESP8266_TIMEOUT;
}

static ESP8266_Result_t ESP8266_AT_ConnectWiFi(ESP8266_t *this, const char *ssid, const char *password) {
    if (!this || !ssid || !password) return ESP8266_INVALID_PARAM;
    if (!this->initialized) return ESP8266_NOT_INITIALIZED;
    
    /* 设置为STA模式 */
    ESP8266_Result_t result = ESP8266_AT_SetMode(this, ESP8266_MODE_STA);
    if (result != ESP8266_OK) return result;
    
    /* 构建连接命令 */
    snprintf(this->cmd_buffer, ESP8266_BUFFER_SIZE, 
             "AT+CWJAP=\"%s\",\"%s\"", ssid, password);
    
    /* 发送连接命令 */
    result = ESP8266_AT_SendCmd(this, this->cmd_buffer, this->response_buffer, 10000);
    
    if (result == ESP8266_OK) {
        /* 保存WiFi信息 */
        strncpy(this->current_wifi.ssid, ssid, ESP8266_SSID_MAX_LEN - 1);
        strncpy(this->current_wifi.password, password, ESP8266_PASSWORD_MAX_LEN - 1);
        this->wifi_status = ESP8266_WIFI_CONNECTED;
        this->connected = true;
    }
    
    return result;
}

/* 其他AT命令实现函数... */
static ESP8266_Result_t ESP8266_AT_Deinit(ESP8266_t *this) {
    if (this) this->initialized = false;
    return ESP8266_OK;
}

static ESP8266_Result_t ESP8266_AT_Reset(ESP8266_t *this) {
    return ESP8266_AT_SendCmd(this, "AT+RST", this->response_buffer, 2000);
}

static ESP8266_Result_t ESP8266_AT_SetMode(ESP8266_t *this, ESP8266_Mode_t mode) {
    snprintf(this->cmd_buffer, ESP8266_BUFFER_SIZE, "AT+CWMODE=%d", mode);
    ESP8266_Result_t result = ESP8266_AT_SendCmd(this, this->cmd_buffer, this->response_buffer, 1000);
    if (result == ESP8266_OK) {
        this->mode = mode;
    }
    return result;
}

static ESP8266_Mode_t ESP8266_AT_GetMode(ESP8266_t *this) {
    return this->mode;
}

static ESP8266_Result_t ESP8266_AT_DisconnectWiFi(ESP8266_t *this) {
    ESP8266_Result_t result = ESP8266_AT_SendCmd(this, "AT+CWQAP", this->response_buffer, 1000);
    if (result == ESP8266_OK) {
        this->wifi_status = ESP8266_WIFI_DISCONNECTED;
        this->connected = false;
    }
    return result;
}

static ESP8266_WiFi_Status_t ESP8266_AT_GetWiFiStatus(ESP8266_t *this) {
    return this->wifi_status;
}

static ESP8266_Result_t ESP8266_AT_GetNetworkInfo(ESP8266_t *this, ESP8266_Network_Info_t *info) {
    /* 获取IP信息的实现 */
    ESP8266_Result_t result = ESP8266_AT_SendCmd(this, "AT+CIFSR", this->response_buffer, 1000);
    if (result == ESP8266_OK && info) {
        /* 解析响应并填充网络信息 */
        /* 这里需要解析AT+CIFSR的响应格式 */
        strcpy(info->ip, "192.168.1.100");  // 示例
        strcpy(info->gateway, "192.168.1.1");
        strcpy(info->netmask, "255.255.255.0");
        strcpy(info->mac, "AA:BB:CC:DD:EE:FF");
    }
    return result;
}

/* ============================================================================
 * 使用示例
 * ============================================================================ */

/* 硬件抽象层实现示例(需要根据具体硬件平台实现) */
void hw_uart_send_byte(uint8_t data) {
    /* 发送一个字节到UART */
    // 具体实现依赖于硬件平台
}

uint8_t hw_uart_receive_byte(void) {
    /* 从UART接收一个字节 */
    // 具体实现依赖于硬件平台
    return 0;
}

bool hw_uart_data_available(void) {
    /* 检查UART是否有数据可读 */
    // 具体实现依赖于硬件平台
    return false;
}

void hw_delay_ms(uint32_t ms) {
    /* 毫秒级延时 */
    // 具体实现依赖于硬件平台
}

uint32_t hw_get_tick_ms(void) {
    /* 获取系统时钟(毫秒) */
    // 具体实现依赖于硬件平台
    return 0;
}

/* 使用示例 */
void example_usage(void) {
    ESP8266_t wifi_module;
    ESP8266_Result_t result;
    ESP8266_Network_Info_t net_info;
    
    /* 1. 构造对象 */
    result = ESP8266_Construct(&wifi_module, &ESP8266_AT_VTable);
    if (result != ESP8266_OK) {
        printf("构造失败: %s\n", ESP8266_GetResultString(result));
        return;
    }
    
    /* 2. 设置硬件抽象层接口 */
    wifi_module.hw_send_byte = hw_uart_send_byte;
    wifi_module.hw_receive_byte = hw_uart_receive_byte;
    wifi_module.hw_data_available = hw_uart_data_available;
    wifi_module.hw_delay_ms = hw_delay_ms;
    wifi_module.hw_get_tick = hw_get_tick_ms;
    
    /* 3. 初始化模块 */
    result = ESP8266_Init(&wifi_module);
    if (result != ESP8266_OK) {
        printf("初始化失败: %s\n", ESP8266_GetResultString(result));
        ESP8266_Destruct(&wifi_module);
        return;
    }
    
    /* 4. 连接WiFi */
    result = ESP8266_ConnectWiFi(&wifi_module, "MyWiFi", "password123");
    if (result == ESP8266_OK) {
        printf("WiFi连接成功\n");
        
        /* 5. 获取网络信息 */
        result = ESP8266_GetNetworkInfo(&wifi_module, &net_info);
        if (result == ESP8266_OK) {
            printf("IP: %s\n", net_info.ip);
            printf("Gateway: %s\n", net_info.gateway);
            printf("MAC: %s\n", net_info.mac);
        }
    } else {
        printf("WiFi连接失败: %s\n", ESP8266_GetResultString(result));
    }
    
    /* 6. 清理资源 */
    ESP8266_Destruct(&wifi_module);
}

/*
面向对象设计特性说明:

1. 封装 (Encapsulation):
   - 数据成员私有化,通过公共接口访问
   - 隐藏内部实现细节
   - 提供清晰的API接口

2. 继承 (Inheritance):
   - 基类定义通用接口和数据结构
   - 派生类实现具体功能(如AT命令实现)
   - 可以轻松扩展新的实现(如SPI实现)

3. 多态 (Polymorphism):
   - 通过虚函数表实现运行时多态
   - 相同接口可以有不同实现
   - 支持动态绑定

4. 抽象 (Abstraction):
   - 定义抽象接口(虚函数表)
   - 隐藏具体实现细节
   - 提供统一的使用方式

5. 组合 (Composition):
   - 硬件抽象层通过函数指针组合
   - 灵活适配不同硬件平台
   - 降低耦合度

优势:
- 代码复用性高
- 易于维护和扩展
- 良好的模块化设计
- 支持不同的硬件平台
- 类型安全
*/