你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F407 + LAN8720A + LWIP 实现TCP服务器

[复制链接]
STMCU小助手 发布时间:2022-4-11 10:16
环境说明:* U( ?6 b4 q& L9 N$ D+ J1 r
开发板:某宝买的,STM32F407IG( V1 V2 P6 f" v- U
STM32CUBEMX5.6
: c* T) T  }% [' IHAL Lib Version 1.25( ~+ W" B2 @9 H
; u+ I. G8 |: f2 ~# Y9 x
(一)配置时钟
/ }: y+ U* r- F3 b2 a( y2 Q& s' p; E, ?6 c% \: c+ \% I
20200521102314536.png & j/ q- F% q; d2 X
8 {4 J, O3 {& k' s' }
(二)配置调试串口
1 x8 ~$ F" M4 l( i* u" T6 g
, d) o& Z/ k% `1 i" h$ j
I6]UV8_AXHHT@95MQAJ(1YH.png
" B& d' F( u- j5 E, J9 m# X3 R% X
(三)配置以太网ETH

% m0 O1 q8 J! A9 ?(1)基础配置
/ N4 j, f+ P; t9 A- ?+ F' n. ?: ?8 Z8 X1 ~. y$ ^9 F' f  J' J
2020052015571192.png
; j5 d- _/ Z0 z  l- u$ b# C7 p: K& @' o* G: t
顺序依次说明:: C& l) ?7 n* z+ u# S3 @  g( `, `
LAN8720A使用的是RMII接口进行配置寄存器# m2 V7 \% B! V0 }$ @% ]; K8 V/ O
自动重连使能
7 x% c0 Y) n# m3 b) sMAC地址1 n- F- R: C2 O% q4 J2 G1 Q1 _8 ]
LAN8720A的物理地址(类似IIC的从设备地址),0或者1,LAN8720A上电后会读取RXER/PHYAD0引脚状态以此来确定设备地址,这里需要根据你自己实际的原理图进行配置,我的原理图是该引脚是悬空的,所以默认就是0。( \' d7 d7 J4 |+ F4 j- m4 t: y' V0 f
8 G- h  E( r$ B3 v! {( k# c
6T9{3DM_%]8`[7_TFFGM`YL.png
+ J3 H+ V* t6 h' z" E* D# P. x5 L9 k# q1 W' o
接收模式:可选轮询和中断,我选择了轮询模式。(注:在STM32CUBEMX中如果开启了LWIP那么只能选择轮询模式,实际上是可以使用中断方式的,不过需要自己移植修改lwip协议栈,课参考正点原子)
  s; V% P0 g- Y4 ~( [/ Q1 S; \
( w9 H7 h# z! u* Z8 ^8 A校验:可选软件和硬件,我选择了由硬件去校验$ J% v4 o# C9 b0 e+ F

! n0 K. r$ F  f5 F# P8 Y  `& N除此之外还有一个复位引脚ETH_RST,拉低是复位LAN8720A,根据你实际的原理图连线配置该IO为复用输出功能即可。
) a& n8 {/ i# \! t! [/ f" K
+ B, _0 Y9 j+ j8 s1 @(2)高级配置
& F# ~2 p* Q+ Q8 D6 U" A/ C' d8 S. n* N, X) J0 E  p; @5 b+ }
20200520161703441.png / T- d/ Y4 i4 z& x
      看下图,此处的配置就是根据实际的PHY芯片寄存器进行配置了,默认的是LAN8742A,而我们使用的是LAN8720A,所以需要更改为 user PHY,配置项默认即可。. j8 ^  Z, x' E  E+ B, y- A

  G1 ~% k# n* a- N 20200520162350617.png " ^" M/ ~# ?1 P0 w4 {7 p

/ S3 G, O; z* @( J5 x对于默认配置,我们将默认配置与LAN8720A的数据手册进行对比然后检查是否正确,以PHY Reset这一项为例,默认值是0x8000,去查看数据手册:
9 g$ S/ g/ A- _) M0 c0 E) B4 ]4 Z0 |2 x( c$ W" m8 ?
BL~P[AYE[9F0MU$]%5G]_96.png
# i0 D" x5 H- k& T7 r/ I2 i( j  R5 T3 u  c6 l
由上图的基本控制寄存器表可知该寄存器偏移地址为0,大小是16位,第15位是软件复位控制,=1是复位,默认为0,那么如果想要复位LAN8720A就需要将该寄存器的第15位置一,也就是0x8000,对比STM32CUBE的默认配置发现一致,其他配置项同理也是这么检查,检查完毕后发现默认配置是OK的。
% L8 e# p, f5 @% j: }5 k$ l: {5 r+ F
$ ]" A: T4 {% m2 {( ^配置LWIP协议栈- D* `9 C- t& C& `
- g, R9 d: k1 r% c( D9 j) W
_CUFRU6Z`A3ICCW4DR1SC%I.png
& S  x# z& _+ M7 S& |: `* P3 x
" w( E; j1 H# w. O" Q如上图,需要开启状态改变回调函数和连接状态改变回调函数,否则无法实现网线的热拔插。' N5 P4 O+ ?' f% T; f6 `, J& a
# v5 \5 g' G: ^/ A1 e! ~* i' q" o" z
工程代码修改# c- V1 t% o1 }4 V
文件ethernetif.c中找到函数low_level_init函数,添加复位LAN8720A代码:  f+ z" |" a+ l. E9 \7 v$ {

. `# i8 }! n# D& e# p 20200521094048989.png $ e0 G- ^3 I3 C( E
+ x# z6 v' O% h) u. q' O
在main函数的主循环中调用函数MX_LWIP_Process。& I+ O+ e3 Z$ d
修改MX_LWIP_Process函数,在其中加入:
" u  Q; B; z0 }# G  s, s" a0 N2 t
20200521095027706.png
7 G/ ~) v2 {/ r$ v, ?6 t$ Q, g* D! O- c: y1 c! K& R6 r
这个函数的作用是检测当前网线的连接状态,如果状态发生改变(例如网线被拔插了一下),那么就会调用回调函数ethernetif_update_config,看函数名就知道这是更新配置,而这个函数尾部又调用了函数ethernetif_notify_conn_changed,看函数名可知道函数作用是通知连接状态改变,所以我们就更改此函数来达到热拔插自动重连的目的。
! p, X7 ^/ W( o0 N" O4 Y( p
( z# c5 q  m+ W0 S# S 20200521100726742.png
# J& ^, y) s$ t7 ?1 Q( _2 P0 J* R
到此,连接上网线ping测试一下即可。& E; t! e2 y# c
6 o  l2 G# i0 b2 W7 Q, Y* W6 X
(四)TCP服务器代码# D  ~: c. _: W9 n1 w3 }
下面代码的流程是:接收来自客户端的数据->将数据从lwip中拷贝出来->发回去。
0 F, f4 B: L& s1 J- G( U- X" @4 x( L3 D
  1. #if 1
    3 D9 C3 Q3 R7 G. L* m! M

  2. , b1 V! S; t: |  E$ p8 m
  3. #include <stdio.h>
      E5 O$ |) {% C: \9 J% V+ D0 U0 m
  4. #include <string.h>
    8 B/ t9 c8 F$ e5 d( O8 x
  5. #include <stdint.h>
    ! @# _, u+ @5 G
  6. #include "lwip/tcp.h"" F# f5 O. v6 D8 v- L& X% p
  7. #include "lwip/err.h"+ b6 |7 l: [% {/ `4 L  Z
  8. #include "lwip/memp.h"+ B' M8 N9 _3 _- ?' f
  9. #include "lwip/inet.h"
    7 O9 }! i+ Q7 H4 u( ]# S

  10. : v4 P. i! P+ Q7 u0 |: {
  11. " e0 @, a* B, v, Z" U4 W
  12. / 回调函数控制宏 3 t0 j; z7 M1 p0 z
  13. #define USE_ERROR_CALLBACK 1
    ' Q. j" Q% o& Q* L
  14. #define USE_SENT_CALLBACK 06 X2 @$ S# U8 m! d
  15. #define USE_POLL_CALLBACK 0
    ! H: m  d+ c8 h: K5 J2 A* t

  16. * K7 d3 `# O) x# T, R$ c

  17. : J& m7 ~8 h* z; J$ q

  18. 5 O  m* `; z- [1 T% X
  19. / 调试信息输出 //& K) V3 Y) |+ I- a
  20. #define DEBUG3 K( n1 f2 J( p3 @8 M2 P" I1 V& E. d
  21. . W2 H- P! F/ P3 `* \" Q
  22. #ifdef DEBUG4 e- r% h3 ?7 z: H( A3 R
  23. #define debug(fmt, ...) do{printf(fmt, ##__VA_ARGS__);}while(0)( l* g9 k" i( n0 s( e
  24. #else
    8 v. ~/ A8 z5 w8 {, y
  25. #define debug(fmt, ...) do{;}while(0)& {' n. d) h. g' z
  26. #endif
    # U# t, a+ h- i

  27. - |" {7 y: s9 V8 f1 t) |1 P0 c
  28. 6 Y5 {; @/ W! _+ @

  29. 5 O" {! A- l7 _% Z
  30. / tcp接收发送缓存 ///
    " N! g1 L/ L2 B; m
  31. #define TCP_RX_LEN  8192) O8 J5 }  B- u: C, t! y* c  ~
  32. uint8_t TCP_RX_BUF[TCP_RX_LEN];8 ~, T' x( h/ O# a0 A
  33. volatile uint16_t TCP_RX_STA = 0;  /* bit15:有无数据标志位        bit14-0:数据量计数 */+ C7 i6 I' K7 o$ x5 v
  34. # T3 A! c) T% h8 ]- F
  35. ( e/ z# T* @% `! R: R- u. W; ^

  36. # G1 `  A2 n5 u" |+ R$ {
  37. / TCP结构句柄 ///
    * v8 L9 z7 L+ v7 ~' O& W" K
  38. struct tcp_pcb* tcppcb = NULL;  `$ U3 H7 {  k4 ]" a( b

  39. " r: h  O* Z6 V4 x& }8 |, T; \
  40. 4 z0 G% U9 N0 c4 q
  41. 1 h% G0 f* z7 L- Z0 w9 x) l  {
  42. / 本地函数定义 ///! K2 o' M: u1 t' m7 ^
  43. static void tcp_server_disconnect(struct tcp_pcb *tpcb);9 l  w8 D3 Y  Y) S( D
  44. static uint32_t tcp_server_send(struct tcp_pcb *tpcb, const void* buf, uint32_t len);. V4 m9 o! L/ }6 @
  45. 7 R; m9 Z: ]% L! J
  46. , |! K: M, A, o9 N6 s

  47. 0 o+ c, F, ?2 A
  48. / 私有函数实现  ///0 u6 w0 a# I9 C! M' s
  49. $ B. M. x9 [/ n$ D
  50. #if (USE_ERROR_CALLBACK == 1)
    3 |: u4 p, X0 \) @% C) d
  51. static void error_callback(void *arg, err_t err)
    : L. w$ D' {) s5 x$ M( `( c) @
  52. {" y; M& n$ f& [6 W* M& \/ T" C
  53.         debug("\r\n error_callback:%d.", err);3 n+ \# f% D  s: ]) @5 T: a
  54. }! F* |1 k2 d5 R" \
  55. #endif  i! P: z; K+ h& @& I; e, `! D
  56. 0 w. Z  h7 p+ o' o, h/ M- r8 O. s8 t  f
  57. #if (USE_ERROR_CALLBACK == 1)  e7 K0 d' H# q- P- @, B& @
  58. static void error_callback(void *arg, err_t err)
    , X- D8 s$ E% @
  59. {
    2 W9 D2 N+ a+ V5 u# h8 M  `
  60.         debug("\r\n error_callback:%d.", err);
    . i1 N0 S3 |% a6 F) {
  61.         switch(err)0 Q6 |8 f8 T3 J* E
  62.         {* B& ]: M& z( w* _
  63.         /* PC上位机如果正常运行中闪退或者不良退出会出现这个错误,此时服务器需要释放掉连接  */
    3 ~+ H9 ~8 i# G% }+ a3 K: j
  64.         case ERR_RST:- o% j2 j9 N$ g4 F
  65.         tcp_server_disconnect(tcppcb);/ b" ]/ M9 I5 d- D! H+ B
  66.         break;
    0 y2 G! s$ Y0 B' m4 n8 z
  67.         default:break;
    . j% {% D) y' Y  |7 e2 m- h6 X
  68.         }2 v! Y: X, u: x
  69. }1 P8 T9 n4 {* T) I' z

  70.   j& u! @0 Q; W1 ?1 h# Z9 c  ^9 x; P
  71. #endif( z6 f2 x# U5 d4 O. y
  72. ( P! S9 e! P  K
  73. static err_t recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)3 `- b, A1 ]" B  j* l3 ^9 K) ~8 G
  74. {
    ' E6 I" V: ]+ ?1 O" c# U) i: E
  75.         if (p == NULL) /* 接收到空包表示对方断开连接 */
    3 ^4 z) `+ J- Z! F# W
  76.         {" Y2 Y3 t4 o8 b7 f/ T
  77.                 tcp_server_disconnect(tpcb);
    ' B; k: `0 X* P4 C; K4 y# ]2 h
  78.                 err = ERR_CLSD;  r) I1 d8 L: r/ v* q
  79.         }  ]  u( G2 D0 t$ d+ q8 z' q* q
  80.         else if (err != ERR_OK) /* 收到非空包但是出现错误 */& n$ _; F0 x9 Q% V: _: I/ o! k
  81.         {
    0 z- Z% ^, h4 D5 K2 p; g
  82.                 pbuf_free(p);! @" e. i0 L% A* j
  83.         }
    - X$ a& Q2 R& v/ O) }$ l. |
  84.         else /* 接收数据正常,遍历pbuf拷贝出接收到的数据 */6 k2 ]1 B% M2 A' O2 I
  85.         {
    ' S0 a& |7 T! i- l8 c- F' T
  86.                 struct pbuf* it = p;
    6 }; {1 U$ t( ]) G! y

  87. 8 Z7 a$ ?9 P9 R: b3 J7 f
  88.                 if ((TCP_RX_STA & 0x8000) == 0) /* 当前缓存为空  */7 t/ k7 j1 c: @: d( C5 O" }; f
  89.                 {+ m- F8 g( O& X) V5 e( Z
  90.                         for (it = p; it != NULL; it = it->next)
    " q" S7 _3 r2 U8 H3 w# J
  91.                         {
    ' Q1 f" O# j! H1 T, l/ a: P
  92.                                 if (TCP_RX_STA + it->len > TCP_RX_LEN) /* 缓存满了 */
    - W+ Z8 s( e$ {3 c0 A; w0 i
  93.                                         break;. _, D4 y) v- `9 H
  94.                                 memcpy(TCP_RX_BUF + TCP_RX_STA, it->payload, it->len);  /* 将接收到的数据拷贝到自己的缓存中  */3 m- t6 a/ a! P6 X, u4 n* ^
  95.                                 TCP_RX_STA += it->len;
    4 ~2 D  t  D* E+ L
  96.                         }. P$ y8 }+ M4 ~- k" D4 C8 q/ z
  97.                         TCP_RX_STA |= 0x8000;    /* 标记有数据收到 */
    7 i/ U3 ]) ~6 z6 x( P$ Z
  98.                 }
    . W6 s8 B5 _5 E9 t
  99.                 tcp_recved(tpcb, p->tot_len); /* 滑动TCP窗口 */7 o4 F% d) E+ i4 S. ~1 ~
  100.                 pbuf_free(p); /* 释放pbuf */5 i3 R! \  E4 }( t7 |
  101.         }
    2 k; H1 f4 M" b
  102.         return err;( u% |* @6 ]0 q3 o$ G3 l0 R
  103. }& Y" c3 r. I! f0 c1 ^6 o. @# y! q& T
  104. 7 x% Y7 H& w$ J% A( Z; I2 I
  105. " p0 G/ k7 ?7 P9 S( Q" y
  106. static err_t accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
    ( t4 R7 m5 k+ [7 X# `
  107. {( m& n" Q4 Y, `
  108.         if (tcppcb == NULL)2 k: f, X; v9 S4 F1 [% g2 i
  109.         {
    3 _9 p& v7 a, `: h1 g
  110.                 if (err == ERR_OK)
    2 `2 h: u0 L9 w  u2 O8 W* m
  111.                 {
    7 e  O4 g9 i* R8 \3 _+ L7 J
  112.                         tcppcb = newpcb;# B2 x- |% M, q  u: u9 W; k7 ]
  113.                         tcp_arg(newpcb, NULL);& x: m0 }0 r* |- U8 ]
  114.                         tcp_recv(newpcb, recv_callback);
    9 a" o8 f2 v2 j, m1 X
  115. ; d+ {4 G0 P8 i# A, Y! d
  116. #if (USE_ERROR_CALLBACK == 1)0 g+ y6 Y( a1 r/ A& ~  r) }2 |/ j/ e! y
  117.                         tcp_err(newpcb, error_callback);
    4 X) l  I* \& a; A% i
  118. #endif
    ) A1 Z9 X( Y# |( H: m" O

  119. 3 W% k& v; l8 \# ~* O
  120. #if (USE_SENT_CALLBACK == 1)4 B' b1 `1 e0 j0 o* p: @
  121.                         tcp_sent(newpcb, sent_callback);! T2 }7 E# u( s8 N% N1 W
  122. #endif, y( Y) C: a( D# j# h! G# v

  123. 8 R8 ^3 T% h8 f. z1 M8 D/ h9 e
  124. #if (USE_POLL_CALLBACK == 1)  y. x3 e" c- Y6 s: Y' M
  125.                         tcp_poll(newpcb, poll_callback, 1);; [% Z, B2 Z: e/ \3 H+ x+ U
  126. #endif; `) V  ?+ ]9 [' [' Y$ }- o; S
  127.                         debug("\r\n %s:%d connect.", inet_ntoa(newpcb->remote_ip), newpcb->remote_port);$ F: j; g0 Y1 D3 h  H  X
  128.                 }
    4 x9 Z' _; g/ }3 y* T9 |4 B
  129.                 else) Y6 z4 M! G6 t4 w2 v7 R* E
  130.                 {
    7 u5 l5 L0 F* X! c* w% v0 @
  131.                         tcp_server_disconnect(newpcb);
    0 d8 t6 g' y+ p+ C* _' a" e$ s
  132.                 }
    ; l0 r: {' _, G* h6 w# o
  133.         }, P0 z' ?4 n5 ?! g; G7 `
  134.         else  e& Q. h: q, l+ _- ~; v! r, f- @5 v
  135.         {: n% J* O+ ]3 q: |# Q# O- K; r
  136.                 tcp_abort(newpcb);. O. ?. A( [* B4 y" {# H  U2 O
  137.                 debug("\r\n already connected. ");/ w" v  _/ g( A, r
  138.         }* M) z3 }) Y" R; m# G
  139.         return err;
    / X' f( _0 ^6 {; N- w
  140. }
    ! T% S# X$ U+ S  N
  141. ) d" l1 c8 w0 i( \' ^' O) i
  142. static void tcp_server_disconnect(struct tcp_pcb *tpcb)
    5 K5 U# A! S* z4 a" |
  143. {+ f3 `4 Y" n: z& B  c8 o: C% P# [
  144.         tcp_arg(tpcb, NULL);# d% ~# C* o4 i0 b
  145.         tcp_recv(tpcb, NULL);0 x- o$ X0 P" ?2 G- y
  146. # O4 \- i+ z' _# M% r4 v& J
  147. #if (USE_SENT_CALLBACK == 1)
    4 C+ i$ c0 e8 D4 G. w. m! J
  148.         tcp_sent(tpcb, NULL);( W3 N) B" x- `8 m
  149. #endif8 F! @3 o& T0 p! V/ t9 q8 u

  150. 2 U3 n# s0 d7 L$ g
  151. #if (USE_POLL_CALLBACK == 1)) {3 w  \( g3 {7 s6 |) G5 U' I( w
  152.         tcp_poll(tpcb, NULL, 0);
    9 Y% V" E& f$ D1 Y$ ?/ Z
  153. #endif: B4 }4 e9 C7 y% c) y, b

  154. " ]' }# p8 a- {9 ]! K) j( B" P
  155. #if (USE_ERROR_CALLBACK == 1)
    ! X1 U" b7 C" Q) S) h. _7 y" u/ I
  156.         tcp_err(tpcb, NULL);
    & P7 V  V9 }) _, y' Y' f" }- j
  157. #endif, Q9 I: v- x! G, S

  158. 7 |6 i5 e+ H3 |  |
  159.         tcp_abort(tpcb); /* 关闭连接并释放tpcb控制块 */
    2 U# S; i  i% a9 i  n+ P
  160.         tcppcb = NULL;
    8 P: c- j1 L) v! u
  161.         debug("\r\n disconnected.");9 |" u$ p3 J# x7 g! O3 u* z' O: d5 ^  E
  162. }
    & w# L( k& K) w: n, N6 l* x6 F% u

  163. 3 ~7 W6 ~' c! m0 I
  164. static uint32_t tcp_server_send(struct tcp_pcb *tpcb, const void* buf, uint32_t len)
    # t+ K3 f. g1 x
  165. {
    % D4 x% @. T8 ~$ _2 |- @3 K
  166.         uint32_t nwrite = 0, total = 0;/ P; {( t/ m7 S, q8 C" K
  167.         const uint8_t* p = (const uint8_t *) buf;
    1 O1 c& p5 Y% N# O- W& z( j
  168.         err_t err = ERR_OK;
    , q5 p' m; [( y- a, a1 i! r# I6 o# n
  169.         if (!tpcb)! w" V2 P$ _# a* ~
  170.                 return 0;
    9 Q$ ~' |, M- T! I0 U, p
  171.         while ((err == ERR_OK) && (len != 0) && (tcp_sndbuf(tpcb) > 0))3 a9 n( b' W, f2 a) l
  172.         {
    9 W% C7 ?0 y  F
  173.                 nwrite = tcp_sndbuf(tpcb) >= len ? len : tcp_sndbuf(tpcb);
    ! V, n  c/ R) o
  174.                 err = tcp_write(tpcb, p, nwrite, 1);
    1 i" {7 s. w$ W7 x: P; M+ L
  175.                 if (err == ERR_OK)
    # R* w3 k+ a! q$ v$ l) Y7 X" ^( A
  176.                 {
    # x5 A% J7 G2 h/ V
  177.                         len -= nwrite;
    * o& {) v) }4 \2 n% B+ h( k
  178.                         total += nwrite;
    1 x# W- b  W$ ^7 R5 p# L0 ^3 G
  179.                         p += nwrite;) ?% t8 I, O% C, n: p6 d
  180.                 }+ X4 B* ^$ _  f5 ]
  181.                 tcp_output(tpcb);
    ; t- U" V/ D9 v+ U; |
  182.         }' y& V/ n( A. J# O& D* q
  183.         return total;
    & J0 d' E$ _- @/ e5 c
  184. }1 L2 M3 a- e6 S& X

  185. 9 g4 S; [& R& D; B+ b
  186. / 导出以下函数供外部调用 ///
    ) W$ `2 Z# a6 J6 ?; ]- V( L

  187. ! g: O. k4 W  ?) u( k$ z" @  _
  188. //extern int tcp_server_start(uint16_t port);
    - r; n6 n) T) J; H
  189. //extern int user_senddata(const void* buf,uint32_t len);
    6 y, S- W7 E; J. b: e
  190. //extern int transfer_data();" d1 G5 F, H: U  b

  191. 7 X6 M! s/ a# K
  192. , N: z) J, y5 D  G0 k
  193. /**1 H( p* y# W2 u! d, h  s
  194. * 启动TCP服务器; \6 ^: i3 \& }5 c  ]$ Q% ~: I' \
  195. * @param  port 本地端口号3 r* g. e& M- I9 Z5 ]; o
  196. * @return      成功返回0# Y6 @: m  B0 h- m, i5 N, ]
  197. */
    2 G0 {8 g# w0 B# S' T, y
  198. int tcp_server_start(uint16_t port)* @/ \9 R" a4 H4 ?! e" p
  199. {; @+ l. e  A7 |8 R# v
  200.         int ret = 0;
    - g3 G" x8 |; }% }$ D7 F; x( K$ @# E
  201.         struct tcp_pcb* pcb = NULL;% V/ j, @- O, V
  202.         err_t err = ERR_OK;/ y9 B8 G$ f# s$ v: o) c* x
  203. . i5 J$ J( e) Q" x
  204.         /* create new TCP PCB structure */
    " P1 g5 v$ V- ]1 s6 W
  205.         pcb = tcp_new();$ ?7 H3 C9 @& l
  206.         if (!pcb). O1 V& U1 a5 e6 y4 S: Y, q4 S% N3 K
  207.         {
    . v& Z3 I) D. O- H, x9 F0 `0 M2 n
  208.                 debug("Error creating PCB. Out of Memory\n\r");% Y; O, w6 h6 H3 X% F0 X! a, {
  209.                 ret = -1;
    % `: B* g) Q9 A0 `' Z1 T
  210.                 goto __exit;: o6 v  o5 E5 @
  211.         }+ q: `, ^0 S4 H+ A( z6 j3 J
  212. / ^3 h* M- _* L2 N( n* U7 F
  213.         /* bind to specified @port */
    1 d' G7 i4 }- i+ j% _0 K* C5 H
  214.         err = tcp_bind(pcb, IP_ADDR_ANY, port);; ]: m- O" s# b# F7 y
  215.         if (err != ERR_OK)+ r/ U; a' Y# @% e! i# k
  216.         {& d& L0 p5 q4 |- F: o" J
  217.                 debug("Unable to bind to port %d: err = %d\n\r", port, err);
    8 {3 V# j; l5 O" i
  218.                 ret = -2;
    % w8 e1 G. a# u/ u$ c8 e' v# P
  219.                 goto __exit;
    * L1 Z; Q  [4 k
  220.         }' H0 G4 Q7 V, n3 ^  N& _# R
  221. * T/ ^- q& X9 @1 c1 Z# J5 C
  222.         /* listen for connections */4 \1 s0 R' ^- X4 d* T% g
  223.         pcb = tcp_listen(pcb);
    9 s: N+ n4 M) O6 B0 ~5 z8 M# Y
  224.         if (!pcb)
    8 }+ X! b+ M# e2 _3 Y& q2 c
  225.         {* Z; {* l9 L9 l4 }
  226.                 debug("Out of memory while tcp_listen\n\r");
    8 [/ p) J4 @3 o; a% h7 W! Z
  227.                 ret = -3;' [! m# C6 a9 |) Z1 o; p6 |
  228.         }0 b/ w$ C- {  T# @- ^+ z" X

  229. ) E9 @2 f9 i' ~- M* [8 n! ]
  230.         /* specify callback to use for incoming connections */
    ' v0 m: _; }6 V2 X5 u8 f2 w
  231.         tcp_accept(pcb, accept_callback);3 X. z( P& T1 y% C/ E$ l' k

  232. : {0 u$ ~" t! v$ I7 V0 s* w
  233.         /* create success */$ P# @2 Z% e3 I2 i
  234.         debug("TCP echo server started @ port %d\n\r", port);
    8 h6 j3 q/ k1 m
  235.         return ret;
    6 B7 V0 m' u+ d4 r7 D3 u

  236. + ~  s( Z2 z& k5 B5 a0 j8 l/ @7 U
  237. __exit:+ \0 K3 z) f$ |* h6 [+ P
  238.         if (pcb)
    3 k6 o1 K3 u/ I* b) Y
  239.                 memp_free(MEMP_TCP_PCB, pcb);9 T# c8 c$ T5 w/ C6 g) [
  240.         return ret;
    9 M9 Y5 z5 d- t
  241. }, y  A( Y! g5 \  o

  242. 9 R2 a; F/ w/ E6 B
  243. /**
    ! `. d2 P! F. x) I
  244. * TCP发送数据* a2 p3 v. y9 |- A+ k, G
  245. * @param  buf 待发送的数据# z2 S0 P8 H/ C/ N
  246. * @param  len 数据长度
    . M  ?1 k2 M1 ?. C) ]1 K# c
  247. * @return     返回实际发送的字节数
    : N$ ?& t$ B5 ]" l! P* B
  248. */
    & [, n8 D- m9 P' d( w# J6 G3 u
  249. int user_senddata(const void* buf, uint32_t len)* j0 c! F5 y: h- m* d+ ?  ?
  250. {
    . U7 `. |6 ~" n* @; j) P
  251.         return tcp_server_send(tcppcb, buf, len);
    / y* \  w5 Y0 v. `+ Y4 ~
  252. }" }6 K) }4 o! @

  253. 5 k; ?+ c( ~6 x! e
  254. /**
    / T) q3 [# C/ H& O& a; r
  255. * 轮询函数,放置于main函数的while死循环中
    0 c# O0 t) \$ v' {; v
  256. * @return 无; x# J6 M! i' C9 p2 j
  257. */
    " |3 i* j) ^  {5 u; u: u9 Z
  258. int transfer_data(), I7 h% B" H; ~) p! P
  259. {
    1 ^) B8 Y  @; y7 G. [# @0 V6 g, O
  260.         uint32_t nsend = 0;
    7 y; m# ^3 }4 b. P) T7 P
  261.         if (tcppcb != NULL && tcppcb->state == ESTABLISHED) /* 连接有效 */
    4 B0 f% M: q) f/ E9 J
  262.         {
    ) p( I! w# c3 g: W+ y' Q3 @
  263.                 if (TCP_RX_STA & 0x8000)   /* 有数据收到  */
    2 g# ^  I! C# j  z) C% g
  264.                 {* o. ^  P0 p( r- A
  265.                         nsend = user_senddata(TCP_RX_BUF, TCP_RX_STA & 0x7FFF);    /* 将接收到的数据发回去  */
    / P$ E2 `2 B' I, i8 V% B& p6 B
  266.                         TCP_RX_STA = 0;, H$ `8 }! C: ^
  267.                         debug("\r\n send %d bytes success.", nsend);
    7 G& H* t, e. ~3 C* j
  268.                 }1 X6 I! S/ y1 n! v  B2 Q" V
  269.         }
    , O+ v4 S4 O0 S" Y- B& P
  270.         return 0;
    5 l* Y) Y6 [) L) ^: R- n
  271. }! ^& F) ]; S* }  o1 g& \

  272. ' e0 X5 c3 ?, `- \: M
  273. #endif
复制代码

* Z* C$ _; H8 {4 |5 v6 f) @
9 ?4 w" d" A7 R+ _* ^; z. P( Q# G+ Q: _! ~- N) J

) d1 r: M- m2 i  R3 u6 k
赞 收藏 评论0 发布时间:2022-4-11 10:16

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版