Clion开发STM32之ESP8266系列(三)

前言

上一篇Clion开发STM32之ESP8266系列(二)

本篇主要内容

  1. ESP8266模块驱动的编写
  2. 对应串口驱动的编写(使用的串口3)

正文

修改STM32Cubmx配置(不让生成串口驱动的代码)

Clion开发STM32之ESP8266系列(三)_第1张图片

串口部分的驱动(只写了串口1和串口3)

Clion开发STM32之ESP8266系列(三)_第2张图片

头文件

/*******************************************************************************
 * @author scl
 * @email [email protected]
 *          @brief 串口封装驱动
 ******************************************************************************/

#ifndef STM32F103VET6_ESP8266_BSP_SERIAL_H
#define STM32F103VET6_ESP8266_BSP_SERIAL_H

#include "bsp_include.h"
/** @brief  检查是否设置了指定的 UART 标志。*/
#define UART_GET_FLAG(__UART__, __FLAG__) (((__UART__)->SR & (__FLAG__)) == (__FLAG__))
/** @brief  使能具体的中断源标志位*/
#define UART_ENABLE_IT(__UART__, __INTERRUPT__)   ((((__INTERRUPT__) >> 28U) == UART_CR1_REG_INDEX)? ((__UART__)->CR1 |= ((__INTERRUPT__) & UART_IT_MASK)): \
                                                   (((__INTERRUPT__) >> 28U) == UART_CR2_REG_INDEX)? ((__UART__)->CR2 |= ((__INTERRUPT__) & UART_IT_MASK)): \
                                                    ((__UART__)->CR3 |= ((__INTERRUPT__) & UART_IT_MASK)))
/** @brief  Disable 具体的中断源标志位.*/
#define UART_DISABLE_IT(__UART__, __INTERRUPT__)  ((((__INTERRUPT__) >> 28U) == UART_CR1_REG_INDEX)? ((__UART__)->CR1 &= ~((__INTERRUPT__) & UART_IT_MASK)): \
                                                           (((__INTERRUPT__) >> 28U) == UART_CR2_REG_INDEX)? ((__UART__)->CR2 &= ~((__INTERRUPT__) & UART_IT_MASK)): \
                                                           ((__UART__)->CR3 &= ~ ((__INTERRUPT__) & UART_IT_MASK)))
#define COM_SIZE 4 /*串口数量*/
typedef enum {
    com1 = 0,
    com2,
    com3,
    com4
} serial_port_type;
/********************************串口1 中断**********************************************/
#define COM1_IT_ENABLE (0) // 中断使能
#define COM1_IT_PreemptPriority (0) // 抢占优先级
#define COM1_IT_SubPriority (0) // 响应优先级
/********************************串口2 中断**********************************************/
/********************************串口3 中断**********************************************/
#define COM3_IT_ENABLE (1) // 中断使能
#define COM3_IT_PreemptPriority (0) // 抢占优先级
#define COM3_IT_SubPriority (0) // 响应优先级

/********************************串口4 中断**********************************************/
/********************************串口 通用**********************************************/
UART_HandleTypeDef *com_handle_get(serial_port_type port);

/**
 * @brief 串口1初始化
 * @param baud 波特率
 */
void com1_init(uint32_t baud);

/**
 * @brief 串口3初始化
 * @param baud 波特率
 */
void com3_init(uint32_t baud);

#endif //STM32F103VET6_ESP8266_BSP_SERIAL_H

源文件

/*******************************************************************************
 * @author scl
 * @email [email protected]
 ******************************************************************************/

#include "bsp_serial.h"

/*串口句柄存放数组*/
static UART_HandleTypeDef com_tb[COM_SIZE];

/********************************串口 通用**********************************************/
/**
 * @brief 获取串口句柄
 * @param port 
 * @return 
 */
inline UART_HandleTypeDef *com_handle_get(serial_port_type port) {
    return &com_tb[port];
}

/********************************串口1 START**********************************************/
void com1_init(uint32_t baud) {
    UART_HandleTypeDef *ptr = com_handle_get(com1);

    ptr->Instance = USART1;
    ptr->Init.BaudRate = baud;
    ptr->Init.WordLength = UART_WORDLENGTH_8B;
    ptr->Init.StopBits = UART_STOPBITS_1;
    ptr->Init.Parity = UART_PARITY_NONE;
    ptr->Init.Mode = UART_MODE_TX_RX;
    ptr->Init.HwFlowCtl = UART_HWCONTROL_NONE;
    ptr->Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_DeInit(ptr);
    if (HAL_UART_Init(ptr) != HAL_OK) {
        error_handle();
    }
}
/********************************串口1 END**********************************************/
/********************************串口3 START**********************************************/

void com3_init(uint32_t baud) {

    UART_HandleTypeDef *ptr = com_handle_get(com3);
    ptr->Instance = USART3;
    ptr->Init.BaudRate = baud;
    ptr->Init.WordLength = UART_WORDLENGTH_8B;
    ptr->Init.StopBits = UART_STOPBITS_1;
    ptr->Init.Parity = UART_PARITY_NONE;
    ptr->Init.Mode = UART_MODE_TX_RX;
    ptr->Init.HwFlowCtl = UART_HWCONTROL_NONE;
    ptr->Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_DeInit(ptr);
    if (HAL_UART_Init(ptr) != HAL_OK) {
        error_handle();
    }
}
/********************************串口3 END**********************************************/

/********************************HAL 库串口硬件通用**********************************************/
static inline void com_gpio_init(GPIO_TypeDef *tx_port, uint32_t tx_pin, GPIO_TypeDef *rx_port, uint32_t rx_pin) {
    GPIO_InitTypeDef GPIO_InitStruct = {.Pin=tx_pin, .Mode=GPIO_MODE_AF_PP, .Speed=GPIO_SPEED_FREQ_HIGH};
    HAL_GPIO_Init(tx_port, &GPIO_InitStruct);
    GPIO_InitStruct.Pin = rx_pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(rx_port, &GPIO_InitStruct);
}

