打印
[应用方案]

APM32实现MQTT通信(二)_实现ESP8266模块的socket接口函数,以提供MQTTClient库底层数据收发接口

[复制链接]
146|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
luobeihai|  楼主 | 2024-12-12 00:31 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

#申请原创# @21小跑堂

上一篇文章(https://bbs.21ic.com/icview-3420436-1-1.html),我们已经移植好了MQTTClient源码,这篇文件将介绍实现MQTTClient源码,基于ESP8266模块的Socket函数接口,从而提供底层的数据收发接口给MQTTClient库。

1. 需要实现哪些函数

MQTTClient库我使用的是 jiejie 写的,GitHub 仓库:https://github.com/jiejieTop/mqttclient

其中,里面有一个与平台相关的目录下,platform_net_socket.c 这个C文件里面的一些函数是需要实现,才能真的的去连接 MQTT 服务器、收发数据等。


打开这个文件,里面已经使用了 LwIP 的接口实现了这些函数了,但是我这里是需要使用 ESP8266 WIFI 模块进行网络连接,数据收发等功能,所以我需要使用 ESP8266 的来实现这些平台 socket 相关的接口函数。

实现的代码中,是依赖前面写的 AT 命令收发解析器的代码的,《APM32F407+FreeRTOS实现AT模块的命令解析器》这篇文件中有介绍,链接:https://bbs.21ic.com/icview-3418740-1-1.html

这个文件里面定义了有8个函数,但实际其实只要实现4个函数即可,分别是:socket 连接、数据收发、socket 关闭这四个函数,如下:

int platform_net_socket_connect(const char *host, const char *port, int proto)
{
    return 0;
}

int platform_net_socket_recv_timeout(int fd, unsigned char *buf, int len, int timeout)
{
    return 0;
}

int platform_net_socket_write_timeout(int fd, unsigned char *buf, int len, int timeout)
{
    return 0;
}

int platform_net_socket_close(int fd)
{
    return 0;
}

2. 各个函数的具体实现

把实现的代码单独写为一个C文件,at_socket_esp8266.c ,然后按照上面 mqtt 平台相关的那4个函数类型,实现4个与 esp8266 模块的 socket 函数,从而给上面的平台网络层代码调用。

2.1 网络连接函数

int esp8266_socket_connect(const char *host, const char *port, int proto)
{
        int result = 0;
        char cmd[64] = {0};
        unsigned char retry_num = 5;

        esp8266_init();
       
        while (retry_num--)
        {
                /* disconnect to WiFi AP */
                result = at_exce_cmd("AT+CWQAP", NULL, 1000);
                if (result)
                {
                        printf("disconnect WiFi AP fail, status %d\r\n", result);
                        continue;
                }
               
                /* send AT commands to connect to WiFi AP */
                /* 命令格式:AT+CWJAP="SSID","password" */
                result = at_exce_cmd("AT+CWJAP=\"" ESP8266_WIFI_SSID "\",\"" ESP8266_WIFI_PASSWORD "\"", NULL, 10*1000);
                if (result)
                {
                        printf("esp8266 device connect to WiFi AP fail, check ssid(%s) and password(%s).\r\n", ESP8266_WIFI_SSID, ESP8266_WIFI_PASSWORD);
                        continue;
                }

                /* send AT commands to connect to server  */
                /* 命令格式:AT+CIPSTART="TCP","192.168.3.116",8080 */
                switch (proto)
        {
                case PLATFORM_NET_PROTO_TCP:
                                sprintf(cmd, "AT+CIPSTART=\"TCP\",\"%s\",%s", host, port);
                    break;

                case PLATFORM_NET_PROTO_UDP:
                                sprintf(cmd, "AT+CIPSTART=\"UDP\",\"%s\",%s", host, port);
                    break;

                default:
                    printf("not supported socket connect type %d.\r\n", proto);
                    goto __exit;
        }
                               
                result = at_exce_cmd(cmd, NULL, 5*1000);
                if (result == AT_RESP_OK)
                {
                        break;
                }
                else
                {
                        printf("esp8266 device socket connect fail, the socket was not be closed and now will connect retry.\r\n");
                        at_exce_cmd("AT+CIPCLOSE", NULL, 300);
                        continue;
                }
        }

__exit:
    return result;
}


2.2 网络数据接收

int esp8266_socket_recv_timeout(int fd, unsigned char *buf, int len, int timeout)
{
        int result = 0;
        char ch = 0;
        unsigned int read_index = 0;

       
        for (read_index = 0; read_index < len; read_index++)
        {
                result = at_client_recvchar(&ch, timeout);
                if (result)
                {               
                        //printf("esp8266 socket receive fail, return status %d.\r\n", result);
                        return result;
                }
                buf[read_index] = ch;
        }

    return read_index;
}


2.3 网络数据发送

int esp8266_socket_write_timeout(int fd, unsigned char *buf, int len, int timeout)
{
        int result = 0;
        unsigned int cur_package_size = 0, send_size = 0;
        char cmd[32] = {0};
               
        while (send_size < len)
        {
                /* 超过最大长度,分包 */
                if (len - send_size < ESP8266_MODULE_SEND_MAX_SIZE)
                {
                        cur_package_size = len - send_size;
                }
                else
                {
                        cur_package_size = ESP8266_MODULE_SEND_MAX_SIZE;
                }

                /* 发送 AT+CIPSEND=7 命令,等待回复 '>' 这个字符( 测试发现回复的是 "OK\r\n>" ) */
                /* 如果断开了和服务器的网络连接之后,调用此命令回复的是:      "link is not valid\r\nERROR" */
                sprintf(cmd, "AT+CIPSEND=%d", cur_package_size);
                result = at_exce_cmd(cmd, NULL, timeout);
                if (result)
                {
                        printf("send cmd(%s) error or timeout.\r\n", cmd);
                        return result;
                }

                /* 发送真正数据,回复 Recv n bytes\r\nSEND OK\r\n 说明发送成功 */
                result = at_client_senddata((char *)buf + send_size, cur_package_size, timeout);
                if (result)
                {
                        printf("send data fali or timeout, return status %d.\r\n", result);
                        return result;
                }

                send_size += cur_package_size;
        }
       
    return result ? result : send_size;
}


2.4 网络断开连接

int esp8266_socket_close(int fd)
{
        int result = 0;

        result = at_exce_cmd("AT+CIPCLOSE", NULL, 300);
       
    return result;
}





使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

19

主题

71

帖子

2

粉丝