STM32 + W5500 + Http client

ORIGINAL POST
By Mr_Johhny
details

20200416163607511.png

这两天在做STM32 W5500通过HTTP GET请求的方式下载bin文件,以实现OTA在线升级,到网上查了一圈,发现并没有很多有效的信息和资料。于是我就实现了一下,把思路和实现过程分享出来。

实现W5500文件下载的几个前提:

1、STM32 W5500的基础配置,使得 电脑端的CMD命令窗口能够PING通W5500,《STM32F103RC驱动W5500入网,并可ping通》

2、STM32 W5500的TCP Client收发数据测试没有问题,《STM32F1 W5500 TCP Client 回环测试》

3、一个可用的文件服务器,文件的URL地址放到浏览器的地址栏后,可以正常下载文件。

4、对HTTP协议有基本的认识。

文件的URL地址放到浏览器的地址栏后,通过Wireshark工具,先看看文件下载的过程,都发生可一些什么

下载请求的header信息,包括以下几个关键信息:

1、请求方式+接口名称+协议和协议版本(GET /file/FLASH_OPER.bin_1.1.3 HTTP/1.1rn)

2、文件服务器主机IP+端口 (举例:192.168.1.105:8888rn)

3、连接状态(Connection: Keep-Alivern)

4、请求端名称(User-Agent: W5500rn)

5、请求端接收的编码(Accept-Encoding: gzip,deflatern)

6、请求头结束标记(rn)

以上是请求的分析,文件服务器返回的信息如下:

从文件服务器返回来的数据分析,报文和文件内容不是一次性传输的,是流的方式多次传输的。

返回的报文,包含以下几个关键点:

1、返回的状态码(HTTP/1.1 200rn)

2、接收范围 字节流(Accept-Ranges: bytesrn)

3、内容长度(Content-Length: 3904rn)

4、头结束标记(rn)

5、字节流Data长度和Content-Length是相等的。

以上是基于浏览器下载文件的过程分析的,那么STM32 W5500下载文件的过程,模拟浏览器下载文件,从理论上来讲也是会实现的。

HTTP协议是在TCP的基础上封装的协议,W5500的TCP Client端与服务端简历连接的过程在此不描述。

STM32 W5500下载文件有几个难点:

1、解析文件服务器返回的报文,判断返回码是否为200,只有200才代表成功;判断是否为字节流;解析出文件的大小(长度)

2、文件字节流和返回报文的分割,以及缓存数组的数据反复搬运(毕竟W5500 一次最多可以收2Kbytes 的数据)。

3、判断文件下载是否完成的依据。

STM32 W5500请求和接收的过程:

即发送一次请求报文后,不断接收文件服务器返回的信息,结果是要么接收到文件字节流和 Content-Length的相等,文件下载成功,要么各种原因失败(连接超时,读取超时,返回码不正确,不是字节流等)。

