現在想讓STM32 W5500通過HTTP Client POST的方式提交數據到遠程服務器,並接收服務返回的JSON格式數據,解析和處理。
實現以上功能,需要具備幾個條件:
1、STM32 W5500的基礎配置,使得PC和W5500在同一個局域網內,PC可以PING通W5500。
2、STM32 W5500的TCP Client可以成功發數據,HTTP協議是基於TCP協議之上封裝的協議。
3、遠程服務器接口可以訪問,可以通過POSTMAN工具先測試。
4、使用WireShark工具,追蹤POSTMAN訪問服務接口的報文數據,以及返回的報文數據。
STM32 W5500的基礎配置和TCP Client我已具備條件,下面看下遠程服務器接口是否可以訪問:
Header部分:
Request Body和Response Body
接口返回了JSON 結構數據,說明接口是可以訪問的。
打開WireShark工具,追蹤一下POSTMAN訪問的流數據,以及服務器返回的響應報文數據。
請求數據的追蹤
接口返回的報文數據追蹤
基礎準備工作已經做好,那麼STM32 W5500 Http Client POST請求的實現,由於一些信息比較敏感,對代碼做了處理:
httppost.c
#ifndef __HTTPPOST_H
#define __HTTPPOST_H
#include "httppost.h"
#endif
u16 func_pack_httppost_body(char *buff_body, char *productId, char *deviceSn, char *deviceMac, char *devicePassword, char *hardwareVersion)
{
u16 len;
len = sprintf(buff_body, "a=%s&b=%s&c=%s&d=%s&e=%s",\
productId, deviceSn, deviceMac, devicePassword, hardwareVersion);
return len;
}
u16 func_pack_httppost_head_body(char *buff_post, char *url_tail, u8 *host, u16 port, char *body, u16 body_len)
{
u16 len;
len = sprintf(buff_post, "POST %s HTTP/1.1\r\n"
"Connection: close\r\n"
"User-Agent:W5500\r\n"
"Content-Type:application/x-www-form-urlencoded\r\n"
"Host: %d.%d.%d.%d:%d\r\n"
"Content-Length: %d\r\n\r\n"
"%s\r\n", url_tail, host[0], host[1], host[2], host[3], port, body_len, body
);
return len;
}
static u16 local_port = 50000;
u8 func_http_post(u8 sock_no, u8 *rip, u16 port, char *buf_post, u16 len_post,char *buf_recv, u16 *len_recv, u16 timeout_ms)
{
u16 cnt, len;
char *body_cont;
cnt = 0;
for(;;)
{
switch(getSn_SR(sock_no))
{
case SOCK_INIT:
connect(sock_no, rip, port);
break;
case SOCK_ESTABLISHED:
send(sock_no, (u8*)buf_post, len_post);
if(getSn_IR(sock_no) & Sn_IR_CON)
{
setSn_IR(sock_no, Sn_IR_CON);
}
len = getSn_RX_RSR(sock_no);
if(len > 0)
{
memset(buf_recv, 0, len_post);
len = recv(sock_no, (u8*)buf_recv, len);
body_cont = strstr((char*)buf_recv, "HTTP/1.1 200");
if(body_cont == NULL)
{
return 2;
}
body_cont = strstr((char*)buf_recv, "\r\n\r\n");
if(body_cont != NULL)
{
len = strlen(body_cont) - 4;
memcpy(buf_recv, body_cont + 4, len);
buf_recv[len] = '\0';
*len_recv = len;
close(sock_no);
return 0;
}
}
break;
case SOCK_CLOSE_WAIT:
close(sock_no);
break;
case SOCK_CLOSED:
socket(sock_no, Sn_MR_TCP, local_port++, Sn_MR_ND);
if(local_port > 64000)
{
local_port = 50000;
}
break;
}
cnt ++;
if(cnt >= timeout_ms)
{
close(sock_no);
return 1;
}
delay_ms(1);
}
}
測試的主函數代碼:
#ifndef __STM32F10X_H
#define __STM32F10X_H
#include "stm32f10x.h"
#endif
#ifndef __Z_UTIL_TIME_H
#define __Z_UTIL_TIME_H
#include "z_util_time.h"
#endif
#ifndef __Z_HARDWARE_LED_H
#define __Z_HARDWARE_LED_H
#include "z_hardware_led.h"
#endif
#ifndef __Z_HARDWARE_SPI_H
#define __Z_HARDWARE_SPI_H
#include "z_hardware_spi.h"
#endif
#ifndef __Z_HARDWARE_USART2_H
#define __Z_HARDWARE_USART2_H
#include "z_hardware_usart2.h"
#endif
#include "w5500.h"
#include "socket.h"
#include "w5500_conf.h"
#include "dhcp.h"
#include "dns.h"
#ifndef __HTTPPOST_H
#define __HTTPPOST_H
#include "httppost.h"
#endif
char buf_send[2048];
char buf_cont[256];
int main(void)
{
DHCP_Get dhcp_get;
// u8 buf_recv[1536] = {0, };
u16 len, recv_len;
u8 res;
uint8 mac[6];
u8 remote_ip[4] = {192, 168, 1, 109};
u16 port = 8084;
init_led();
init_system_spi();
func_w5500_reset();
init_hardware_usart2_dma(115200);
getMacByLockCode(mac);
setSHAR(mac);
sysinit(txsize, rxsize);
setRTR(2000);
setRCR(3);
//USART DMA problem 2byte missing
func_usart2_dma_send_bytes(mac, 2);
delay_ms(100);
//DHCP
for(;func_dhcp_get_ip_sub_gw(1, mac, &dhcp_get, 500) != 0;);
if(func_dhcp_get_ip_sub_gw(1, mac, &dhcp_get, 500) == 0)
{
setSUBR(dhcp_get.sub);
setGAR(dhcp_get.gw);
setSIPR(dhcp_get.lip);
}
len = func_pack_httppost_body(buf_cont, "", "", "", "", "");
// pack http message
len = func_pack_httppost_head_body(buf_send, "/a/b/c/d/create", remote_ip, port, buf_cont, len);
// res = func_httpc_post(0, remote_ip, port, buf_send, len, buf_send, &recv_len, 1000, 5000);
res = func_http_post(0, remote_ip, port, buf_send, len, buf_send, &recv_len, 1000);
if(res == 0)
{
func_usart2_dma_send_bytes((u8*)buf_send, recv_len);
}
for(;;)
{
func_led1_on();
delay_ms(1000);
func_led1_off();
delay_ms(1000);
}
}
測試的結果,解析報文的body,並通過串口打印出來:
通過16進制轉字符串轉換一下,看看結果