1、准备开发板
开发板功能区分布图
开发板俯视图
我们在前面实现了一个WebClient,但是缺点就是模块之间耦合度太高,还有会出现堆栈溢出的情况 ,为了解决这些问题,我重新改写了代码,对模块之间进行解耦,让大家拿到任一个模块都可以单独运行起来得到想要的结果 。
3、在MDK中编写代码
WebClient客户端代码 | |
---|
web_strdup | 将字符串复制到新开辟的内存空间 | webclient_header_fields_add | 将请求句柄封装到客户端缓存区 | webclient_header_fields_get | 解析响应数据的单一消息报头 | webclient_header_length_response | 获取请求头的长度 | webclient_handle_response | 获取服务器响应的状态码 | webclient_data_analysis | 获取服务器返回的数据包 |
HTTP请求方法 | |
---|
webclient_get_method | 客户端GET请求方法 | webclient_post_method | 客户端POST请求方法 |
????LWWC(Light Weight Web Client),即轻量Web客户端,通过一些简单的字符串处理和解析函数,可以有效的进行常用HTTP协议组包和响应解析,各个模块之间经过解耦的编程思想,模块可以独立运行得出结果。占用内存非常小,可以满足一些小型嵌入式系统HTTP/HTTPS协议开发的需求。 这里只修改了webclient的代码,其余代码参考上一章。
在lwwc.h中编写以下代码:
#ifndef __LWWC_H_
#define __LWWC_H_
#include "sys.h"
#ifndef WEBCLIENT_OK
#define WEBCLIENT_OK 0
#endif
#ifndef WEBCLIENT_NOK
#define WEBCLIENT_NOK 1
#endif
void webclient_get_method(void);
void webclient_post_method(void);
#endif
在lwwc.c中编写以下代码:
#include "lwwc.h"
#include "ESP8266.h"
#include "usart.h"
#include "StringUtil.h"
char* web_strdup(const char* s)
{
uint16_t len = strlen(s) + 1;
char* tmp = (char*)malloc(len);
if (!tmp)
return NULL;
memcpy(tmp, s, len);
return tmp;
}
unsigned int webclient_header_fields_add(char* buffer, unsigned int bufsize, const char* fmt, ...)
{
int length = strlen(buffer);
if (length >= bufsize) {
printf("Buffer uninitialized or exceeded.");
return 0;
}
va_list args;
va_start(args, fmt);
length = vsnprintf(buffer + length, bufsize, fmt, args);
if (length < 0)
{
printf("add fields header data failed, return length(%d) error.", length);
return length;
}
va_end(args);
return length;
}
int webclient_handle_response(char* buffer)
{
int rc = 0;
char* mime_ptr = NULL;
char* mime_buffer = NULL;
const char* transfer_encoding;
int i;
int resp_status;
mime_ptr = web_strdup(buffer);
if (strstr(mime_ptr, "HTTP/1."))
{
char* ptr = mime_ptr;
ptr += strlen("HTTP/1.x");
while (*ptr && (*ptr == ' ' || *ptr == '\t'))
ptr++;
for (i = 0; ((ptr[i] != ' ') && (ptr[i] != '\t')); i++);
ptr[i] = '\0';
resp_status = (int)strtol(ptr, NULL, 10);
}
if (mime_ptr)
{
free(mime_ptr);
}
return resp_status;
}
const char* webclient_header_fields_get(char* resp_buf, const char* fields)
{
char* dataPtr;
char* mime_ptr = NULL;
dataPtr = strstr(resp_buf,fields);
if(dataPtr != NULL)
{
mime_ptr = strstr(dataPtr,":");
if(mime_ptr != NULL)
{
mime_ptr += 1;
while (*mime_ptr && (*mime_ptr == ' ' || *mime_ptr == '\t'))
mime_ptr++;
return mime_ptr;
}
}
return NULL;
}
uint8_t* webclient_data_analysis(char* buffer)
{
char* dataptr;
dataptr = strstr(buffer,"\r\n\r\n");
if(dataptr != NULL)
{
dataptr += 4;
return (uint8_t*)dataptr;
}
return NULL;
}
void webclient_get_method(void)
{
uint8_t uwRet = WEBCLIENT_NOK;
uint8_t *dataPtr;
char* mime_ptr = (char*)netDeviceInfo.netIOInfo->rxBuf;
char postBuf[200];
memset(postBuf,0,sizeof(postBuf));
webclient_header_fields_add(postBuf,sizeof(postBuf),"GET https://api.seniverse.com/v3/weather/now.json?key=smtq3n0ixdggurox&location=nanning&language=en&unit=c HTTP/1.1\r\n");
webclient_header_fields_add(postBuf,sizeof(postBuf),"Host:www.baidu.com\r\n");
webclient_header_fields_add(postBuf,sizeof(postBuf),"\r\n");
if(ESP8266_DisconnectServer(0) != ESP8266_OK)
return;
if(ESP8266_Link_Server(enumTCP,"api.seniverse.com","80",Single_ID_0) == ESP8266_OK)
{
uwRet = ESP8266_SendData(DISABLE,(uint8_t*)postBuf,strlen(postBuf),Single_ID_0);
if(uwRet == WEBCLIENT_OK)
{
dataPtr = ESP8266_GetIPD(DISABLE,2000);
if(dataPtr != NULL)
{
if(webclient_handle_response((char*)dataPtr) == 200)
{
dataPtr = webclient_data_analysis((char*)dataPtr);
if(dataPtr != NULL)
{
if(strstr((char*)dataPtr,"+IPD,"))
{
dataPtr = Filter_string((char*)dataPtr,(char*)"+IPD,",(char*)":");
if(dataPtr!=NULL)
{
printf("dataPtr:%s\r\n",dataPtr);
}
}
else
{
printf("dataPtr:%s\r\n",dataPtr);
}
}
}
}
}
}
}
void webclient_post_method(void)
{
uint8_t uwRet = WEBCLIENT_NOK;
uint8_t *dataPtr;
char* mime_ptr = (char*)netDeviceInfo.netIOInfo->rxBuf;
char postBuf[200];
memset(postBuf,0,sizeof(postBuf));
webclient_header_fields_add(postBuf,sizeof(postBuf),"POST /devices/583402349/datapoints HTTP/1.1\r\n");
webclient_header_fields_add(postBuf,sizeof(postBuf),"api-key:rBIh6FFxeyW=kVJyybB2FzD5QAQ=\r\n");
webclient_header_fields_add(postBuf,sizeof(postBuf),"Host: api.heclouds.com\r\n");
webclient_header_fields_add(postBuf,sizeof(postBuf),"Content-Length:66\r\n");
webclient_header_fields_add(postBuf,sizeof(postBuf),"\r\n");
webclient_header_fields_add(postBuf,sizeof(postBuf),"{\"datastreams\":[{\"id\":\"test_stream\",\"datapoints\":[{\"value\":30}]}]}");
if(ESP8266_DisconnectServer(0) != ESP8266_OK)
return;
if(ESP8266_Link_Server(enumTCP,"api.heclouds.com","80",Single_ID_0) == ESP8266_OK)
{
uwRet = ESP8266_SendData(DISABLE,(uint8_t*)postBuf,strlen(postBuf),Single_ID_0);
if(uwRet == WEBCLIENT_OK)
{
dataPtr = ESP8266_GetIPD(DISABLE,5000);
if(dataPtr != NULL)
{
if(webclient_handle_response((char*)dataPtr) == 200)
{
dataPtr = webclient_data_analysis((char*)dataPtr);
if(dataPtr != NULL)
{
if(strstr((char*)dataPtr,"+IPD,"))
{
dataPtr = Filter_string((char*)dataPtr,(char*)"+IPD,",(char*)":");
if(dataPtr!=NULL)
{
printf("dataPtr:%s\r\n",dataPtr);
}
}
else
{
printf("dataPtr:%s\r\n",dataPtr);
}
}
}
}
}
}
}
在main.c中编写以下代码
int main(void)
{
unsigned char* dataPtr = NULL;
uint32_t request_time = 0;
ESP8266_RETTYPE uwRet = ESP8266_NOK;
uint32_t request_method=0;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_LPUART1_UART_Init();
MX_USART1_UART_Init();
MX_TIM2_Init();
TIM_Interupt_Enable();
USART_Interupt_Enable();
while (1)
{
if(!netDeviceInfo.netWork)
{
if(NET_DEVICE_Init() == ESP8266_OK)
{
printf("初始化成功\r\n");
}
}
if(time2Count - request_time >= 15000)
{
if(netDeviceInfo.netWork)
{
if(request_method)
{
webclient_post_method();
request_method = 0;
}
else
{
webclient_get_method();
request_method = 1;
}
}
}
}
}
4、实验现象
实现的功能 |
---|
1、上电自动连接WIFI | 2、如果是POST请求,则请求POST接口(我这里用的是ONENET的POST接口) | 3、如果是GET请求,则请求GET接口(我这里用的是心知天气的GET接口) |
POST请求(Onenet物联网平台) GET请求(心知天气)
|