好像该讲的都讲了,下面给出STM32 W5500 Http GET方式下载文件的代码(我测试下载 4k/13k/67k 左右的文件都可以),例程中打印了 各个分支的log信息,将文件下载的内容通过串口DMA的方式打印出来。(工程可以看我的 基础配置文章下载,再将这个主测试函数替换)

  1. #ifndef __STM32F10X_H
  2. #define __STM32F10X_H
  3. #include “stm32f10x.h”
  4. #endif
  5. #ifndef __Z_UTIL_TIME_H
  6. #define __Z_UTIL_TIME_H
  7. #include “z_util_time.h”
  8. #endif
  9. #ifndef __Z_HARDWARE_LED_H
  10. #define __Z_HARDWARE_LED_H
  11. #include “z_hardware_led.h”
  12. #endif
  13. #ifndef __Z_HARDWARE_SPI_H
  14. #define __Z_HARDWARE_SPI_H
  15. #include “z_hardware_spi.h”
  16. #endif
  17. #ifndef __W5500_H
  18. #define __W5500_H
  19. #include “w5500.h”
  20. #endif
  21. #ifndef __SOCKET_H
  22. #define __SOCKET_H
  23. #include “socket.h”
  24. #endif
  25. #ifndef __W5500_CONF_H
  26. #define __W5500_CONF_H
  27. #include “w5500_conf.h”
  28. #endif
  29. #ifndef __DHCP_H
  30. #define __DHCP_H
  31. #include “dhcp.h”
  32. #endif
  33. #ifndef __Z_HARDWARE_USART2_H
  34. #define __Z_HARDWARE_USART2_H
  35. #include “z_hardware_usart2.h”
  36. #endif
  37. #include <stdlib.h>
  38. void log_net(char *log);
  39. void func_pack_http_get_download_header(u8* buff, u16 size_buff, u8* srv_ip, u16 srv_port, char* interface);
  40. u8 func_http_get_download_file(u8 sockno, u8* srv_ip, u16 srv_port, char* interface, u16 timeout_ms, u8* buff, u16 size_buff);
  41. u8 func_analysis_http_download_header(u8* buffer, u16 len_buf, u8 *resp_code, u8 *is_stream, u32 *cont_len);
  42. u8 buf[2048];
  43. int main(void)
  44. {
  45. u8 mac[6]={0, };
  46. DHCP_Get dhcp_get;
  47. //FIXME input your server ip to download file
  48. u8 srv_ip[] = {192, 168, 1, 105};
  49. u16 srv_port = 8888;
  50. systick_configuration();
  51. init_led();
  52. init_hardware_usart2_dma(115200);
  53. init_system_spi();
  54. func_w5500_reset();
  55. getMacByLockCode(mac);
  56. setSHAR(mac);
  57. sysinit(txsize, rxsize);
  58. setRTR(2000);
  59. setRCR(3);
  60. //USART DMA problem: 2 bytes missing
  61. func_usart2_dma_send_bytes(mac, 2);
  62. delay_ms(100);
  63. //DHCP
  64. for(;func_dhcp_get_ip_sub_gw(1, mac, &dhcp_get, 500) != 0;);
  65. if(func_dhcp_get_ip_sub_gw(1, mac, &dhcp_get, 500) == 0)
  66. {
  67. setSUBR(dhcp_get.sub);
  68. setGAR(dhcp_get.gw);
  69. setSIPR(dhcp_get.lip);
  70. close(1);
  71. log_net(“0”);
  72. }
  73. memset(buf, 0 , sizeof(buf));
  74. func_http_get_download_file(0, srv_ip, srv_port, “/file/FLASH_OPER.bin_1.1.3”, 5000, buf, sizeof(buf));
  75. for(;;)
  76. {
  77. func_led1_toggle();
  78. delay_ms(500);
  79. }
  80. }
  81. u8 func_http_get_download_file(u8 sockno, u8* srv_ip, u16 srv_port, char* interface, u16 timeout_ms, u8* buff, u16 size_buff)
  82. {
  83. u16 local_port = 60000, len = 0, cnt = 0;
  84. u8 sendok = 0, recv_start = 0;
  85. u8 cache[2048];
  86. u16 cache_cont_len;
  87. u32 cont_len, download_cont_len;
  88. func_pack_http_get_download_header(buff, size_buff, srv_ip, srv_port, interface);
  89. // setkeepalive(sockno);//auto
  90. IINCHIP_WRITE(Sn_KPALVTR(sockno),0x00);//manual
  91. memset(cache, 0 , sizeof(cache));
  92. cache_cont_len = 0;
  93. for(;;)
  94. {
  95. switch(getSn_SR(sockno))
  96. {
  97. case SOCK_INIT:
  98. connect(sockno, srv_ip, srv_port);
  99. break;
  100. case SOCK_ESTABLISHED:
  101. {
  102. if(sendok == 0)
  103. {
  104. log_net(“1”);
  105. len = strlen((char *)buff);
  106. send(sockno, buff, len);
  107. sendok ++;
  108. if(getSn_IR(sockno) & Sn_IR_CON)
  109. {
  110. setSn_IR(sockno, Sn_IR_CON);
  111. break;
  112. }
  113. }
  114. len = getSn_RX_RSR(sockno);
  115. if(len > 0)
  116. {
  117. cnt = 0;
  118. memset(buff, 0, size_buff);
  119. len = recv(sockno, buff, len);
  120. if(recv_start == 0)
  121. {
  122. u8 res, resp_code, isstream;
  123. log_net(“2”);
  124. if(cache_cont_len + len <= sizeof(cache))
  125. {
  126. log_net(“3”);
  127. memcpy(cache+cache_cont_len, buff, len);
  128. cache_cont_len += len;
  129. memset(buff, 0, size_buff);
  130. len = 0;
  131. }
  132. else
  133. {
  134. u32 len_copy;
  135. log_net(“4”);
  136. len_copy = sizeof(cache) – cache_cont_len;
  137. memcpy(cache+cache_cont_len, buff, len_copy);
  138. memcpy(buff, buff + len_copy, len – len_copy);
  139. memset(buff + (len – len_copy), 0, size_buff – (len – len_copy));
  140. len = len – len_copy;
  141. cache_cont_len = sizeof(cache);
  142. }
  143. res = func_analysis_http_download_header(cache, cache_cont_len, &resp_code, &isstream, &cont_len);
  144. if(res == 0)
  145. {
  146. if(resp_code != 200 || isstream != 1)//response code 200, must be iostream
  147. {
  148. log_net(“22”);
  149. return 3;// response not ok
  150. }
  151. recv_start++;
  152. //logic -> file size should be no more than 108 Kbytes
  153. if(cont_len > 108*1024)
  154. {
  155. log_net(“23”);
  156. return 4;
  157. }
  158. //if download file done
  159. {
  160. u32 tmp_len;
  161. u8* pos_header;
  162. pos_header = (u8*)strstr((char*)cache, “rnrn”);
  163. //remove header, save file byte to cache
  164. tmp_len = cache_cont_len – (pos_header + 4 – cache);
  165. memcpy(cache, pos_header + 4, tmp_len);
  166. memset(cache + tmp_len, 0 , sizeof(cache) – tmp_len);
  167. cache_cont_len = tmp_len;
  168. download_cont_len = cache_cont_len;
  169. if(len > 0)
  170. {
  171. if(cache_cont_len + len <= sizeof(cache))
  172. {
  173. log_net(“5”);
  174. memcpy(cache+cache_cont_len, buff, len);
  175. cache_cont_len += len;
  176. download_cont_len += len;
  177. memset(buff, 0, size_buff);
  178. len = 0;
  179. }
  180. else
  181. {
  182. u32 len_copy;
  183. log_net(“6”);
  184. len_copy = sizeof(cache) – cache_cont_len;
  185. memcpy(cache+cache_cont_len, buff, len_copy);
  186. memcpy(buff, buff + len_copy, len – len_copy);
  187. memset(buff + (len – len_copy), 0, size_buff – (len – len_copy));
  188. len = len – len_copy;
  189. cache_cont_len = sizeof(cache);
  190. //TODO write to FLASH backup
  191. func_usart2_dma_send_bytes(cache, cache_cont_len);
  192. memset(cache, 0, cache_cont_len);
  193. cache_cont_len = 0;
  194. memcpy(cache+cache_cont_len, buff, len);
  195. cache_cont_len = len;
  196. download_cont_len = sizeof(cache) + cache_cont_len;
  197. }
  198. }
  199. if(download_cont_len == cont_len)// small file download done
  200. {
  201. log_net(“7”);
  202. func_usart2_dma_send_bytes(cache, cache_cont_len);
  203. //TODO write to FLASH backup and record
  204. disconnect(sockno);
  205. return 0;//download file done
  206. }
  207. }
  208. }
  209. }
  210. else
  211. {
  212. IINCHIP_WRITE(Sn_CR(sockno),Sn_CR_SEND_KEEP);//keep-alive manual
  213. //file size is big, write to FALSH several times
  214. download_cont_len += len;
  215. if(cache_cont_len + len <= sizeof(cache))
  216. {
  217. log_net(“8”);
  218. memcpy(cache+cache_cont_len, buff, len);
  219. cache_cont_len += len;
  220. memset(buff, 0, size_buff);
  221. len = 0;
  222. }
  223. else
  224. {
  225. u32 len_copy;
  226. log_net(“9”);
  227. len_copy = sizeof(cache) – cache_cont_len;
  228. memcpy(cache+cache_cont_len, buff, len_copy);
  229. memcpy(buff, buff + len_copy, len – len_copy);
  230. memset(buff + (len – len_copy), 0, size_buff – (len – len_copy));
  231. len = len – len_copy;
  232. cache_cont_len = sizeof(cache);
  233. //TODO write to FLASH backup
  234. func_usart2_dma_send_bytes(cache, cache_cont_len);
  235. memset(cache, 0, cache_cont_len);
  236. cache_cont_len = 0;
  237. memcpy(cache+cache_cont_len, buff, len);
  238. cache_cont_len = len;
  239. }
  240. //if donwload file done
  241. if(download_cont_len == cont_len)
  242. {
  243. log_net(“10”);
  244. //TODO write to FLASH backup and record
  245. func_usart2_dma_send_bytes(cache, cache_cont_len);
  246. disconnect(sockno);
  247. return 0;//download file done
  248. }
  249. }
  250. }
  251. }
  252. break;
  253. case SOCK_CLOSE_WAIT:
  254. close(sockno);
  255. log_net(“21”);
  256. return 2;//read timeout
  257. case SOCK_CLOSED:
  258. close(sockno);
  259. sendok = 0;
  260. recv_start = 0;
  261. if(local_port > 65400)
  262. {
  263. local_port = 60000;
  264. }
  265. socket(sockno, Sn_MR_TCP, local_port++, Sn_MR_ND);
  266. break;
  267. }
  268. cnt ++;
  269. if(cnt >= timeout_ms)
  270. {
  271. log_net(“20”);
  272. return 1;//connect timeout
  273. }
  274. delay_ms(1);
  275. }
  276. }
  277. u8 func_analysis_http_download_header(u8* buffer, u16 len_buf, u8 *resp_code, u8 *is_stream, u32 *cont_len)
  278. {
  279. *resp_code = 0;
  280. *is_stream = 0;
  281. *cont_len = 0;
  282. if(strstr((char*)buffer, “rnrn”) != NULL)//response header ok
  283. {
  284. char *p1, *p2;
  285. p1 = strstr((char*)buffer, “HTTP/1.1 200”);
  286. if(p1 != NULL)// io stream
  287. {
  288. *resp_code = 200;
  289. }
  290. p1 = strstr((char*)buffer, “Accept-Ranges: bytes”);
  291. if(p1 != NULL)// io stream
  292. {
  293. *is_stream = 1;
  294. }
  295. p1 = strstr((char*)buffer, “Content-Length: “);
  296. if(p1 != NULL)
  297. {
  298. p2 = strstr(p1, “rn”);
  299. if(p2 != NULL)
  300. {
  301. char str_len[8] = {0,};
  302. memcpy(str_len, p1 + strlen(“Content-Length: “), p2 – p1 – strlen(“Content-Length: “));
  303. *cont_len = atoi(str_len);
  304. return 0;
  305. }
  306. }
  307. }
  308. return 1;
  309. }
  310. void log_net(char *log)
  311. {
  312. u8 logsrv_ip[] = {192, 168, 1, 105};
  313. socket(2, Sn_MR_UDP, 7890, 0x00);
  314. sendto(2, (u8*)log, strlen(log), logsrv_ip, 9876);
  315. }
  316. void func_pack_http_get_download_header(u8* buff, u16 size_buff, u8* srv_ip, u16 srv_port, char* interface)
  317. {
  318. u8 tmp[64];
  319. memset(buff, 0, size_buff);
  320. //header
  321. memcpy(buff, “GET “, strlen(“GET “));
  322. strcat((char *)buff, interface);
  323. strcat((char *)buff, ” HTTP/1.1rn”);
  324. memset(tmp, 0 , sizeof(tmp));
  325. sprintf((char*)tmp, “Host: %d.%d.%d.%d:%drn”, srv_ip[0], srv_ip[1], srv_ip[2], srv_ip[3], srv_port);
  326. strcat((char *)buff, (char*)tmp);
  327. strcat((char *)buff, “Connection: Keep-Alivern”);
  328. strcat((char *)buff, “User-Agent: W5500rn”);
  329. strcat((char *)buff, “Accept-Encoding: gzip,deflatern”);
  330. strcat((char *)buff, “rn”);
  331. }