/********************************HAL 库串口硬件驱动初始化**********************************************/
void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) {

    if (uartHandle->Instance == USART1) {
        /* USART1 clock enable */
        __HAL_RCC_USART1_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();
        /**USART1 GPIO Configuration
        PA9     ------> USART1_TX
        PA10     ------> USART1_RX
        */
        com_gpio_init(GPIOA, GPIO_PIN_9, GPIOA, GPIO_PIN_10);
#if COM1_IT_ENABLE
        /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, COM1_IT_PreemptPriority, COM1_IT_SubPriority);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
#endif
    } else if (uartHandle->Instance == USART3) {
        __HAL_RCC_USART3_CLK_ENABLE();
        __HAL_RCC_GPIOB_CLK_ENABLE();
        /**USART3 GPIO Configuration
            PB10     ------> USART3_TX
            PB11     ------> USART3_RX
        */
        com_gpio_init(GPIOB, GPIO_PIN_10, GPIOB, GPIO_PIN_11);
#if COM3_IT_ENABLE
        /* USART3 interrupt Init */
        HAL_NVIC_SetPriority(USART3_IRQn, COM3_IT_PreemptPriority, COM3_IT_SubPriority);
        HAL_NVIC_EnableIRQ(USART3_IRQn);
#endif
    }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef *uartHandle) {

    if (uartHandle->Instance == USART1) {
        /* Peripheral clock disable */
        __HAL_RCC_USART1_CLK_DISABLE();
        HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9 | GPIO_PIN_10);
#if COM1_IT_ENABLE
        /* USART1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART1_IRQn);
#endif
    } else if (uartHandle->Instance == USART3) {
        __HAL_RCC_USART3_CLK_DISABLE();
        HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10 | GPIO_PIN_11);
#if COM3_IT_ENABLE
        /*  interrupt Deinit */
        HAL_NVIC_DisableIRQ(USART3_IRQn);
#endif
    }
}

ESP8266模块驱动的编写

头文件

/*******************************************************************************
 * @author scl
 * @email [email protected]
 ******************************************************************************/

/*******************************************************************************
 * @author scl
 * @email [email protected]
 ******************************************************************************/

#ifndef STM32F103VET6_ESP8266_MODULE_ESP8266_H
#define STM32F103VET6_ESP8266_MODULE_ESP8266_H

#include "app_dr_include.h"

#define ESP_CLOSED_MSG "CLOSED\r\n"
#define RX_BUF_MAX_LEN 1024 // 最大接收缓存字节数

typedef enum {
    ap_mode = 0,    /* 设置 ESP8266 SoftAP*/
    sta_mode = 1,   /* 设置 ESP8266 Station*/
    sta_ap_mode = 2 /*设置 ESP8266 SoftAP 和 Station*/
} esp8266_net_mode;
typedef enum {
    open_mode = 0,
    wep_mode = 1,
    wpa_psk_mode = 2,
    wpa2_psk_mode = 3,
    wpa_wpa2_psk_mode = 4,
} esp8266_ap_psd_mode;
typedef enum {
    multiple_id_0 = 0,
    multiple_id_1 = 1,
    multiple_id_2 = 2,
    multiple_id_3 = 3,
    multiple_id_4 = 4,
    single_id_0 = 5, /*单连接模式*/
} esp8266_id_no;

typedef enum {
    link_error = 0,/*获取状态失败*/
    link_get_ip = 2, /*获取ip*/
    link_established = 3, /*建立连接*/
    link_lose_connect = 4, /*失去连接*/
} esp8266_link_status;

/**
 * @brief esp 延迟函数指针定义
 * */
typedef void (*esp_delay_def)(uint32_t ms);

/**
 * @brief  esp 调试函数指针定义
 */
typedef void (*esp_debug_def)(char *format, ...);
/*************************************************外部实现接口***************************************************/
/**
 * @brief esp8266 驱动外设初始化
 */
extern void esp8266_driver_init();

/**
 * @brief esp8266 复位引脚
 * @param flag true: 置高; false: 置低
 */
extern void esp8266_rst_pin(bool flag);

/**
 * @brief esp8266 使能引脚
 * @param flag true: 使能
 */
extern void esp8266_ch_enable(bool flag);


/**
 * @brief esp8266 发送数据
 * @param data
 * @param len
 */
extern void esp8266_send(void *data, uint16_t len);

/**
 * @brief 清空接收缓冲区
 */
extern void esp8266_clear_buf(void);

/**
 * @brief esp8266 接收数据
 * @return 接收数据
 */
extern char *esp8266_rec();

/**
 * @brief esp8266 构造指令的缓存区
 * @return
 */
extern char *esp8266_get_cmd_buf();
/*************************************************底层收发接口***************************************************/
/**
 * @brief esp8266发送和接收
 * @param data 数据
 * @param wait_time 等待响应的时间
 * @return 返回结果
 */
char *esp8266_send_and_rec(char *data, uint32_t wait_time);

/**
 * @brief esp8266发送和接收 并进行验证
 * @param cmd 数据
 * @param reply1 期待的响应1,为NULL表不需响应
 * @param reply2 期待的响应2,为NULL表不需响应
 *      reply1和reply2为或逻辑关系
 * @param wait_time
 * @return
 */
char *esp8266_send_cmd_msg(char *cmd, const char *reply1, const char *reply2, uint32_t wait_time);

/**
 * @brief 对WF-ESP8266模块发送AT指令
 * @param cmd 发送的指令
 * @param reply1 期待的响应1,为NULL表不需响应
 * @param reply2 期待的响应2,为NULL表不需响应
 *               reply1和reply2为或逻辑关系
 * @param wait_time 等待响应的时间
 * @return
 */
bool esp8266_send_cmd(char *cmd, const char *reply1, const char *reply2, uint32_t wait_time);
/*************************************************函数回调接口***************************************************/
/**
 * @brief 设置esp8266 延迟函数回调
 * @param call
 */
void esp8266_set_delay_call(esp_delay_def call);

/**
 * @brief 设置esp8266 调试函数回调
 * @param call
 */
void esp8266_set_debug_call(esp_debug_def call);
/*************************************************基础接口***************************************************/
/**
 * @brief 对WF-ESP8266模块进行AT测试启动
 * @param try_cnt 尝试次数
 * @param wait_time 设置esp8266 延迟函数回调
 * @return
 */
bool esp8266_base_at_cmd_test(uint8_t try_cnt, uint32_t wait_time);

/**
 * @brief 开关回显功能
 * @param en
 *      true:  开回显
 *      false: 关回显
 * @param wait_time 设置esp8266 延迟函数回调(默认 200)
 */
bool esp8266_base_ate_conf(bool en, uint32_t wait_time);

/**
 * @brief 恢复出厂设置
 * @param wait_time 设置esp8266 延迟函数回调(默认 200)
 */
