#申请原创# @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;
- }
|