最后,附上我测试的效果图:

串口打印的字节数和 Content-Length的长度一致,并和原bin文件做了对比,内容一致。

20200416163607511.png

这两天在做STM32 W5500通过HTTP GET请求的方式下载bin文件,以实现OTA在线升级,到网上查了一圈,发现并没有很多有效的信息和资料。于是我就实现了一下,把思路和实现过程分享出来。

实现W5500文件下载的几个前提:

1、STM32 W5500的基础配置,使得 电脑端的CMD命令窗口能够PING通W5500,《STM32F103RC驱动W5500入网,并可ping通》

2、STM32 W5500的TCP Client收发数据测试没有问题,《STM32F1 W5500 TCP Client 回环测试》

3、一个可用的文件服务器,文件的URL地址放到浏览器的地址栏后,可以正常下载文件。

4、对HTTP协议有基本的认识。

文件的URL地址放到浏览器的地址栏后,通过Wireshark工具,先看看文件下载的过程,都发生可一些什么

下载请求的header信息,包括以下几个关键信息:

1、请求方式+接口名称+协议和协议版本(GET /file/FLASH_OPER.bin_1.1.3 HTTP/1.1rn)

2、文件服务器主机IP+端口 (举例:192.168.1.105:8888rn)

3、连接状态(Connection: Keep-Alivern)