bool esp8266_base_factory_reset_conf(uint32_t wait_time);

/**
 * @brief 重启WF-ESP8266模块
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 */
void esp8266_base_rst(bool soft, uint32_t wait_time);
/****************************************ESP8266 WIFI 配置**************************************************/
/**
 * @brief 设置当前 Wi-Fi 模式,@note 不保存到 Flash
 * @param mode
 *          ap_mode     设置 ESP8266 SoftAP
 *          sta_mode    设置 ESP8266 Station
 *          sta_ap_mode 设置 ESP8266 SoftAP 和 Station
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_wifi_mode_cur_set(esp8266_net_mode mode, int wait_time);

/**
 * @brief 临时连接 AP
 *  @note
 *      1. 参数设置需要开启 Station 模式,相关配置请查看 @see esp8266_wifi_mode_cur_set
 *      2. 若 SSID 或者password 中含有特殊符号,例如 , 或者 “ 或者 \ 时,需要进行转义,其它字符转义无效。
 * @param ssid WiFi名称字符串
 * @param pwd WiFi密码字符串
 * @param bssid 目标 AP 的 MAC 地址(可选配置)
 * @param wait_time 等待响应的时间 (-1,默认为 3000 )
 * @return
 */
bool esp8266_wifi_join_cur_set(char *ssid, char *pwd, char *bssid, int wait_time);

/**
 * @brief 断开与 AP 的连接
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_wifi_disconnect(int wait_time);

/**
 * @brief 配置 ESP8266 SoftAP 当前参数
 *  @note 指令只有在 SoftAP 模式开启后有效,相关配置请查看 @see esp8266_wifi_mode_cur_set
 * @param ssid WiFi名称字符串
 * @param pwd WiFi密码字符串
 * @param channel 通道号
 * @param psd_mode 加密方式,不支持 WEP
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_wifi_conf_cur_set(char *ssid, char *pwd, uint8_t channel,
                               esp8266_ap_psd_mode psd_mode, int wait_time);

/****************************************ESP8266 DHCP 配置**************************************************/