4、请求端名称(User-Agent: W5500rn)

5、请求端接收的编码(Accept-Encoding: gzip,deflatern)

6、请求头结束标记(rn)

以上是请求的分析,文件服务器返回的信息如下:

从文件服务器返回来的数据分析,报文和文件内容不是一次性传输的,是流的方式多次传输的。

返回的报文,包含以下几个关键点:

1、返回的状态码(HTTP/1.1 200rn)

2、接收范围 字节流(Accept-Ranges: bytesrn)

3、内容长度(Content-Length: 3904rn)

4、头结束标记(rn)

5、字节流Data长度和Content-Length是相等的。

以上是基于浏览器下载文件的过程分析的,那么STM32 W5500下载文件的过程,模拟浏览器下载文件,从理论上来讲也是会实现的。

HTTP协议是在TCP的基础上封装的协议,W5500的TCP Client端与服务端简历连接的过程在此不描述。

STM32 W5500下载文件有几个难点:

1、解析文件服务器返回的报文,判断返回码是否为200,只有200才代表成功;判断是否为字节流;解析出文件的大小(长度)

2、文件字节流和返回报文的分割,以及缓存数组的数据反复搬运(毕竟W5500 一次最多可以收2Kbytes 的数据)。

3、判断文件下载是否完成的依据。