/**
 * @brief 设置 DHCP,不保存到 Flash
 * @note
 *      1. 本设置指令与设置静态 IP 的指令(AT+CIPSTA 系列列和 AT+CIPAP 系列)互相影响
 *         > 设置使能 DHCP,则静态 IP 无效
 *         > 设置静态 IP,则 DHCP 关闭
 *         > 以最后的设置为准
 * @param mode
 *          ap_mode     设置 ESP8266 SoftAP
 *          sta_mode    设置 ESP8266 Station
 *          sta_ap_mode 设置 ESP8266 SoftAP 和 Station
 * @param en
 *          true:  开启DHCP
 *          false: 关闭DHCP
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_dhcp_cur_set(esp8266_net_mode mode, bool en, int wait_time);

/**
 * @brief 设置 ESP8266 SoftAP DHCP 分配的 IP 范围,不不保存到 Flash
 *  @note
 *      1. 本指令必须在 ESP8266 SoftAP 模式使能, @see esp8266_wifi_mode_cur_set
 *      2. 且开启 DHCP 的情况下使用, @see esp8266_dhcp_cur_set
 *      3. 设置的 IP 范围必须与 ESP8266
SoftAP 在同⼀一⽹网段。
 * @param en
 *      false: 清除设置 IP 范围,恢复默认值,后续参数无需填写
 *      true: 使能设置 IP 范围,后续参数必须填写
 * @param lease_min 租约时间,单位:分钟,取值范围 [1, 2880]
 * @param start_ip DHCP 服务器 IP 池的起始 IP
 * @param end_ip   DHCP 服务器 IP 池的结束 IP
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_dhcp_ip_cur_set(bool en, uint16_t lease_min, char *start_ip, char *end_ip, int wait_time);
/****************************************ESP8266 MAC地址 配置**************************************************/
/**
 * @brief 设置 ESP8266 Station 当前 MAC 地址,不保存到 Flash
 *  @note
 *      1. ESP8266 SoftAP 和 Station 的 MAC 地址并不相同,请勿将其设置为同一 MAC 地址。
 *      2. ESP8266 MAC 地址第一个字节的 bit 0 不不能为 1,例如,MAC 地址可以为 "18:…" 但不不能为 "15:…"。
 * @param mac mac地址
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_mac_sta_cur_set(char *mac, int wait_time);

/**
 * @brief 设置 ESP8266 SoftAP 当前 MAC 地址,不保存到 Flash
 *  @note
 *      1. ESP8266 SoftAP 和 Station 的 MAC 地址并不相同,请勿将其设置为同一 MAC 地址。
 *      2. ESP8266 MAC 地址第一个字节的 bit 0 不不能为 1,例如,MAC 地址可以为 "18:…" 但不不能为 "15:…"。
 * @param mac mac地址
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_mac_ap_cur_set(char *mac, int wait_time);

/****************************************ESP8266 IP地址 配置**************************************************/
/**
 * @brief 设置 ESP8266 Station 的 IP 地址,不不保存到 Flash
 *  @note
 *      1. 本设置指令与设置 DHCP 的指令(AT+CWDHCP 系列)互相影响: @see esp8266_dhcp_cur_set
 *          ‣ 设置静态 IP,则 DHCP 关闭;
 *          ‣ 设置使能 DHCP,则静态 IP 无效;
 *          ‣ 以最后的设置为准。
 *      2. 目前仅支持 C 类 IP 地址
 * @param ip 字符串,
 * @param gw 网关
 * @param sub 子⽹网掩码
 * @param wait_time  等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_ip_sta_cur_set(char *ip, char *gw, char *sub, int wait_time);

/**
 * @brief 设置 ESP8266 SoftAP 的 IP 地址,不保存到 Flash
 *  @note
 *      1. 本设置指令与设置 DHCP 的指令(AT+CWDHCP 系列)互相影响: @see esp8266_dhcp_cur_set
 *          ‣ 设置静态 IP,则 DHCP 关闭;
 *          ‣ 设置使能 DHCP,则静态 IP 无效;
 *          ‣ 以最后的设置为准。
 *      2. 目前仅支持 C 类 IP 地址
 * @param ip 字符串,
 * @param gw 网关
 * @param sub 子网掩码
 * @param wait_time  等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_ip_ap_cur_set(char *ip, char *gw, char *sub, int wait_time);

/**
 * @brief 获取 F-ESP8266 的 AP IP
 *  @note ESP8266 Station IP 需连上 AP 后,才可以查询
 * @param ret_ip 存放 AP IP 的数组的首地址
 * @param len 数组的长度
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_ip_ap_inquire(char *ret_ip, uint8_t len, int wait_time);


/**
 * @brief 查询本地 IP 地址
 *  @note
 *      1. ESP8266 Station IP 需连上 AP 后,才可以查询。
 * @param dstIp 保存查询结果
 * @param len dstIp的长度
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_ip_sta_inquire(char *dstIp, uint8_t len, int wait_time);
/****************************************ESP8266 功能指令**************************************************/
/**
 * @brief 获取 WF-ESP8266 的连接状态,较适合单端口时使用
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
esp8266_link_status esp8266_net_link_status(int wait_time);

/**
 * @brief 建立 TCP 连接,UDP 传输或 SSL 连接(单连接)
 * @param type
 *      1: tcp
 *      2: udp
 *      3: ssl
 * @param server_addr 服务器地址
 * @param port 服务器端口
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_net_single_socket_build(uint8_t type, char *server_addr, uint16_t port, int wait_time);

/**
 * @brief  建立 TCP 连接,UDP 传输或 SSL 连接(多连接)
 * @param type
 *      1: tcp
 *      2: udp
 *      3: ssl
 * @param link_id 网络连接 ID (0 ~ 4),用于多连接的情况
 * @param server_addr 服务器地址
 * @param port 服务器端口
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_net_mul_socket_build(uint8_t type, uint8_t link_id, char *server_addr, uint16_t port, int wait_time);

/**
 * @brief 关闭 TCP/UDP/SSL 传输
 *      AT+CIPCLOSE=
 *      @note
 *          需要关闭的连接 ID 号。当 ID 为 5 时,关闭所有连接。(开启 server 后 ID 为 5 无效)
 * @param id
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_socket_close(esp8266_id_no id, int wait_time);

/*************************************************ESP8266 服务器和客户端通用***************************************************/
/**
 * @brief WF-ESP8266模块启动多连接
 *      @note
 *          1. 默认为单连接;
 *          2. 只有⾮透传模式 (AT+CIPMODE=0),才能设置为多连接
 *          3. 必须在没有连接建⽴的情况下,设置连接模式;
 *          4. 如果建⽴了 TCP 服务器,想切换为单连接,必须关闭服务器 (AT+CIPSERVER=0),服务器仅⽀持多连接
 * @param en true: 多连接模式;false 单连接模式
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_mul_connect_set(bool en, int wait_time);
/*************************************************ESP8266 服务端***************************************************/
/**
 * @brief 设置服务器允许建⽴立的最大连接数。
 *  @note
 *      1.如需设置最⼤大连接数,请在创建服务器之前设置。
 * @param mx_conn 连接数(范围是 1-5)
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_server_connect_num_set(uint8_t mx_conn, int wait_time);

/**
 * @brief 设置 TCP 服务器超时时间
 *     @note
 *          1. ESP8266 作为 TCP 服务器,会断开一直不通信直至超时了的 TCP 客户端连接
 *          2. 如果设置 AT+CIPSTO=0,则永远不会超时,不建议这样设置
 * @param timeout TCP 服务器超时时间,取值范围 0 ~ 7200s
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_server_tcp_timeout_set(uint16_t timeout, int wait_time);

/**
 * @brief tcp 服务器建立
 *  @note
 *      1. 多连接情况下 (AT+CIPMUX=1),才能开启 TCP 服务器。
 *      2. 创建 TCP 服务器后,自动建立 TCP 服务器监听。
 *      3. 当有 TCP 客户端接⼊入,会自动占用一个连接 ID。
 * @param en
 *      true:   开启服务器
 *      false: 关闭服务器
 * @param port 端口
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_server_tcp_start(bool en, uint16_t port, int wait_time);

/**
 * @brief 普通模式下发送数据
 * @param ucId 客户端连接id号
 * @param data 发送的字符串
 * @param len 发送的字符串的长度
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_server_tcp_send_to(esp8266_id_no ucId, char *data, uint16_t len, int wait_time);
/*************************************************ESP8266 客户端***************************************************/
/**
 * @brief 设置传输模式
 *          AT+CIPMODE=
 * @param en true: 透传模式;false 普通模式
 *      @note
 *          1. 透传模式,仅⽀支持 TCP 单连接和 UDP 固定通信对端的情况
 *          2. 本设置不不保存到 Flash。
 *          3. 透传模式传输时,如果连接断开, ESP8266 会不不停尝试重连,此时单独输⼊入 +++ 退出透传,则停⽌止重连;
 *             普通传输模式则不会重连,提示连接断开。
 *
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_transmission_mode_enter(bool en, int wait_time);

/**
 * @brief 退出透传模式
 *   @note
 *      1. 仅当传输模式为透传时
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
void esp8266_transmission_mode_exit(int wait_time);

/**
 * @brief 在tcp 客户端 透传模式下,更新连接关闭状态标志为
 * @param close_status
 *          true: 已关闭连接
 *          false: 处于连接中
 */
void esp8266_tcp_update_closed_flag(bool close_status);

/**
 * @brief 在tcp 客户端 透传模式下,读取连接关闭状态标志为
 * @return
 *          true: 已关闭连接
 *          false: 处于连接中
 */
bool esp8266_tcp_read_closed_flag();

/**
 * @brief 透传模式下发送数据
 * @param str 数据
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return 如果对端不反数据,则为NULL
 */
char *esp8266_transmission_mode_send(char *str, int wait_time);

/**
 * @brief WF-ESP8266模块发送字符串
 * @param ucId 哪个ID发送的字符串
 * @param already_tm_flag 是否已使能了透传模式
 * @param str 要发送的字符串
 * @param len 字符串的字节数
 * @param wait_time 等待响应的时间 (-1,默认为 1000 )
 * @return
 */
bool esp8266_send_str(esp8266_id_no ucId, bool already_tm_flag, char *str, uint32_t len, int wait_time);

#endif //STM32F103VET6_ESP8266_MODULE_ESP8266_H

源文件

/*******************************************************************************
 * @author scl
 * @email [email protected]
 ******************************************************************************/

#include "module_esp8266.h"

#define LEVEL_DELAY 200
#define DELAY_500 500
#define OK_MSG "OK"
#define NO_CHANGE_MSG "no change"
/**
 * @brief 判断参数是否为空
 * */
#define esp8266_is_null(par) ((par)==NULL)
/**
 * @brief 判断带参函数指针是否为空,不为空则执行
 */
#define esp8266_asset_not_nul_run(ptr, par) if((ptr)!=NULL) ptr(par)
/**
 * @brief 判断参数是否等于某个值,并重新赋值
 */
#define esp8266_assert_equal_set(par, equal_value, new_value) if((par)==(equal_value)) par=new_value

static void (*esp8266_delay)(uint32_t ms) =NULL;

static void (*esp8266_debug)(char *format, ...) =NULL;

static char *p_cmd = NULL;

#define esp8266_assert_log(log) if(esp8266_debug!=NULL) log

/**
 *
 * @param call
 */
void esp8266_set_delay_call(esp_delay_def call) {
    esp8266_delay = call;
}

void esp8266_set_debug_call(esp_debug_def call) {
    esp8266_debug = call;
}

char *esp8266_send_and_rec(char *data, uint32_t wait_time) {
    // 发送数据
    esp8266_send(data, strlen(data));
    /* 发送数据DEBUG */
    if (!esp8266_is_null(esp8266_debug) && !esp8266_is_null(data)) {
        esp8266_debug("[esp8266_send]%s\r\n", data);
    }
    // 延迟
    esp8266_asset_not_nul_run(esp8266_delay, wait_time);
    // 读取数据
    char *rec = esp8266_rec();
    /* 接收数据DEBUG */
    if (!esp8266_is_null(esp8266_debug) && !esp8266_is_null(rec)) {
        esp8266_debug("[esp8266_rec]%s\r\n", rec);
    }
    return rec;
}

char *esp8266_send_cmd_msg(char *cmd, const char *reply1, const char *reply2, uint32_t wait_time) {
    bool flag = false;
    char *rec_data = esp8266_send_and_rec(cmd, wait_time);
    // 判断是否需要接收数据
    if (esp8266_is_null(reply1) && esp8266_is_null(reply2)) {
        return NULL;
    }
    // 接收超时
    if (esp8266_is_null(rec_data)) return NULL;
    if (!esp8266_is_null(reply1) && !esp8266_is_null(reply2)) {
        flag = (bool) strstr(rec_data, reply1) || (bool) strstr(rec_data, reply2);
    } else if (!esp8266_is_null(reply1)) {
        flag = (bool) strstr(rec_data, reply1);
    } else {
        flag = (bool) strstr(rec_data, reply2);
    }
    if (flag) {
        return rec_data;
    }
    return NULL;

}

bool esp8266_send_cmd(char *cmd, const char *reply1, const char *reply2, uint32_t wait_time) {
    // 清空接收缓冲区
    esp8266_clear_buf();
    char *msg = esp8266_send_and_rec(cmd, wait_time);
    if (esp8266_is_null(reply1) && esp8266_is_null(reply2)) {
        return true;
    }
    if (esp8266_is_null(msg)) {
        return false;
    }
    return true;
}
/*************************************************基础接口***************************************************/

/**
 * @brief 对WF-ESP8266模块进行AT测试启动
 * @param try_cnt 尝试次数
 * @param wait_time 设置esp8266 延迟函数回调
 * @return
 */
bool esp8266_base_at_cmd_test(uint8_t try_cnt, uint32_t wait_time) {
    esp8266_rst_pin(true);
    esp8266_asset_not_nul_run(esp8266_delay, wait_time);
    for (int i = 0; i < try_cnt; ++i) {
        if (esp8266_send_cmd("AT\r\n", OK_MSG, NULL, wait_time)) {
            return true;
        } else {
            esp8266_base_rst(false, -1);
        }
    }
    return false;
}

bool esp8266_base_ate_conf(bool en, uint32_t wait_time) {
    esp8266_assert_equal_set(wait_time, -1, LEVEL_DELAY);
    if (en) {
        return esp8266_send_cmd("ATE1\r\n", OK_MSG, NULL, wait_time);
    }
    return esp8266_send_cmd("ATE0\r\n", OK_MSG, NULL, wait_time);
}

bool esp8266_base_factory_reset_conf(uint32_t wait_time) {
    esp8266_assert_equal_set(wait_time, -1, LEVEL_DELAY);
    return esp8266_send_cmd("AT+RESTORE\r\n", OK_MSG, NULL, wait_time);
}

void esp8266_base_rst(bool soft, uint32_t wait_time) {
    esp8266_assert_equal_set(wait_time, -1, 500);
    if (soft) {
        esp8266_send_cmd("AT+RST\r\n", OK_MSG, "ready", 2500);
    } else {
        esp8266_rst_pin(false);
        esp8266_asset_not_nul_run(esp8266_delay, wait_time);
        esp8266_rst_pin(true);

    }
}

/****************************************ESP8266 WIFI 配置**************************************************/
/**
 * @brief 设置当前 Wi-Fi 模式,@note 不保存到 Flash
 * @param mode
 *          ap_mode     设置 ESP8266 SoftAP
 *          sta_mode    设置 ESP8266 Station
 *          sta_ap_mode 设置 ESP8266 SoftAP 和 Station
 * @param wait_time
 * @return
 */
bool esp8266_wifi_mode_cur_set(esp8266_net_mode mode, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, LEVEL_DELAY);
    p_cmd = esp8266_get_cmd_buf();
    sprintf(p_cmd, "AT+CWMODE_CUR=%d\r\n", mode);
    return esp8266_send_cmd(p_cmd, OK_MSG, NULL, wait_time);
}
/**
 * @brief 临时连接 AP
 *  @note
 *      1. 参数设置需要开启 Station 模式,相关配置请查看 @see esp8266_wifi_mode_cur_set
 *      2. 若 SSID 或者password 中含有特殊符号,例如 , 或者 “ 或者 \ 时,需要进行转义,其它字符转义无效。
 * @param ssid WiFi名称字符串
 * @param pwd WiFi密码字符串
 * @param bssid 目标 AP 的 MAC 地址(可选配置)
 * @param wait_time 等待响应的时间 (-1,默认为 3000 )
 * @return
 */