STM32 W5500请求和接收的过程:

即发送一次请求报文后,不断接收文件服务器返回的信息,结果是要么接收到文件字节流和 Content-Length的相等,文件下载成功,要么各种原因失败(连接超时,读取超时,返回码不正确,不是字节流等)。

好像该讲的都讲了,下面给出STM32 W5500 Http GET方式下载文件的代码(我测试下载 4k/13k/67k 左右的文件都可以),例程中打印了 各个分支的log信息,将文件下载的内容通过串口DMA的方式打印出来。(工程可以看我的 基础配置文章下载,再将这个主测试函数替换)

  1. #ifndef __STM32F10X_H
  2. #define __STM32F10X_H
  3. #include “stm32f10x.h”
  4. #endif
  5. #ifndef __Z_UTIL_TIME_H
  6. #define __Z_UTIL_TIME_H
  7. #include “z_util_time.h”
  8. #endif
  9. #ifndef __Z_HARDWARE_LED_H
  10. #define __Z_HARDWARE_LED_H
  11. #include “z_hardware_led.h”
  12. #endif
  13. #ifndef __Z_HARDWARE_SPI_H
  14. #define __Z_HARDWARE_SPI_H
  15. #include “z_hardware_spi.h”
  16. #endif
  17. #ifndef __W5500_H
  18. #define __W5500_H
  19. #include “w5500.h”
  20. #endif
  21. #ifndef __SOCKET_H
  22. #define __SOCKET_H
  23. #include “socket.h”
  24. #endif
  25. #ifndef __W5500_CONF_H
  26. #define __W5500_CONF_H
  27. #include “w5500_conf.h”
  28. #endif
  29. #ifndef __DHCP_H
  30. #define __DHCP_H
  31. #include “dhcp.h”
  32. #endif
  33. #ifndef __Z_HARDWARE_USART2_H
  34. #define __Z_HARDWARE_USART2_H
  35. #include “z_hardware_usart2.h”
  36. #endif
  37. #include <stdlib.h>
  38. void log_net(char *log);
  39. void func_pack_http_get_download_header(u8* buff, u16 size_buff, u8* srv_ip, u16 srv_port, char* interface);
  40. u8 func_http_get_download_file(u8 sockno, u8* srv_ip, u16 srv_port, char* interface, u16 timeout_ms, u8* buff, u16 size_buff);
  41. u8 func_analysis_http_download_header(u8* buffer, u16 len_buf, u8 *resp_code, u8 *is_stream, u32 *cont_len);
  42. u8 buf[2048];
  43. int main(void)
  44. {
  45. u8 mac[6]={0, };
  46. DHCP_Get dhcp_get;
  47. //FIXME input your server ip to download file
  48. u8 srv_ip[] = {192, 168, 1, 105};
  49. u16 srv_port = 8888;
  50. systick_configuration();
  51. init_led();
  52. init_hardware_usart2_dma(115200);
  53. init_system_spi();
  54. func_w5500_reset();
  55. getMacByLockCode(mac);
  56. setSHAR(mac);
  57. sysinit(txsize, rxsize);
  58. setRTR(2000);
  59. setRCR(3);
  60. //USART DMA problem: 2 bytes missing
  61. func_usart2_dma_send_bytes(mac, 2);
  62. delay_ms(100);
  63. //DHCP
  64. for(;func_dhcp_get_ip_sub_gw(1, mac, &dhcp_get, 500) != 0;);
  65. if(func_dhcp_get_ip_sub_gw(1, mac, &dhcp_get, 500) == 0)
  66. {
  67. setSUBR(dhcp_get.sub);
  68. setGAR(dhcp_get.gw);
  69. setSIPR(dhcp_get.lip);
  70. close(1);
  71. log_net(“0”);
  72. }
  73. memset(buf, 0 , sizeof(buf));
  74. func_http_get_download_file(0, srv_ip, srv_port, “/file/FLASH_OPER.bin_1.1.3”, 5000, buf, sizeof(buf));
  75. for(;;)
  76. {
  77. func_led1_toggle();
  78. delay_ms(500);
  79. }
  80. }
  81. u8 func_http_get_download_file(u8 sockno, u8* srv_ip, u16 srv_port, char* interface, u16 timeout_ms, u8* buff, u16 size_buff)
  82. {
  83. u16 local_port = 60000, len = 0, cnt = 0;
  84. u8 sendok = 0, recv_start = 0;
  85. u8 cache[2048];
  86. u16 cache_cont_len;
  87. u32 cont_len, download_cont_len;
  88. func_pack_http_get_download_header(buff, size_buff, srv_ip, srv_port, interface);
  89. // setkeepalive(sockno);//auto
  90. IINCHIP_WRITE(Sn_KPALVTR(sockno),0x00);//manual
  91. memset(cache, 0 , sizeof(cache));
  92. cache_cont_len = 0;
  93. for(;;)
  94. {
  95. switch(getSn_SR(sockno))
  96. {
  97. case SOCK_INIT:
  98. connect(sockno, srv_ip, srv_port);
  99. break;
  100. case SOCK_ESTABLISHED:
  101. {
  102. if(sendok == 0)
  103. {
  104. log_net(“1”);
  105. len = strlen((char *)buff);
  106. send(sockno, buff, len);
  107. sendok ++;
  108. if(getSn_IR(sockno) & Sn_IR_CON)
  109. {
  110. setSn_IR(sockno, Sn_IR_CON);
  111. break;
  112. }
  113. }
  114. len = getSn_RX_RSR(sockno);
  115. if(len > 0)
  116. {
  117. cnt = 0;
  118. memset(buff, 0, size_buff);
  119. len = recv(sockno, buff, len);
  120. if(recv_start == 0)
  121. {
  122. u8 res, resp_code, isstream;
  123. log_net(“2”);
  124. if(cache_cont_len + len <= sizeof(cache))
  125. {
  126. log_net(“3”);
  127. memcpy(cache+cache_cont_len, buff, len);
  128. cache_cont_len += len;
  129. memset(buff, 0, size_buff);
  130. len = 0;
  131. }
  132. else
  133. {
  134. u32 len_copy;
  135. log_net(“4”);
  136. len_copy = sizeof(cache) – cache_cont_len;
  137. memcpy(cache+cache_cont_len, buff, len_copy);
  138. memcpy(buff, buff + len_copy, len – len_copy);
  139. memset(buff + (len – len_copy), 0, size_buff – (len – len_copy));
  140. len = len – len_copy;
  141. cache_cont_len = sizeof(cache);
  142. }
  143. res = func_analysis_http_download_header(cache, cache_cont_len, &resp_code, &isstream, &cont_len);
  144. if(res == 0)
  145. {
  146. if(resp_code != 200 || isstream != 1)//response code 200, must be iostream
  147. {
  148. log_net(“22”);
  149. return 3;// response not ok
  150. }
  151. recv_start++;
  152. //logic -> file size should be no more than 108 Kbytes
  153. if(cont_len > 108*1024)
  154. {
  155. log_net(“23”);
  156. return 4;
  157. }
  158. //if download file done
  159. {
  160. u32 tmp_len;
  161. u8* pos_header;
  162. pos_header = (u8*)strstr((char*)cache, “rnrn”);
  163. //remove header, save file byte to cache
  164. tmp_len = cache_cont_len – (pos_header + 4 – cache);
  165. memcpy(cache, pos_header + 4, tmp_len);
  166. memset(cache + tmp_len, 0 , sizeof(cache) – tmp_len);
  167. cache_cont_len = tmp_len;
  168. download_cont_len = cache_cont_len;
  169. if(len > 0)
  170. {
  171. if(cache_cont_len + len <= sizeof(cache))
  172. {
  173. log_net(“5”);
  174. memcpy(cache+cache_cont_len, buff, len);
  175. cache_cont_len += len;
  176. download_cont_len += len;
  177. memset(buff, 0, size_buff);
  178. len = 0;
  179. }
  180. else
  181. {
  182. u32 len_copy;
  183. log_net(“6”);
  184. len_copy = sizeof(cache) – cache_cont_len;
  185. memcpy(cache+cache_cont_len, buff, len_copy);
  186. memcpy(buff, buff + len_copy, len – len_copy);
  187. memset(buff + (len – len_copy), 0, size_buff – (len – len_copy));
  188. len = len – len_copy;
  189. cache_cont_len = sizeof(cache);
  190. //TODO write to FLASH backup
  191. func_usart2_dma_send_bytes(cache, cache_cont_len);
  192. memset(cache, 0, cache_cont_len);
  193. cache_cont_len = 0;
  194. memcpy(cache+cache_cont_len, buff, len);
  195. cache_cont_len = len;
  196. download_cont_len = sizeof(cache) + cache_cont_len;
  197. }
  198. }
  199. if(download_cont_len == cont_len)// small file download done
  200. {
  201. log_net(“7”);
  202. func_usart2_dma_send_bytes(cache, cache_cont_len);
  203. //TODO write to FLASH backup and record
  204. disconnect(sockno);
  205. return 0;//download file done
  206. }
  207. }
  208. }
  209. }
  210. else
  211. {
  212. IINCHIP_WRITE(Sn_CR(sockno),Sn_CR_SEND_KEEP);//keep-alive manual
  213. //file size is big, write to FALSH several times
  214. download_cont_len += len;
  215. if(cache_cont_len + len <= sizeof(cache))
  216. {
  217. log_net(“8”);
  218. memcpy(cache+cache_cont_len, buff, len);
  219. cache_cont_len += len;
  220. memset(buff, 0, size_buff);
  221. len = 0;
  222. }
  223. else
  224. {
  225. u32 len_copy;
  226. log_net(“9”);
  227. len_copy = sizeof(cache) – cache_cont_len;
  228. memcpy(cache+cache_cont_len, buff, len_copy);
  229. memcpy(buff, buff + len_copy, len – len_copy);
  230. memset(buff + (len – len_copy), 0, size_buff – (len – len_copy));
  231. len = len – len_copy;
  232. cache_cont_len = sizeof(cache);
  233. //TODO write to FLASH backup
  234. func_usart2_dma_send_bytes(cache, cache_cont_len);
  235. memset(cache, 0, cache_cont_len);
  236. cache_cont_len = 0;
  237. memcpy(cache+cache_cont_len, buff, len);
  238. cache_cont_len = len;
  239. }
  240. //if donwload file done
  241. if(download_cont_len == cont_len)
  242. {
  243. log_net(“10”);
  244. //TODO write to FLASH backup and record
  245. func_usart2_dma_send_bytes(cache, cache_cont_len);
  246. disconnect(sockno);
  247. return 0;//download file done
  248. }
  249. }
  250. }
  251. }
  252. break;
  253. case SOCK_CLOSE_WAIT:
  254. close(sockno);
  255. log_net(“21”);
  256. return 2;//read timeout
  257. case SOCK_CLOSED:
  258. close(sockno);
  259. sendok = 0;
  260. recv_start = 0;
  261. if(local_port > 65400)
  262. {
  263. local_port = 60000;
  264. }
  265. socket(sockno, Sn_MR_TCP, local_port++, Sn_MR_ND);
  266. break;
  267. }
  268. cnt ++;
  269. if(cnt >= timeout_ms)
  270. {
  271. log_net(“20”);
  272. return 1;//connect timeout
  273. }
  274. delay_ms(1);
  275. }
  276. }
  277. u8 func_analysis_http_download_header(u8* buffer, u16 len_buf, u8 *resp_code, u8 *is_stream, u32 *cont_len)
  278. {
  279. *resp_code = 0;
  280. *is_stream = 0;
  281. *cont_len = 0;
  282. if(strstr((char*)buffer, “rnrn”) != NULL)//response header ok
  283. {
  284. char *p1, *p2;
  285. p1 = strstr((char*)buffer, “HTTP/1.1 200”);
  286. if(p1 != NULL)// io stream
  287. {
  288. *resp_code = 200;
  289. }
  290. p1 = strstr((char*)buffer, “Accept-Ranges: bytes”);
  291. if(p1 != NULL)// io stream
  292. {
  293. *is_stream = 1;
  294. }
  295. p1 = strstr((char*)buffer, “Content-Length: “);
  296. if(p1 != NULL)
  297. {
  298. p2 = strstr(p1, “rn”);
  299. if(p2 != NULL)
  300. {
  301. char str_len[8] = {0,};
  302. memcpy(str_len, p1 + strlen(“Content-Length: “), p2 – p1 – strlen(“Content-Length: “));
  303. *cont_len = atoi(str_len);
  304. return 0;
  305. }
  306. }
  307. }
  308. return 1;
  309. }
  310. void log_net(char *log)
  311. {
  312. u8 logsrv_ip[] = {192, 168, 1, 105};
  313. socket(2, Sn_MR_UDP, 7890, 0x00);
  314. sendto(2, (u8*)log, strlen(log), logsrv_ip, 9876);
  315. }
  316. void func_pack_http_get_download_header(u8* buff, u16 size_buff, u8* srv_ip, u16 srv_port, char* interface)
  317. {
  318. u8 tmp[64];
  319. memset(buff, 0, size_buff);
  320. //header
  321. memcpy(buff, “GET “, strlen(“GET “));
  322. strcat((char *)buff, interface);
  323. strcat((char *)buff, ” HTTP/1.1rn”);
  324. memset(tmp, 0 , sizeof(tmp));
  325. sprintf((char*)tmp, “Host: %d.%d.%d.%d:%drn”, srv_ip[0], srv_ip[1], srv_ip[2], srv_ip[3], srv_port);
  326. strcat((char *)buff, (char*)tmp);
  327. strcat((char *)buff, “Connection: Keep-Alivern”);
  328. strcat((char *)buff, “User-Agent: W5500rn”);
  329. strcat((char *)buff, “Accept-Encoding: gzip,deflatern”);
  330. strcat((char *)buff, “rn”);
  331. }

最后,附上我测试的效果图:

串口打印的字节数和 Content-Length的长度一致,并和原bin文件做了对比,内容一致。

COMMENTS

Please Login to comment
  Subscribe  
Notify of
POSTED BY