bool esp8266_wifi_join_cur_set(char *ssid, char *pwd, char *bssid, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, 3000);
    p_cmd = esp8266_get_cmd_buf();
    if (bssid == NULL) {
        sprintf(p_cmd, "AT+CWJAP_CUR=\"%s\",\"%s\"\r\n", ssid, pwd);

    } else {
        sprintf(p_cmd, "AT+CWJAP_CUR=\"%s\",\"%s\",\"%s\"\r\n", ssid, pwd, bssid);
    }
    return esp8266_send_cmd(p_cmd, OK_MSG, NO_CHANGE_MSG, wait_time);
}
/**
 * @brief 断开与 AP 的连接
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_wifi_disconnect(int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, LEVEL_DELAY);
    return esp8266_send_cmd("AT+CWQAP\r\n", OK_MSG, NO_CHANGE_MSG, wait_time);
}
/**
 * @brief 配置 ESP8266 SoftAP 当前参数
 *  @note 指令只有在 SoftAP 模式开启后有效,相关配置请查看 @see esp8266_wifi_mode_cur_set
 * @param ssid WiFi名称字符串
 * @param pwd WiFi密码字符串
 * @param channel 通道号
 * @param psd_mode 加密方式,不支持 WEP
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_wifi_conf_cur_set(char *ssid, char *pwd, uint8_t channel,
                               esp8266_ap_psd_mode psd_mode, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, LEVEL_DELAY);
    p_cmd = esp8266_get_cmd_buf();
    sprintf(p_cmd, "AT+CWSAP_CUR=\"%s\",\"%s\",%d,%d\r\n", ssid, pwd, channel, psd_mode);
    return esp8266_send_cmd(p_cmd, OK_MSG, NULL, wait_time);
}
/****************************************ESP8266 DHCP 配置**************************************************/

/**
 * @brief 设置 DHCP,不保存到 Flash
 *          设置指令: AT+CWDHCP=,
 *          响应结果: OK
 * @param mode
 *          ap_mode     设置 ESP8266 SoftAP
 *          sta_mode    设置 ESP8266 Station
 *          sta_ap_mode 设置 ESP8266 SoftAP 和 Station
 * @param en
 *          true:  开启DHCP
 *          false: 关闭DHCP
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_dhcp_cur_set(esp8266_net_mode mode, bool en, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, DELAY_500);
    p_cmd = esp8266_get_cmd_buf();
    sprintf(p_cmd, "AT+CWDHCP_CUR=%d,%d\r\n", mode, en);

    return esp8266_send_cmd(p_cmd, OK_MSG, NULL, wait_time);
}

/**
 * @brief 设置 ESP8266 SoftAP DHCP 分配的 IP 范围,不不保存到 Flash
 * @param en
 *      false: 清除设置 IP 范围,恢复默认值,后续参数无需填写
 *      true: 使能设置 IP 范围,后续参数必须填写
 * @param lease_min 租约时间,单位:分钟,取值范围 [1, 2880]
 * @param start_ip DHCP 服务器 IP 池的起始 IP
 * @param end_ip   DHCP 服务器 IP 池的结束 IP
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_dhcp_ip_cur_set(bool en, uint16_t lease_min, char *start_ip, char *end_ip, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, DELAY_500);
    p_cmd = esp8266_get_cmd_buf();
    if (en) {
        sprintf(p_cmd, "AT+CWDHCPS_CUR=1,%d,\"%s\",\"%s\"\r\n", lease_min, start_ip, end_ip);
    } else {
        sprintf(p_cmd, "AT+CWDHCPS_CUR=0\r\n");
    }
    return esp8266_send_cmd(p_cmd, OK_MSG, NULL, wait_time);
}
/****************************************ESP8266 MAC地址 配置**************************************************/
/**
 * @brief 设置 ESP8266 Station 当前 MAC 地址,不保存到 Flash
 *  @note
 *      1. ESP8266 SoftAP 和 Station 的 MAC 地址并不相同,请勿将其设置为同一 MAC 地址。
 *      2. ESP8266 MAC 地址第一个字节的 bit 0 不不能为 1,例如,MAC 地址可以为 "18:…" 但不不能为 "15:…"。
 * @param mac mac地址
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_mac_sta_cur_set(char *mac, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, DELAY_500);
    p_cmd = esp8266_get_cmd_buf();
    sprintf(p_cmd, "AT+CIPSTAMAC_CUR=\"%s\"\r\n", mac);
    return esp8266_send_cmd(p_cmd, OK_MSG, NULL, wait_time);
}
/**
 * @brief 设置 ESP8266 SoftAP 当前 MAC 地址,不保存到 Flash
 *  @note
 *      1. ESP8266 SoftAP 和 Station 的 MAC 地址并不相同,请勿将其设置为同一 MAC 地址。
 *      2. ESP8266 MAC 地址第一个字节的 bit 0 不不能为 1,例如,MAC 地址可以为 "18:…" 但不不能为 "15:…"。
 * @param mac mac地址
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_mac_ap_cur_set(char *mac, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, DELAY_500);
    p_cmd = esp8266_get_cmd_buf();
    sprintf(p_cmd, "AT+CIPAPMAC_CUR=\"%s\"\r\n", mac);
    return esp8266_send_cmd(p_cmd, OK_MSG, NULL, wait_time);
}
/****************************************ESP8266 IP地址 配置**************************************************/
/**
 * @brief 设置 ESP8266 Station 的 IP 地址,不不保存到 Flash
 *  @note
 *      1. 本设置指令与设置 DHCP 的指令(AT+CWDHCP 系列列)互相影响:
 *          ‣ 设置静态 IP,则 DHCP 关闭;
 *          ‣ 设置使能 DHCP,则静态 IP ⽆无效;
 *          ‣ 以最后的设置为准。
 * @param ip 字符串串, ESP8266 Station 的 IP 地址
 * @param gw 网关
 * @param sub 子⽹网掩码
 * @param wait_time  等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_ip_sta_cur_set(char *ip, char *gw, char *sub, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, DELAY_500);
    p_cmd = esp8266_get_cmd_buf();
    if (!esp8266_is_null(gw) && !esp8266_is_null(sub)) {
        sprintf(p_cmd, "AT+CIPSTA_CUR=\"%s\",\"%s\",\"%s\"\r\n", ip, gw, sub);
    } else {
        sprintf(p_cmd, "AT+CIPSTA_CUR=\"%s\"\r\n", ip);
    }
    return esp8266_send_cmd(p_cmd, OK_MSG, NO_CHANGE_MSG, wait_time);
}
/**
 * @brief 设置 ESP8266 SoftAP 的 IP 地址,不保存到 Flash
 *  @note
 *      1. 本设置指令与设置 DHCP 的指令(AT+CWDHCP 系列)互相影响: @see esp8266_dhcp_cur_set
 *          ‣ 设置静态 IP,则 DHCP 关闭;
 *          ‣ 设置使能 DHCP,则静态 IP 无效;
 *          ‣ 以最后的设置为准。
 *      2. 目前仅支持 C 类 IP 地址
 * @param ip 字符串,
 * @param gw 网关
 * @param sub 子网掩码
 * @param wait_time  等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_ip_ap_cur_set(char *ip, char *gw, char *sub, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, DELAY_500);
    p_cmd = esp8266_get_cmd_buf();
    if (!esp8266_is_null(gw) && !esp8266_is_null(sub)) {
        sprintf(p_cmd, "AT+CIPAP_CUR=\"%s\",\"%s\",\"%s\"\r\n", ip, gw, sub);
    } else {
        sprintf(p_cmd, "AT+CIPAP_CUR=\"%s\"\r\n", ip);
    }
    return esp8266_send_cmd(p_cmd, OK_MSG, NO_CHANGE_MSG, wait_time);
}

/****************************************ESP8266 功能指令**************************************************/


esp8266_link_status esp8266_net_link_status(int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, 200);
    p_cmd = esp8266_get_cmd_buf();
    char *msg = esp8266_send_cmd_msg("AT+CIPSTATUS\r\n", OK_MSG, NULL, wait_time);
    if (esp8266_is_null(msg)) {
        return link_error;
    }
    if (strstr(msg, "STATUS:2\r\n"))
        return link_get_ip;
    else if (strstr(msg, "STATUS:3\r\n"))
        return link_established;
    else if (strstr(msg, "STATUS:4\r\n"))
        return link_lose_connect;
    return link_error;
}

/**
 * @brief 建立 TCP 连接,UDP 传输或 SSL 连接(单连接)
 * @param type
 *      1: tcp
 *      2: udp
 *      3: ssl
 * @param server_addr 服务器地址
 * @param port 服务器端口
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_net_single_socket_build(uint8_t type, char *server_addr, uint16_t port, int wait_time) {
    char *pro = type == 1 ? "TCP" : type == 2 ? "UDP" : type == 3 ? "SSL" : NULL;
    if (pro == NULL) return false;
    esp8266_assert_equal_set(wait_time, -1, DELAY_500);
    p_cmd = esp8266_get_cmd_buf();
    sprintf(p_cmd, "AT+CIPSTART=\"%s\",\"%s\",%d\r\n", pro, server_addr, port);
    return esp8266_send_cmd(p_cmd, OK_MSG, "CONNECTED", wait_time);
}
/**
 * @brief  建立 TCP 连接,UDP 传输或 SSL 连接(多连接)
 * @param type
 *      1: tcp
 *      2: udp
 *      3: ssl
 * @param link_id 网络连接 ID (0 ~ 4),用于多连接的情况
 * @param server_addr 服务器地址
 * @param port 服务器端口
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_net_mul_socket_build(uint8_t type, uint8_t link_id, char *server_addr, uint16_t port, int wait_time) {
    char *pro = type == 1 ? "TCP" : type == 2 ? "UDP" : type == 3 ? "SSL" : NULL;
    if (pro == NULL || link_id > 4) return false;
    esp8266_assert_equal_set(wait_time, -1, DELAY_500);
    p_cmd = esp8266_get_cmd_buf();
    sprintf(p_cmd, "AT+CIPSTART=%d,\"%s\",\"%s\",%d\r\n", link_id, pro, server_addr, port);
    return esp8266_send_cmd(p_cmd, OK_MSG, "CONNECTED", wait_time);
}
/**
 * @brief 关闭 TCP/UDP/SSL 传输
 *      AT+CIPCLOSE=
 *      @note
 *          需要关闭的连接 ID 号。当 ID 为 5 时,关闭所有连接。(开启 server 后 ID 为 5 无效)
 * @param id
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_socket_close(esp8266_id_no id, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, LEVEL_DELAY);
    p_cmd = esp8266_get_cmd_buf();
    if (id < 5) {
        sprintf(p_cmd, "AT+CIPCLOSE=%d\r\n", id);
    } else {
        sprintf(p_cmd, "AT+CIPCLOSE\r\n");
    }
    return esp8266_send_cmd(p_cmd, OK_MSG, NULL, wait_time);
}
/*************************************************ESP8266 服务器和客户端通用***************************************************/
/**
 * @brief WF-ESP8266模块启动多连接
 *      @note
 *          1. 默认为单连接;
 *          2. 只有⾮透传模式 (AT+CIPMODE=0),才能设置为多连接
 *          3. 必须在没有连接建⽴的情况下,设置连接模式;
 *          4. 如果建⽴了 TCP 服务器,想切换为单连接,必须关闭服务器 (AT+CIPSERVER=0),服务器仅⽀持多连接
 * @param en true: 多连接模式;false 单连接模式
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_mul_connect_set(bool en, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, 500);
    p_cmd = esp8266_get_cmd_buf();
    sprintf(p_cmd, "AT+CIPMUX=%d\r\n", en);
    return esp8266_send_cmd(p_cmd, OK_MSG, NULL, wait_time);
}
/*************************************************ESP8266 服务端***************************************************/
/**
 * @brief 设置服务器允许建⽴立的最大连接数。
 *  @note
 *      1.如需设置最⼤大连接数,请在创建服务器之前设置。
 * @param mx_conn 连接数(范围是 1-5)
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_server_connect_num_set(uint8_t mx_conn, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, LEVEL_DELAY);
    if (mx_conn < 1 || mx_conn > 5) return false;
    p_cmd = esp8266_get_cmd_buf();
    sprintf(p_cmd, "AT+CIPSERVERMAXCONN=%d\r\n", mx_conn);
    return esp8266_send_cmd(p_cmd, OK_MSG, NULL, wait_time);
}
/**
 * @brief 设置 TCP 服务器超时时间
 *     @note
 *          1. ESP8266 作为 TCP 服务器,会断开一直不通信直至超时了的 TCP 客户端连接
 *          2. 如果设置 AT+CIPSTO=0,则永远不会超时,不建议这样设置
 * @param timeout TCP 服务器超时时间,取值范围 0 ~ 7200s
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_server_tcp_timeout_set(uint16_t timeout, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, LEVEL_DELAY);
    p_cmd = esp8266_get_cmd_buf();
    sprintf(p_cmd, "AT+CIPSTO=%d\r\n", timeout);
    return esp8266_send_cmd(p_cmd, OK_MSG, NULL, wait_time);
}
/**
 * @brief tcp 服务器建立
 *  @note
 *      1. 多连接情况下 (AT+CIPMUX=1),才能开启 TCP 服务器。
 *      2. 创建 TCP 服务器后,自动建立 TCP 服务器监听。
 *      3. 当有 TCP 客户端接⼊入,会自动占用一个连接 ID。
 * @param en
 *      true:   开启服务器
 *      false: 关闭服务器
 * @param port 端口
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_server_tcp_start(bool en, uint16_t port, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, LEVEL_DELAY);
    p_cmd = esp8266_get_cmd_buf();
    sprintf(p_cmd, "AT+CIPSERVER=%d,%d\r\n", en, port);
    return esp8266_send_cmd(p_cmd, OK_MSG, NULL, wait_time);
}
/**
 * @brief 普通模式下发送数据
 * @param ucId 客户端连接id号
 * @param data 发送的字符串
 * @param len 发送的字符串的长度
 * @param wait_time 等待响应的时间 (-1,默认为 100 )
 * @return
 */
bool esp8266_server_tcp_send_to(esp8266_id_no ucId, char *data, uint16_t len, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, 100);
    p_cmd = esp8266_get_cmd_buf();
    if (ucId < 5) {
        sprintf(p_cmd, "AT+CIPSEND=%d,%d\r\n", ucId, len);
    } else {
        sprintf(p_cmd, "AT+CIPSEND=%d\r\n", len);
    }
    esp8266_send_cmd(p_cmd, NULL, NULL, wait_time);
    return esp8266_send_cmd(data, NULL, NULL, wait_time);
}
/*************************************************ESP8266 客户端***************************************************/
/**
 * @brief 设置传输模式
 *          AT+CIPMODE=
 * @param en true: 透传模式;false 普通模式
 *      @note
 *          1. 透传模式,仅⽀支持 TCP 单连接和 UDP 固定通信对端的情况
 *          2. 本设置不不保存到 Flash。
 *          3. 透传模式传输时,如果连接断开, ESP8266 会不不停尝试重连,此时单独输⼊入 +++ 退出透传,则停⽌止重连;
 *             普通传输模式则不会重连,提示连接断开。
 *
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
bool esp8266_transmission_mode_enter(bool en, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, 500);
    p_cmd = esp8266_get_cmd_buf();
    sprintf(p_cmd, "AT+CIPMODE=%d\r\n", en);
    if (esp8266_send_cmd(p_cmd, OK_MSG, NULL, wait_time)) {
        return esp8266_send_cmd("AT+CIPSEND\r\n", "SEND OK", 0, wait_time);
    }
    return false;
}

/**
 * @brief 配置WF-ESP8266模块关闭透传模式
 * @param wait_time 等待响应的时间 (-1,默认为 500 )
 * @return
 */
void esp8266_transmission_mode_exit(int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, 500);
    // 延迟
    esp8266_send_cmd("+++", NULL, NULL, wait_time);
    esp8266_asset_not_nul_run(esp8266_delay, wait_time * 2);
}

static volatile bool tcp_closed_flag;

void esp8266_tcp_update_closed_flag(bool close_status) {
    tcp_closed_flag = close_status;
}

bool esp8266_tcp_read_closed_flag() {
    return tcp_closed_flag;
}
/*************************************************API接口***************************************************/
bool esp8266_ip_ap_inquire(char *ret_ip, uint8_t len, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, 500);
    p_cmd = esp8266_get_cmd_buf();
    char *msg = esp8266_send_cmd_msg("AT+CIFSR\r\n", OK_MSG, NULL, wait_time);
    if (esp8266_is_null(msg)) {
        return false;
    }
    char *pCh = strstr(msg, "APIP,\"");
    if (pCh) {
        pCh += 6;
    } else {
        return 0;
    }
    for (uint8_t uc = 0; uc < len; uc++) {
        ret_ip[uc] = *(pCh + uc);
        if (ret_ip[uc] == '\"') {
            ret_ip[uc] = '\0';
            break;
        }
    }
    return true;
}


bool esp8266_send_str(esp8266_id_no ucId, bool already_tm_flag, char *str, uint32_t len, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, 1000);
    p_cmd = esp8266_get_cmd_buf();
    bool bRet = false;
    if (already_tm_flag) {
        esp8266_send(str, len);
        bRet = true;
    } else {
        if (ucId < 5)
            sprintf(p_cmd, "AT+CIPSEND=%d,%d\r\n", ucId, len + 2);
        else
            sprintf(p_cmd, "AT+CIPSEND=%lu\r\n", len + 2);

        bRet = esp8266_send_cmd(p_cmd, "SEND OK", 0, wait_time);
    }

    return bRet;
}

char *esp8266_transmission_mode_send(char *str, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, 100);
    p_cmd = esp8266_get_cmd_buf();
    /*清除上一次接收的缓存数据*/
    esp8266_clear_buf();
    return esp8266_send_and_rec(str, wait_time);
}

/*************************************************ESP 查询相关指令***************************************************/
/**
 * @brief 查询本地 IP 地址
 *  @note
 *      1. ESP8266 Station IP 需连上 AP 后,才可以查询。
 * @param dstIp 保存查询结果
 * @param len dstIp的长度
 * @param wait_time
 * @return
 */
bool esp8266_ip_sta_inquire(char *dstIp, uint8_t len, int wait_time) {
    esp8266_assert_equal_set(wait_time, -1, LEVEL_DELAY);
    char *result = esp8266_send_cmd_msg("AT+CIFSR\r\n", OK_MSG, NULL, wait_time);
    esp8266_assert_log(esp8266_debug("esp8266_ip_sta_inquire: %s", result));
    char *ptr = strstr(result, "STAIP,\"");
    if (ptr == NULL) return false;
    ptr += 7;
    for (uint8_t i = 0; i < len; ++i) {
        dstIp[i] = ptr[i];
        if (ptr[i] == '\"') {
            ptr[i] = '\0';
            break;
        }
    }
    return true;
}

下一篇

  1. 对编写的驱动进行测试

你可能感兴趣的:(stm32,单片机,嵌入式硬件)