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

Marvell 88W8686 WiFi模块创建或连接热点并使用lwip建立http服务器

[复制链接]
zlk1214 发布时间:2017-7-20 16:34
本程序所用的单片机型号为:STM32F103RE1 a; A8 {6 q( U2 Y7 h' s* E) s
PB12端口为外接的WiFi模块电源开关,当PB12输出低电平时接通电源。
$ u" G% R8 ?3 i0 M+ i2 ?6 B注意:WM-G-MR-09模块的芯片组(Chip Set)就是Marvell 88W8686。+ @' S/ ^/ h1 q' h" y
该程序目前只能连接没有设密码的路由器,创建热点时也无法设置密码。7 H6 l  E0 W5 L! I* _
固件内容请参考:http://blog.csdn.net/zlk1214/article/details/74612925
" l6 I& I- ]( ^% C( @* g3 h$ h( k+ R- C( R
注意必须把STM32启动文件*.s中的函数堆栈大小Stack_Size改大,否则函数中无法创建大数组!1 B# ^5 l/ A3 H, C! W. y
  1. Stack_Size      EQU     0x00000c00  
复制代码
【main.c】
( L6 M* |0 x; w% }# C$ ^. V0 O4 ?
  1. #include <stdio.h>  x1 N5 {7 y7 Y4 G
  2. #include <stm32f10x.h>
    8 }- u9 D9 `) L' x( d
  3. #include <string.h>  W# [. z+ O! S! h
  4. #include "lwip/init.h" // lwip_init函数所在的头文件3 Y6 c3 u" X! K- G3 c- ~
  5. #include "lwip/timeouts.h" // sys_check_timeouts函数所在的头文件
    . T: [1 S9 V; N4 K+ b9 e7 @$ [! b
  6. #include "netif/ethernet.h" // ethernet_input函数所在头文件- ^) _1 h9 c3 C* X
  7. #include "WiFi.h"  i: F; y5 f3 a! O

  8. $ N9 b/ R8 i$ U6 ]" V& l
  9. // 这两个函数位于ethernetif.c中, 但没有头文件声明
    9 o% H6 Z5 d/ C; u4 h6 q
  10. err_t ethernetif_init(struct netif *netif);
    , K1 e" \( a  I5 s
  11. void ethernetif_input(struct netif *netif);7 V% \0 R  K* T
  12. 0 s& T* G* |& A$ X  D; E
  13. // httptest.c中的函数/ l2 A+ K9 }2 S( E! e
  14. void init_http(void);
    0 W. `  ^, g& v& q$ `/ B* t
  15. " V$ v% J. \  L( d, _) A' q
  16. // 延时n毫秒' ^% H  H+ A/ H( T
  17. void delay(uint16_t n). |1 p% B/ r6 [5 D; F
  18. {& w- r) I3 e. P1 r$ M
  19.     WiFi_PrepareTimer(n);
    & J/ d/ F8 Z, y
  20.     while ((TIM6->SR & TIM_SR_UIF) == 0); // 等待计时完毕
    9 x% ?% g! X+ {. [4 x+ k
  21.     TIM6->SR &= ~TIM_SR_UIF; // 清除溢出标志  b0 w0 z4 D5 |
  22. }
    + O9 f- r8 J" Y( \4 U% y) g; Z# s/ L# h
  23. $ I8 t" G- K- z( W
  24. void dump_data(uint8_t *data, uint16_t len)
    2 T, N1 Q% u2 x4 a* H2 i8 I
  25. {. U6 f, J" S8 S6 `: v
  26.     while (len--)
    , ?) c8 c! T4 b! H. I1 f
  27.         printf("%02X", *data++);# C& M' V- u- q- l7 w4 M
  28.     printf("\n");
    8 a6 c7 [% e5 S8 ~
  29. }. U/ [$ l. g* o
  30. & G: _2 s( \3 H0 K- Z' O
  31. int fputc(int ch, FILE *fp)- E2 l2 D; `( x( F; c3 e* P5 S9 p
  32. {
    : h. Y# e$ I. a' c  o
  33.     if (fp == stdout)% v7 {9 I. V! X4 m
  34.     {
    6 f* ?# \+ H5 F# u; C
  35.         if (ch == '\n')' |+ X, `) V4 d, B; [2 _. L
  36.         {0 R5 M8 Z  y1 l# |+ _
  37.             while ((USART1->SR & USART_SR_TXE) == 0);, V1 i( G0 O, ^! Z' Y  m: O: m4 ~1 {
  38.             USART1->DR = '\r';3 ~. i% {: ^) {0 q, Y' B/ V
  39.         }- Y0 _" \% b1 N+ ^" B3 l9 N
  40.         while ((USART1->SR & USART_SR_TXE) == 0);, ^+ d! T0 O* F$ e( Q# h; U
  41.         USART1->DR = ch;
    . L7 k$ t1 X3 p/ I
  42.     }3 ~1 ?8 F1 _; U1 I" ~
  43.     return ch;
    # [; t4 B2 z! o: M# ?6 ~' U
  44. }
    + x+ H- q2 J) J( O' U

  45. 4 ~. D9 B3 _4 |# C2 t, t
  46. // RTC时间转化为毫秒数, _$ s$ _% \5 t
  47. uint32_t sys_now(void)- p' T/ q, {: [: ?- p
  48. {
    $ x: {! P8 h& ^+ u
  49.     uint32_t tmp = (RTC->CNTH << 16) | RTC->CNTL; // 秒
    8 x5 h% M0 o5 u
  50.     tmp = tmp * 1000 + (32767 - RTC->DIVL) * 1000 / 32768; // 毫秒& Q! H9 O3 G  H
  51.     return tmp;0 X2 }) g1 ]( W4 L: `( N& C" s
  52. }
    7 L; k8 n- y. a& U0 R

  53. ; F. K2 e9 r3 V
  54. int main(void)
    / n4 V: I( L6 _0 i$ X
  55. {, s# M( s0 Y$ W# J; p, n
  56.     struct ip4_addr ipaddr, netmask, gw;
    ( H( j; {$ I  n: z
  57.     struct netif wifi_88w8686;
    . k* V# L# q9 v( f/ p  _
  58.     uint32_t last_check = 0;
    0 i6 [4 a! _& c2 k# v/ a4 u' _* a
  59.    
    ' P  M$ Y# p! X1 y0 ]
  60.     RCC->AHBENR = RCC_AHBENR_SDIOEN;+ |* I9 U1 N; N2 Y! ~1 r
  61.     RCC->APB1ENR = RCC_APB1ENR_PWREN | RCC_APB1ENR_TIM6EN;
      K" G' Y6 ?, L- \& ~. K; h* h
  62.     RCC->APB2ENR = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | RCC_APB2ENR_USART1EN;$ Y3 ?) D) E. T/ B5 a1 C
  63.    
    8 h- y0 `0 Z, P# ~# l9 j9 F) \
  64.     GPIOA->CRH = 0x000004b0;
      S8 ?" ~/ t, d8 y2 y, h+ A* I
  65.     GPIOB->CRH = 0x00030000; // PB12为外接的WiFi模块电源开关, PB12=0时打开WiFi模块" k1 r8 R3 _# i* N6 L1 O
  66.     GPIOC->CRH = 0x000bbbbb;* n1 H' X4 [9 K7 y8 \+ a7 }# G+ f, ~
  67.     GPIOD->CRL = 0x00000b00;
    * M1 H9 O4 r( a" T' X' o' E: j
  68.    
    * l) P8 v) V. z* ]
  69.     USART1->BRR = 0x271; // 波特率: 115200
    % E6 C2 L3 W7 [! V0 e: P& y% T* c
  70.     USART1->CR1 = USART_CR1_UE | USART_CR1_TE;3 ?  V. w; V9 O+ }
  71.    
    2 j/ B% P# A9 ]' \" W" d( z3 H
  72.     PWR->CR = PWR_CR_DBP; // 允许写入后备寄存器
    : O( D9 r5 ]0 Q3 L1 G
  73.     if ((RCC->CSR & RCC_CSR_LSION) == 0)
    % z7 ]6 d! b7 J  t
  74.     {1 h2 F9 @6 O! Z4 S' t
  75.         RCC->CSR |= RCC_CSR_LSION; // 开内部低速晶振LSI
    ; b4 j4 W& e0 h+ w' [/ I9 m  I
  76.         while ((RCC->CSR & RCC_CSR_LSIRDY) == 0);7 l1 k! s3 i1 J4 M
  77.         //printf("LSI Ready!\n");
    8 T5 Z& n0 G1 A
  78.     }
    , A4 i+ \; A) t) G, B3 m" g
  79.     if ((RCC->BDCR & RCC_BDCR_RTCEN) == 0)
    - F. [+ \4 u8 \
  80.     {
    $ ^! ^# ~! G$ S
  81.         // 若RTC还没有打开, 则初始化RTC& h  M0 G% |* c- O0 A: X
  82.         RCC->BDCR |= RCC_BDCR_RTCEN; // 打开RTC外设, 但暂不开始走时
    5 m7 `# n+ Z9 q: }2 T
  83.         5 K; P$ l& ~! {2 S$ t* h) R
  84.         RTC->CRL |= RTC_CRL_CNF; // 进入RTC配置模式
      H. `2 G% Y1 D) a& A. P! ]: e
  85.         RTC->PRLH = 0;
    + |) x+ d9 i0 ?0 i* ~" C
  86.         RTC->PRLL = 39999; // 定时1s (PRLH和PRLL寄存器只能写不能读)" X: c: m9 D" F. |; d% ]: g0 r
  87.         //RTC->CNTH = 0;
    % \% e' D* F4 \  n0 u
  88.         //RTC->CNTL = 50; // 初始时间' K6 X, d- w: a' L7 G# n- W
  89.         RTC->CRL &= ~RTC_CRL_CNF; // 保存设置
    / h9 Z. y9 A; k/ r  ]% Z
  90.         $ Y+ h% a, v( D$ q2 `
  91.         RCC->BDCR |= RCC_BDCR_RTCSEL_1; // 选LSI作为RTC时钟, 准备走时
    % Z" ~& c* {0 M( }6 F. Q) n
  92.         while ((RTC->CRL & RTC_CRL_RTOFF) == 0); // 等待设置生效
    8 V1 L" w1 f+ |* @
  93.         // RTC从此处开始走时) q5 ^3 k' U) y+ g- ?0 `: k5 O' M6 D- H
  94.     }& ~! u3 r) `8 D4 d
  95.    
    $ w# H+ _. [- k) y/ M
  96.     WiFi_Init();
    $ S# Z  c7 D# F3 H# F" ?+ I3 a
  97.     WiFi_Scan();
    & q3 ]3 u( Z, @% J& p: E
  98.    
    ) m9 Y) l, }% F- U7 Z
  99.     //WiFi_StartADHOC("Marvell_88W8686"); // 创建一个热点' l# [) `% g5 y! X7 X* j$ D6 W% ~; D
  100.     WiFi_Connect("vivo Y29L", NULL); // 连接一个WiFi热点 (目前还不支持设密码)9 z( B* {  y/ g( \
  101.    
    + I9 v$ W; E# O% Q9 k
  102.     lwip_init();+ C$ T, q( s" A) q
  103.     IP4_ADDR(&ipaddr, 192, 168, 43, 10); // IP地址
    ( A0 f- {7 R( a. `" A. ^" n# @
  104.     IP4_ADDR(&netmask, 255, 255, 255, 0); // 子网掩码
    * R, `! j0 B0 H* U
  105.     IP4_ADDR(&gw, 192, 168, 43, 1); // 网关
    # i! W$ l1 o0 C
  106.     - n( ?9 G# i) Y
  107.     netif_add(&wifi_88w8686, &ipaddr, &netmask, &gw, NULL, ethernetif_init, ethernet_input);) m' x4 \# K. d7 t. X
  108.     netif_set_default(&wifi_88w8686); // 设为默认网卡! c( |$ W/ p8 i) J) M/ S
  109.     netif_set_up(&wifi_88w8686);. a, O( s$ E) b! p* I) `
  110.    
    " _) Y) O# j4 j1 n& X
  111.     init_http();2 h! n5 D0 x! R  S4 ]
  112.    
    ' _8 Y( b4 _+ o' t; R5 y
  113.     while (1); @' z* j7 T1 \7 N1 t
  114.     {
    * e, T) |- T: g- K* Q& B
  115.         if (WiFi_PacketPending() || WiFi_PacketArrived())' Q3 K; S! E; m4 G* [! v* E
  116.             ethernetif_input(&wifi_88w8686);
    ) M& X4 |$ |: ~/ I2 b
  117.         1 E9 X: u+ I/ ~6 m; K0 H$ T
  118.         // sys_check_timeouts函数千万不能调用的太频繁, 否则会出错!(例如开机后要等1~2分钟DHCP才能分配到IP地址)
    ; ?8 ?; E1 K$ ]1 p) {
  119.         if (sys_now() - last_check > 200)$ t. k! b' [7 Z7 @' t8 d
  120.         {3 `* G+ C' ]6 y4 I) S$ R* Z
  121.             last_check = sys_now();+ R) D: B+ i$ c3 p0 z
  122.             //printf("Time: %d\n", last_check);: E* q( P$ S1 [5 }7 j& ^; I
  123.             sys_check_timeouts();
    1 I' N, G9 f/ @9 [. h. {8 G
  124.         }
    9 s8 \/ {7 v- e- F7 E
  125.     }
    ! Q% e0 ?' S2 g, u. {! r8 o1 |: y
  126. }
复制代码
【httptest.c】) R! M: {* F+ E3 c1 S* O
  1. #include <string.h>* E2 l+ w$ n6 C& V, \
  2. #include "lwip/tcp.h" // 一般情况下需要包含的头文件! H5 d! J# Y  l) E3 V2 a( R) B
  3. 6 u0 X' f$ G( w/ M
  4. #define STR_AND_SIZE(str) (str), strlen(str)' T: N- b  l' Q

  5. & o! [- B- z. K
  6. err_t http_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)6 v( T1 v6 q" m& @; @9 @
  7. {: t% k. X' S9 O$ R/ S) s, f
  8.         char len[10]; // 存放HTML内容的长度
    ) ]3 A; c# N! x: l2 ~' v! R
  9.         char str[200]; // 存放HTML内容
    6 D; D# `: S. H9 M
  10.         6 Y; I6 E$ a3 X* \  ~9 k
  11.         char name[100];2 @+ z8 U  f' B! ?3 R2 g
  12.         char *pstr;+ ?1 w" f+ F: U4 b7 D
  13.         uint8_t i = 0;
    $ f& S3 w* Q- B( B8 S0 T: U
  14.         if (p != NULL)* a! x  X, p9 B6 u1 }8 A& b
  15.         {0 u/ Q1 C* e. d4 V6 J
  16.                 // 提取页面名称! S- E3 E3 _7 N( T9 d% B1 W
  17.                 pstr = (char *)p->payload;
    % ]& }/ g# {4 t' H( e" `
  18.                 while (*pstr++ != ' ');! N0 F; |2 g* ^
  19.                 while (*pstr != ' ')
    9 N- K3 u5 {7 s
  20.                         name[i++] = *pstr++;
    8 V( M( A+ A% E# a6 O2 Q
  21.                 name[i] = '\0'; // 不要忘了结束name字符串
    # q( E! ]/ P6 E
  22.                 tcp_recved(tpcb, p->tot_len);3 E. M9 I+ w2 ~9 z, n
  23.                 9 V- `8 `+ c, j5 i
  24.                 // 生成HTML内容
    * ^. P; m. _) Z2 D$ p* C
  25.                 sprintf(str, "<meta charset="gb2312"><title>获取网页名称</title><div style="font-family:Arial"><b>请求的网页文件名称是: </b>%s</div>", name);" W3 P- p0 j- p5 j9 w3 x2 L3 [+ v
  26.                
    4 u$ X& G9 t' \
  27.                 sprintf(len, "%d", strlen(str)); // HTML内容的长度& ?; m2 `3 ~5 d: v& ?4 L* Y- a
  28.                 tcp_write(tpcb, STR_AND_SIZE("HTTP/1.1 200 OK\r\nContent-Length: "), TCP_WRITE_FLAG_MORE);* b; K1 F5 K/ j$ c& y8 o% V1 E
  29.                 tcp_write(tpcb, STR_AND_SIZE(len), TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
    8 I1 X7 K7 G, Z, x
  30.                 tcp_write(tpcb, STR_AND_SIZE("\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\n\r\n"), TCP_WRITE_FLAG_MORE);
    * c- f; e* ]' f) X. X8 N2 b
  31.                 tcp_write(tpcb, STR_AND_SIZE(str), TCP_WRITE_FLAG_COPY); // 发送HTML内容
    4 n# g6 K* f2 @2 ?4 R& h9 B( k
  32.                 pbuf_free(p);: \7 \. r: Q( n) o$ \  m$ [, \
  33.         }
    % L$ M5 P  u7 ?8 ]  Z# W
  34.         return ERR_OK;
    $ W, x& q! d; C6 y5 w
  35. }
    9 V3 \- e- J% W+ W6 K* Z

  36. * [& ?( c! q2 E" q, E# y5 S2 ~  @
  37. err_t http_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
    / P) p; r: b+ B: _
  38. {
    7 E$ P; s+ w% i; o
  39.         tcp_recv(newpcb, http_recv);, Z9 |7 b% V$ @0 M- j
  40.         return ERR_OK;1 o# {* u* B% z; I  v8 _# Y* S4 P
  41. }4 x7 g% {4 C- o1 R
  42. & b) V1 r" z9 N5 R. G% K: H$ P! P" q/ a- t
  43. void init_http(void)9 k" @8 H# I( o- n! h7 ^7 v  U
  44. {6 P5 r8 x+ j+ ]6 B3 I
  45.         struct tcp_pcb *tpcb = tcp_new();% ]) r, Y) l: R) {$ ?; m6 \; N
  46.         tcp_bind(tpcb, IP_ADDR_ANY, 80);
    6 j8 _1 v0 X2 @2 Q( r0 n* w: \
  47.         tpcb = tcp_listen(tpcb);
    0 ^, Q! }! \' V& b8 I" _7 k
  48.         tcp_accept(tpcb, http_accept);
    0 _! Y2 g6 K$ n, f+ ?9 D  [. N
  49. }
复制代码
【WiFi.h】
9 y3 n# x6 @* r. n! a1 {- }
  1. #define _BV(n) (1u << (n))+ T. [! b0 O0 R0 |8 i  ~
  2. 7 a0 R" E7 C1 v, H# \" ]
  3. #define CMD52_WRITE _BV(31)( P3 P0 O4 `/ P4 Z& P" G
  4. #define CMD52_READAFTERWRITE _BV(27)
      ^% N7 H7 |/ |. C
  5. ) f, T2 J, ?% p' c9 S
  6. #define CMD53_WRITE _BV(31)+ \. i6 b2 p* s, e
  7. #define CMD53_BLOCKMODE _BV(27)' `: i1 d7 E, j7 d0 d
  8. #define CMD53_INCREMENTING _BV(26): S4 Y3 |1 n3 m

  9. & y# [) _. E2 X: ]
  10. // 16.5 SDIO Card Metaformat
    ' ~& ]* f9 ^* Z: @, V! u6 x
  11. #define CISTPL_NULL 0x00 // Null tuple
    # s/ O+ H: f9 u# o: ^
  12. #define CISTPL_VERS_1 0x15 // Level 1 version/product-information; s+ C/ {# u+ Q6 s# E8 t
  13. #define CISTPL_MANFID 0x20 // Manufacturer Identification String Tuple3 b8 [7 l  i- D! j
  14. #define CISTPL_FUNCID 0x21 // Function Identification Tuple; P6 i+ g- I. E' A3 d7 k
  15. #define CISTPL_FUNCE 0x22 // Function Extensions1 ]% y0 d2 w9 L
  16. #define CISTPL_END 0xff // The End-of-chain Tuple
    / |$ Q5 y1 w# @, |. q; p
  17. ! {- |: J1 X' p- y# v
  18. #define WIFI_DEFAULTTIMEOUT 1500 // WiFi命令回应的超时时间(ms). s) Q% x% Y& S0 z- e4 \3 }

  19. & U% D" I  T+ P7 O; i# I1 e$ y
  20. #define WIFI_SQREADBASEADDR0 0x10
    * L/ R+ J1 S4 w" B
  21. #define WIFI_SQREADBASEADDR1 0x11  [3 |6 U' N5 z6 I' @
  22. #define WIFI_SQREADBASEADDR2 0x121 ^! r9 U* Y' R, ]
  23. #define WIFI_SQREADBASEADDR3 0x13
    % A5 x7 G" N2 |

  24. , i9 t6 [3 ^$ Q; A
  25. #define WIFI_CARDSTATUS 0x20 // Card Status
    . {! d' I' @. P/ R! a
  26. #define WIFI_CARDSTATUS_IOREADY _BV(3) // I/O Ready Indicator
    6 E/ p8 A! Y) Y  `" w
  27. #define WIFI_CARDSTATUS_CISCARDRDY _BV(2) // Card Information Structure Card Ready
    % M/ K8 i$ W  h: e, ^
  28. #define WIFI_CARDSTATUS_UPLDCARDRDY _BV(1) // Upload Card Ready
    " Y2 }/ U# v/ z9 O1 I" s
  29. #define WIFI_CARDSTATUS_DNLDCARDRDY _BV(0) // Download Card Ready/ g6 k) t, d3 r
  30. / U" G: o$ a. v! s' G$ V+ Q
  31. #define WIFI_CAPABILITY_BSS _BV(0)) W7 g( q6 j8 T+ _3 L$ C# G. [& Y: K& G
  32. #define WIFI_CAPABILITY_IBSS _BV(1)- F' {# X) J8 k
  33. #define WIFI_CAPABILITY_CF_POLLABLE _BV(2)# A2 S3 d( p8 w" J0 _
  34. #define WIFI_CAPABILITY_CF_POLL_REQUEST _BV(3)7 s$ o5 a% `- Q- y" c% X- e
  35. #define WIFI_CAPABILITY_PRIVACY _BV(4); F2 n* F: P; I+ Y' g5 h/ o# O4 ~
  36. #define WIFI_CAPABILITY_SHORT_PREAMBLE _BV(5)
    - P/ l2 t- h1 J5 x% z6 Q: J
  37. #define WIFI_CAPABILITY_PBCC _BV(6)' @% _, g: [" Z* x2 Z
  38. #define WIFI_CAPABILITY_CHANNEL_AGILITY _BV(7)
    4 b; R7 z1 G$ i
  39. #define WIFI_CAPABILITY_SPECTRUM_MGMT _BV(8)
    0 t# g( n/ d3 M, [* ~6 B9 u7 A
  40. #define WIFI_CAPABILITY_QOS _BV(9)
    # O# O8 H; U) R4 g; E$ I% A
  41. #define WIFI_CAPABILITY_SHORT_SLOT _BV(10)  S! |5 h+ I8 ?
  42. #define WIFI_CAPABILITY_DSSS_OFDM _BV(13)
    " Y4 i/ R7 Q/ }% b: x( {
  43. + Y  j" A9 `: F5 d( }! T' H0 D# {( z
  44. #define WIFI_SDIOFRAME_DATA 0x00
    5 [! R/ N7 p  k; h* R5 F" ~- B
  45. #define WIFI_SDIOFRAME_COMMAND 0x01, ?9 |7 C1 b& I# m
  46. #define WIFI_SDIOFRAME_EVENT 0x03
    * t! d( \& Z9 K- X' O1 r
  47. : b6 K! D! r9 t% F- a! X" @' y
  48. /* Command List */
    ( U# t/ t6 d$ R5 c6 O
  49. #define CMD_802_11_SCAN 0x0006 // Starts the scan process' N  J$ t3 w& Z5 Z- {( b
  50. #define CMD_802_11_ASSOCIATE 0x0012 // Initiate an association with the AP' H4 V6 O( g1 X- K
  51. #define CMD_MAC_CONTROL 0x0028 // Controls hardware MAC
    ( K- ~8 _) e7 }' o" K3 j" F, o- u. @2 s
  52. #define CMD_802_11_AD_HOC_START 0x002b // Starts an Ad-Hoc network
    6 D1 H# t% N  b- u
  53. #define CMD_802_11_MAC_ADDR 0x004d // WLAN MAC address
    / y) P4 s' W. s# f1 t+ ]
  54. #define CMD_802_11_KEY_MATERIAL 0x005e // Gets/sets key material used to do Tx encryption or Rx decryption( f8 P& K' d: n
  55. #define CMD_802_11_BG_SCAN_CONFIG 0x006b // Gets/sets background scan configuration$ F( ]# R1 R- V1 n9 H% Y7 u8 E8 t8 z
  56. #define CMD_802_11_BG_SCAN_QUERY 0x006c // Gets background scan results( g% n. o" a# \, a& \4 \: i
  57. . v2 j. \0 h" W# O- [' V2 @+ s2 l
  58. /* Command Result Codes */
    * k/ }* \- H1 ~- Z+ c
  59. #define CMD_STATUS_SUCCESS 0x0000 // No error- b( M* b' e: ]! h
  60. #define CMD_STATUS_ERROR 0x0001 // Command failed) V5 }: |4 x$ y
  61. #define CMD_STATUS_UNSUPPORTED 0x0002 // Command is not supported8 o7 W& W/ `4 Y" Y5 ]1 f/ M$ u

  62. 6 O' d* p6 D: K
  63. #define WIFI_ACT_GET 0
    0 Q$ r' G) V' C' R
  64. #define WIFI_ACT_SET 1
    : r! {( I6 A- c
  65. 8 s, t2 J  d4 e+ G
  66. /* Authentication Type to be used to authenticate with AP */
    3 \& X- d: U8 S0 l
  67. #define AUTH_MODE_OPEN 0x00
    2 ?8 _# K/ u" U/ x# J/ Z
  68. #define AUTH_MODE_SHARED 0x01
    . u1 c/ R) T0 W5 X/ v5 k
  69. #define AUTH_MODE_NETWORK_EAP 0x80  \9 W: i. e- B2 z0 s
  70.   B, \/ M' Q2 Y- f7 g) [' F  d. j* a  D
  71. /* WiFi_Associate return value */- E, ]* W! b5 j1 \0 ^
  72. #define WIFI_ASSOCIATION_NOTFOUND 0xfffe7 p' {' y6 U6 q8 ?* b
  73. #define WIFI_ASSOCIATION_ERROR 0xffff
    " O1 @, K4 E) r# ?6 V
  74. #define WIFI_ASSOCIATION_SUCCESS 0x0000 // 连接成功
    5 l4 k& D5 x3 v" v1 l/ Q
  75. #define WIFI_ASSOCIATION_INTERNALERROR 0x0101- M, H0 r2 v- T$ X1 o' f' D
  76. #define WIFI_ASSOCIATION_AUTHUNHANDLED(ret) (((ret) & 0xff00) == 0x200) // 未处理的认证帧
    # }& r1 f9 {) W* w
  77. #define WIFI_ASSOCIATION_UNSUPPORTEDAUTHALG 0x02131 @7 [$ W& p) ^4 s. K( d
  78. #define WIFI_ASSOCIATION_INVALIDSEQUENCENUMBER 0x0214
    7 l9 \1 n7 m9 d; R8 L1 Q
  79. #define WIFI_ASSOCIATION_AUTHREFUSED(ret) (((ret) & 0xff00) == 0x300) // 认证失败
    : I: b  @8 U6 f
  80. #define WIFI_ASSOCIATION_TIMEOUT(ret) (((ret) & 0xff00) == 0x400) // 超时9 e. J9 z2 Q1 Y; T$ z5 T: N
  81. #define WIFI_ASSOCIATION_ASSOCTIMEOUT 0x0401 // 连接超时
    + {6 e  D1 x& z8 s: S* _9 {
  82. #define WIFI_ASSOCIATION_AUTHTIMEOUT 0x402 // 认证超时
    ! E$ K3 P6 L( W+ E7 g0 h
  83. #define WIFI_ASSOCIATION_NETWORKJOINTIMEOUT 0x403 // 加入网络时超时( ?9 b* b- n2 q4 }6 V& g

  84. 6 V! [4 ~1 L0 I6 Z
  85. #define WIFI_KEYTYPE_WEP 0# K" l! d& c% N
  86. #define WIFI_KEYTYPE_TKIP 1
      \. H2 d/ t) I0 B7 Z
  87. #define WIFI_KEYTYPE_AES 2. Q2 @6 k/ T( H* y" B
  88.   k) e' d" T. W. W0 R
  89. #define WIFI_KEYINFO_KEYENABLED _BV(2). y- g( m- o* H* Z# d  J
  90. #define WIFI_KEYINFO_UNICASTKEY _BV(1)- l2 {; F( E; S  ^+ {
  91. #define WIFI_KEYINFO_MULTICASTKEY _BV(0)! Q6 T8 q4 Z" o5 g8 p5 i4 j( b& C6 o1 n" W
  92. ' U* [  A/ z% o, \
  93. #define WIFI_MACCTRL_RX _BV(0)6 H4 w9 K! `$ b. \5 [6 K
  94. #define WIFI_MACCTRL_TX _BV(1) // 此位必须要置1才能发送数据!!!
    6 j5 A1 W) Y1 m. j
  95. #define WIFI_MACCTRL_LOOPBACK _BV(2)$ e. ^# F/ Y: f* L9 W# i- q
  96. #define WIFI_MACCTRL_WEP _BV(3): U# i- e) L# ?2 p: X3 J2 z& B  m; p
  97. #define WIFI_MACCTRL_ETHERNET2 _BV(4)
    4 J7 o0 o: E: N1 \6 ]% {% w( x
  98. #define WIFI_MACCTRL_PROMISCUOUS _BV(7)
    $ s" }; F+ W$ W$ h
  99. #define WIFI_MACCTRL_ALLMULTICAST _BV(8)3 X9 L* n! J& X9 H% K. M) v2 r3 t+ d1 ?9 F4 t
  100. #define WIFI_MACCTRL_ENFORCEPROTECTION _BV(10) // strict protection
    ( J) x0 p: ~/ d, N* l7 N
  101. #define WIFI_MACCTRL_ADHOCGPROTECTIONMODE _BV(13) // 802.11g protection mode
    % I/ J0 l1 q5 x$ g

  102. 8 e, |+ [0 S! J8 E( r: j
  103. /* BSS type */
    ' K& l# i( h) [: f/ J( k3 j
  104. #define BSS_INFRASTRUCTURE 0x01; R# l; P* R  M6 L9 I. x. O
  105. #define BSS_INDEPENDENT 0x02
    $ M! q- {" X* h. O3 p+ p
  106. #define BSS_ANY 0x034 T: g& B1 F, S7 H  g/ E
  107. , S/ |9 _- l% @1 `7 w* F0 T! z1 @& G& X
  108. /* Table 45: IEEE 802.11 Standard IE Translated to Marvell IE */! k; U1 u$ ]! Z2 m* E' x- }
  109. /* PDF中的表45有一些拼写错误, MRVIIE应该改为MRVLIE */: @. q* k& |6 a
  110. #define MRVLIETYPES_SSIDPARAMSET 0x0000( f- ~$ w# R9 C4 L$ N1 k3 B) J
  111. #define MRVLIETYPES_RATESPARAMSET 0x0001
    & b" a& Y; g  `+ O
  112. #define MRVLIETYPES_DSPARAMSET 0x0003
    ! {& {/ l0 y& W& G3 B" i$ t
  113. #define MRVLIETYPES_CFPARAMSET 0x0004
    3 X$ l. `: P% [' |
  114. #define MRVLIETYPES_IBSSPARAMSET 0x00066 `( ]0 J8 H0 P# f( Z
  115. #define MRVLIETYPES_RSNPARAMSET 0x00301 ^; v1 i: ~& p- K8 `- q, w( G0 l
  116. #define MRVLIETYPES_VENDORPARAMSET 0x00dd1 Q8 v. j  D2 \+ q" G' F9 l$ u

  117. $ Q) Q7 q& j; E0 i. F
  118. #define MRVLIETYPES_KEYPARAMSET 0x0100
    5 A( s4 n+ |/ b" E
  119. #define MRVLIETYPES_CHANLISTPARAMSET 0x0101
    6 Z6 g1 r: [' H' @
  120. #define MRVLIETYPES_TSFTIMESTAMP 0x0113
    : U" g) e' y: |; \( R- Q# c
  121. #define MRVLIETYPES_AUTHTYPE 0x011f2 W2 V# G/ Z! v) V' `8 y* X  X4 Z

  122. + x4 Y" `/ x: i2 k2 V4 l7 M% g) w5 R
  123. #define MRVLIE_PAYLOADLEN(s) (sizeof(s) - sizeof((s).header)) // 已知结构体大小sizeof(s), 求数据域的大小
    # U. q& A9 _- L3 U
  124. #define MRVLIE_STRUCTLEN(s) (sizeof((s).header) + (s).header.length) // 已知数据域大小, 求整个结构体的大小
    8 i8 A3 t6 ^" E) V1 e' z

  125. + {- W9 r0 @: F
  126. typedef __packed struct* L+ L: U! d+ Q; j2 E; _8 W
  127. {
    ' n7 h. |0 V' Z* z* \1 Z
  128.         uint8_t type;
    8 T- b" X/ S8 ]- O7 K% P
  129.         uint8_t length;
    . E7 m( Y: u" B' L
  130.         uint8_t data[1];0 j6 x9 l* C* c1 f* h0 P
  131. } IEEEType;
    ) J" j# c" v! L& h6 \% [6 b
  132. 9 B$ {: k3 }& r; k# F
  133. typedef __packed struct: _/ b0 d; T3 U- [7 l  V
  134. {
    " k* d. W, a) X2 ~8 U
  135.         uint16_t ie_length; // Total information element length
    " D' y8 @, G+ e9 f8 l" Z: l
  136.         uint8_t bssid[6]; // BSSID
    , i& h) a) F1 n" N" o
  137.         uint8_t rssi; // RSSI value as received from peer6 |6 _$ b1 C: X
  138.         
    ) K1 U/ S$ q1 o$ n" o
  139.         /* Probe Response/Beacon Payload */
    ' b( n* Z6 ]( W% S4 V
  140.         uint64_t pkt_time_stamp; // Timestamp: l" F* g7 ^7 e2 L
  141.         uint16_t bcn_interval; // Beacon interval: o2 g- {4 p3 L" {9 D9 B# J. s
  142.         uint16_t cap_info; // Capabilities information1 Z4 t2 P. v) V; O5 ]% K
  143.         IEEEType ie_parameters; // 存放的是一些IEEE类型的数据
    & R4 t, o8 `' A
  144. } WiFi_BssDescSet;! ~5 |' f; K; A2 b7 w

  145. 9 i6 o" Y7 Q4 m
  146. typedef __packed struct  w$ R( G2 N6 z) |( {
  147. {  Y3 w! w- D1 L* h( @+ U
  148.         uint8_t oui[3];& Q; N" q# F) Z) R' X! W
  149.         uint8_t oui_type;
    . p9 O7 K# M: y, I8 `6 ~
  150.         uint8_t oui_subtype;/ D8 _- R0 `% v4 ?
  151.         uint8_t version;! t/ m7 A8 m; U7 n" N0 @
  152. } WiFi_VendorHeader;
    " h% j% m  c/ `7 f+ N% I/ B  i+ f9 ^( t

  153. 5 i2 Y  V% z' L; D5 E4 t
  154. typedef __packed struct
    # U. v, e( U  i, a, ]
  155. {0 W+ o; q4 e. D7 @, ^  I) i
  156.         uint16_t type;4 y# B) ~# q4 h. W8 A
  157.         uint16_t length;
    " m/ h4 Z7 A/ H6 d
  158. } MrvlIEHeader;
    , _8 _- |$ L, g9 W

  159. $ _! w" n6 V+ ?+ D1 Y; Y
  160. typedef __packed struct
    * V) f$ [+ r$ `4 L2 |
  161. {
    ' d2 j7 D/ f3 }# A( S& r& n
  162.         MrvlIEHeader header;9 K7 t. n0 L) E% X3 N8 X+ p
  163.         uint16_t auth_type;" t: c0 Q" T$ X0 p! J
  164. } MrvlIETypes_AuthType_t;
    & z, d, W3 U0 B

  165. ! n9 h: g0 e: t" R
  166. typedef uint16_t MrvlIETypes_CapInfo_t; // Section 7.3.1.4: IEEE 802.11-1999 Spec+ e. ]! @  _7 m$ Z

  167. / a+ }4 H& [. r2 Q/ ?
  168. typedef __packed struct
    * }& Y3 Z! X5 ?, B
  169. {4 O* ^9 i. W( U) J3 {1 L! W2 `
  170.         MrvlIEHeader header;
    9 n" P3 E8 X8 E
  171.         uint8_t count;; j3 ^) w0 V$ N
  172.         uint8_t period;
    . |; a/ K9 ]) n# j
  173.         uint16_t max_duration;
    4 g/ ?, J4 O. e+ j+ p" B
  174.         uint16_t duration_remaining;- G% Q" b+ g( Y; Y$ B4 G5 J+ |
  175. } MrvlIETypes_CfParamSet_t;
    2 A# [$ r6 C/ i! ~  u

  176. ) s+ W9 k6 v1 [& ~
  177. /*typedef __packed struct5 W" N5 c" g- p; l) v6 F. ~! G
  178. {; P4 h( e/ ^4 r. f2 w
  179.         MrvlIEHeader header;8 x, u# k8 s8 v- c: g  J  Y
  180.         __packed struct
    0 D3 y9 D' e8 g& |2 Y
  181.         {
    8 o2 b1 D$ O, [
  182.                 uint8_t band_config_type;
    8 T( r4 A& B7 y6 o9 R: n7 E
  183.                 uint8_t chan_number;
    4 Z5 R3 t, K# E6 P
  184.         } channels[1];
    * l/ Y6 C. f' P4 q$ Z
  185. } MrvlIETypes_ChanBandList_t;*/% |( n/ _: F. L# b
  186. . F( Y( |9 _0 u/ S
  187. typedef __packed struct) Z3 H' t; y; T5 v
  188. {
    4 N# H* s. e' u" g/ y! K
  189.         MrvlIEHeader header;5 `3 E, S7 g, i- @
  190.         __packed struct' f% P' K, ?% {: d7 K
  191.         {
    8 m5 L$ g* t6 X& S6 M- F! X
  192.                 uint8_t band_config_type;
    ! |9 u3 ^, A4 `3 _+ J6 n/ G
  193.                 uint8_t chan_number;3 N5 g: ^; b5 v$ A
  194.                 uint8_t scan_type;; q  G7 i) T/ i
  195.                 uint16_t min_scan_time;
    0 D  q) y" ?8 E- J" w1 D' n9 D
  196.                 uint16_t max_scan_time;; l6 M( a: c( D5 R' H: s
  197.         } channels[1];& M- w+ N! {; k
  198. } MrvlIETypes_ChanListParamSet_t;0 o1 H0 H; x. x1 G
  199. , O7 n4 e* C  K7 }# q+ }
  200. typedef __packed struct. D4 f# k6 O. D0 D, Z$ s+ X% D
  201. {
    ' x. ?4 A, r  ?# y; W  `
  202.         MrvlIEHeader header;# [2 d. V$ M0 e: f$ r
  203.         uint8_t channel;: B6 `5 x3 B/ t3 {" U8 k
  204. } MrvlIETypes_DsParamSet_t;- E; z( L( c& S7 c) _

  205. : p7 N) _% S8 l% `! B, g- Y
  206. typedef MrvlIETypes_DsParamSet_t MrvlIETypes_PhyParamDSSet_t;+ v, e( k9 ~0 ^8 h2 [% Y

  207. , m; T# F2 D* [& z* i" R& X
  208. typedef __packed struct& s6 \" {) a7 r) f
  209. {
    " @2 [4 F* w4 F5 \
  210.         MrvlIEHeader header;
    ; H& t7 t# s: k* L& k
  211.         uint16_t atim_window;
    ' v7 ?- j" O% ~
  212. } MrvlIETypes_IbssParamSet_t;; F2 b# B0 @6 v9 f5 A

  213. ! d% N$ R3 K: b  T  y
  214. typedef __packed struct
    , i' C2 v! Y" ]8 a4 M3 {; _
  215. {# E( d0 d- P" d
  216.         MrvlIEHeader header;% ?4 B2 `; ^: V" l7 b1 a
  217.         uint16_t key_type_id;  {9 Z  p1 x; j5 i4 A
  218.         uint16_t key_info;
    2 P: q, k3 M/ u- J1 c
  219.         uint16_t key_len;. |9 T: F1 r6 M- l7 u$ S. K! ]( B
  220.         uint8_t key[32];% j1 f3 K- K, A+ l8 s( z  h% y1 B
  221. } MrvlIETypes_KeyParamSet_t;' i( l5 ^3 e' I9 y* t  \2 `
  222. $ V! s( S) ?5 [8 y+ I1 n
  223. typedef __packed struct
    ! f3 M: ?, Q9 @* B4 W& w0 N; p1 K
  224. {
    - j* j) X/ o5 {  O6 ^
  225.         MrvlIEHeader header;$ B. U5 g, P0 [
  226.         uint8_t rates[14];
    / O& R3 ~* @) [
  227. } MrvlIETypes_RatesParamSet_t;
    & t) i" Y1 G/ f+ x# D# g

  228. 2 H- Q% Y0 A" Q) p9 @- c
  229. typedef __packed struct! j  S! w; `5 t2 r+ _
  230. {
    ; o- {  A$ E4 J# j
  231.         MrvlIEHeader header;. C8 f8 \& X! I! x& ^4 M9 z
  232.         uint8_t rsn[64];
    . p7 A' j) |# ~+ v+ E
  233. } MrvlIETypes_RsnParamSet_t;3 Z5 D. F' m( N4 G
  234. ' A* {& E/ m3 }/ b' F0 H) j
  235. typedef __packed struct
    7 ^8 u3 z. k/ j' I
  236. {
    9 B* d* \7 M' d6 `) L
  237.         MrvlIEHeader header;' S0 _, Y6 b. O/ c$ m, q" [
  238.         uint8_t ssid[32];* {3 a0 _1 t8 d/ ^, C/ q
  239. } MrvlIETypes_SSIDParamSet_t;
      `3 y3 D+ v1 `  Y+ J: }, ~3 y
  240. % E1 y8 I0 Z' E! ]6 ^
  241. typedef __packed struct: q- A# p; w& e, L0 N% _  J7 y
  242. {+ u& n" X# b% p1 a. A
  243.         MrvlIEHeader header;
      x) L' Y0 l% `: m- v9 p; k
  244.         uint64_t tsf_table[1];
    6 Y+ w3 |+ i& a7 u0 k
  245. } MrvlIETypes_TsfTimestamp_t;
    # L2 ~7 w4 ~  g) X

  246. . B, w) O7 r% e" T6 D$ t% U
  247. // 整个结构体的最大大小为256字节
    3 q3 S: ^3 W" ]; R) V
  248. typedef __packed struct
    & E3 F  z; b- J
  249. {% c9 S9 x8 ]- c+ V
  250.         MrvlIEHeader header;
    : Z9 K, B5 N' I* K
  251.         uint8_t vendor[64]; // 通常情况下64字节已足够
    - K( l3 }  ?2 p( ?0 S, E
  252. } MrvlIETypes_VendorParamSet_t;" n' Y3 @+ C" B& Z; J8 L
  253. 8 v/ ]$ J7 v& a9 h- b! r; F
  254. typedef __packed struct
    & V( O, S0 C% z* N9 o
  255. {# C  c& @6 `1 ~, C% r0 ]2 H
  256.         uint16_t length;0 T- w; \; H, x" J/ `, V
  257.         uint16_t type;
    2 f0 h2 H6 @. k4 M8 E
  258. } WiFi_SDIOFrameHeader;( r3 |, _% a9 k$ a* U" J2 _
  259. ! W( Y/ I- Y4 U1 h0 m
  260. typedef __packed struct/ d$ m" M# b0 w$ Q
  261. {) S4 x, ?8 ^& [. t0 ]5 O( l
  262.         WiFi_SDIOFrameHeader frame_header;
    9 |+ B  m8 |8 H
  263.         uint16_t cmd_code;
    $ k- s; W. N& l8 ^- p. K
  264.         uint16_t size;
    # o. o; I, z9 L0 A, u/ P
  265.         uint16_t seq_num;
    " r1 P6 D4 @% V7 L
  266.         uint16_t result;
    , ?, y8 w5 z# c# ^4 O0 C& f
  267. } WiFi_CommandHeader;
    & y# E& p8 I1 [$ d+ @

  268. ! y9 O# F  A' T! f5 L0 l/ Z0 b9 u
  269. /* Table 2: Fields in Receive Packet Descriptor */) d% Q/ v2 Y! s, V3 V- }
  270. typedef __packed struct
    ; \. E, o/ F% U& b5 f
  271. {
    5 r! ]& p  d. e
  272.         WiFi_SDIOFrameHeader header;+ g8 J5 ^. ]- T( R: a9 i& M4 O
  273.         uint16_t reserved1;' }! s1 b* R; a0 |. K* q3 e
  274.         uint8_t snr; // Signal to noise ratio for this packet (dB)
    # n7 p& c2 Z. `$ I
  275.         uint8_t reserved2;" H- V+ R! U( E- [4 D
  276.         uint16_t rx_packet_length; // Number of bytes in the payload) i. U4 v/ q- V, l. n
  277.         uint8_t nf; // Noise floor for this packet (dBm). Noise floor is always negative. The absolute value is passed.
    . H' z2 J2 j$ s4 P4 t6 r; r- U
  278.         uint8_t rx_rate; // Rate at which this packet is received) a. t! Y  r+ e4 q
  279.         uint32_t rx_packet_offset; // Offset from the start of the packet to the beginning of the payload data packet
    4 b; x. E5 V2 R+ R3 Y
  280.         uint32_t reserved3;+ i) j1 c; u( I' b1 W: W
  281.         uint8_t priority; // Specifies the user priority of received packet
    % |6 s/ }; G% z1 W  H2 s7 @
  282.         uint8_t reserved4[3];
    ; q9 P9 {1 B5 j+ ~( p2 }2 ^4 t
  283.         uint8_t payload[1]; // 数据链路层上的帧  w. k+ Y4 `4 p4 ?3 H$ o
  284. } WiFi_DataRx;
    , Q- ^" }& a. ]6 h) T
  285. 7 s. A6 J) N1 Y0 g0 b$ M' |9 p& G+ I
  286. /* Table 3: Fields in Transmit Packet Descriptor */
    6 w6 O1 J( n; ^* r! E3 `$ T5 g
  287. typedef __packed struct
    8 z' [* P. f8 l9 R! m1 t2 c4 x% n
  288. {. e( h% |7 p7 j" t4 ~7 {4 N
  289.         WiFi_SDIOFrameHeader header;8 ~0 {! N3 e) ~/ X& L' w
  290.         uint32_t reserved1;5 D# ?* b# b1 U/ [; a3 y( s
  291.         uint32_t tx_control; // See 3.2.1 Per-Packet Settings- B8 h2 G8 `" R, h: d# E5 D0 U) G9 S  E$ c+ A
  292.         uint32_t tx_packet_offset; // Offset of the beginning of the payload data packet (802.3 or 802.11 frames) from the beginning of the packet (bytes)7 d8 a4 M9 |, \8 r3 O- T) V! {
  293.         uint16_t tx_packet_length; // Number of bytes in the payload data frame
    : |+ S6 t; F+ S* `- F/ _1 z
  294.         uint16_t tx_dest_addr_high; // Destination MAC address bytes 4 to 5( S% r+ i2 b% b  n: C7 I6 r7 l  |  V
  295.         uint32_t tx_dest_addr_low; // Destination MAC address bytes 0 to 3- p! O4 R9 `% }! p* N
  296.         uint8_t priority; // Specifies the user priority of transmit packet# b. _2 c6 b. F. X6 U( O
  297.         uint8_t flags;
    & x  q- Y3 _# x- g! a" H2 E0 O
  298.         uint8_t pkt_delay_2ms; // Amount of time the packet has been queued in the driver layer for WMM implementations
    " W6 O: h$ ~4 E; N: t
  299.         uint8_t reserved2;
    8 }/ l8 i2 L5 D% N. {
  300.         uint8_t payload[1]; // 数据链路层上的帧# I- S# H/ i9 K: F
  301. } WiFi_DataTx;
    " J+ l* i9 c1 Y! s1 \6 K
  302. 3 j8 ^- d0 z* P, h. U: I
  303. typedef __packed struct3 f/ L( Y$ o' R% F6 ~7 [) q. N
  304. {
    8 \# `+ G, B$ L% r; F. d
  305.         WiFi_CommandHeader header;. x* N6 b% t: V( H- ^' _% q0 s
  306.         uint16_t action;
    . F) K1 a1 {( M& Y0 i' ~
  307. } WiFi_Cmd_KeyMaterial;
    ) m7 ]6 T1 C% D3 m4 g5 c
  308. " K; y* {( b" V4 H8 G
  309. typedef __packed struct
    7 ?* a0 H% C0 n, x
  310. {( d0 E: V& S3 j; U; {) d7 l
  311.         WiFi_CommandHeader header;8 a2 v2 a0 m  q; n& `/ @( N. h4 o1 y
  312.         uint16_t action;
    ) S* \! N9 K3 L# m/ {& d
  313.         uint8_t mac_addr[6];2 s/ [; k% ~# d$ ]) f
  314. } WiFi_Cmd_MACAddr;! q5 |- v$ V3 g9 Y; S

  315. , O/ x" W4 P7 B$ W$ \
  316. typedef __packed struct
    . m% X4 M5 k' E/ z) n9 }
  317. {
    % m9 R, A; g( u% ?" M6 B/ H" r
  318.         WiFi_CommandHeader header;
    5 M9 o, G. T# f$ Q+ W8 g
  319.         uint16_t action;. r) l; j! _) h2 ^
  320.         uint16_t reserved;; I8 a1 U7 g: u+ P3 ?
  321. } WiFi_Cmd_MACCtrl;9 Q; a! ?$ A( R% D

  322. " u9 s7 l7 L- v5 Y
  323. typedef __packed struct
    / R% m  e; L' v4 E7 |* N
  324. {: q0 |* o% V1 k1 T$ R$ {
  325.         WiFi_CommandHeader header;7 s7 f+ X5 P4 o4 s8 C& i9 ]0 z
  326.         uint8_t ssid[32];! M7 Z) `+ |, i* V$ G' T6 t; K
  327.         uint8_t bss_type;
    . L4 V$ V5 }8 ^& ^3 a  V/ ?* e
  328.         uint16_t bcn_period;+ b  Y! j. A: p" x8 c
  329.         uint8_t reserved1;- I3 E& l! d# z5 _5 I. [  b$ i
  330.         MrvlIETypes_IbssParamSet_t ibss_param_set; // ATIM window length in TU# o& p6 A& N$ y8 v4 w, m- ~
  331.         uint32_t reserved2;
    & u+ y6 ^1 f3 Y
  332.         MrvlIETypes_DsParamSet_t ds_param_set; // The channel for ad-hoc network
    ! i: u+ W6 @1 n' Z- D4 s- ~
  333.         uint16_t reserved3[3];
    + a8 P# n2 ], N% s
  334.         MrvlIETypes_CapInfo_t cap_info; // Capability information" g2 v2 Y' v3 ?+ _
  335.         uint8_t data_rate[14];1 B( Y" k0 l+ K7 r$ f. {4 o
  336. } WiFi_CmdRequest_ADHOCStart;
    4 _) M; R7 H# n
  337. 2 y# X% D  O; ^* w
  338. typedef __packed struct7 ?3 ]* s$ E; w9 |4 v+ p
  339. {
    5 X5 E" {4 y. }/ @" Z" P
  340.         WiFi_CommandHeader header;  v% M- |. [# |7 |
  341.         uint8_t peer_sta_addr[6]; // Peer MAC address6 m0 Q. {+ y; _% W9 V& d
  342.         MrvlIETypes_CapInfo_t cap_info; // Capability information+ g; d9 k/ z0 L* r, X& a" N) U
  343.         uint16_t listen_interval; // Listen interval* h9 ^0 o. X- w6 ]
  344.         uint16_t bcn_period; // Beacon period
    6 P7 G: M, p+ b$ T2 ]
  345.         uint8_t dtim_period; // DTIM period; O7 S5 Q: e' v9 W4 A, G3 t
  346. } WiFi_CmdRequest_Associate;
    ; M( K+ Y. R& s0 U7 [  p3 h- Y3 B

  347. ! i/ N# H$ |1 F; A
  348. typedef __packed struct
    # A0 F9 x! K( E3 @
  349. {
    9 M0 q! g1 W" y4 E9 x& ]6 K
  350.         WiFi_CommandHeader header;" ]7 `  Y3 [6 p% i6 |( K
  351.         uint8_t bss_type;1 w) @3 e# z0 A- M2 o
  352.         uint8_t bss_id[6];
    ; o5 v/ W% x8 [! ~! X+ \; w
  353. } WiFi_CmdRequest_Scan;
    , A9 \' `8 U& x6 ?
  354. , z4 X: s/ [: Z# P: Z' e: L
  355. typedef __packed struct
    6 S% w! B- o1 j% P
  356. {
    / f* ?5 v6 Q9 Y2 F0 B/ r# b
  357.         WiFi_CommandHeader header;
    9 S/ K% ^- c5 K; c7 ~& Y* }
  358.         uint16_t capability;
    9 p% d% z0 X$ J8 T
  359.         uint16_t status_code;; |  y  v, o) k
  360.         uint16_t association_id;
    7 Z! i7 Y( ]# Q1 w) V. D
  361.         IEEEType ie_buffer;
    ! V: Y) j0 i4 {0 [8 M! P
  362. } WiFi_CmdResponse_Associate;
    ; p0 H2 S8 q: @/ Q' z- p
  363. " c+ e) B2 Z( Z; w; M
  364. typedef __packed struct
    . Y" i5 b4 j: Z9 }
  365. {
    ) F/ L5 \' N: b
  366.         WiFi_CommandHeader header;8 `  e+ n) o5 x, i  a+ |
  367.         uint16_t buf_size;+ x- Y+ A8 @5 h2 ^" h2 `# M
  368.         uint8_t num_of_set;
    & A, V/ H. b) N
  369. } WiFi_CmdResponse_Scan;
    : r1 X7 O- ~, y5 s. }( P

  370. + y" ?* M. }5 S& g- m
  371. typedef __packed struct
    9 m: Q: r8 e8 |
  372. {2 ]; ?, Z0 b( J
  373.         MrvlIETypes_SSIDParamSet_t ssid;
    7 f& q0 }5 T9 A" @- @5 L
  374.         uint8_t mac_addr[6];( E  V# h: [- E- J: R% a
  375.         MrvlIETypes_CapInfo_t cap_info;
    5 K0 Y, h  M" x# o5 [* R! ?( _
  376.         uint16_t bcn_period;' W  Q6 h1 N$ G4 s
  377.         uint8_t channel;
    " Q6 Q; `3 r1 r+ ?% R; {
  378.         MrvlIETypes_RatesParamSet_t rates;
    : {9 z; u5 r8 p5 V
  379.         MrvlIETypes_RsnParamSet_t rsn;
    * E6 Z+ i( m% M' ~: J) Y; b2 `1 F
  380.         MrvlIETypes_VendorParamSet_t wpa;
    ( @  x- T0 \8 v, H+ b( V/ S
  381.         MrvlIETypes_VendorParamSet_t wwm;% Q+ }' `% ]" p4 a- W$ y
  382.         MrvlIETypes_VendorParamSet_t wps;
    $ d9 h! ~- L& K! J$ v+ o
  383. } WiFi_SSIDInfo;5 [# l/ H! ]/ T& }- G2 I

  384. 4 q5 j. l" U7 V8 Z) T1 B4 `
  385. #define WiFi_DropPacket() WiFi_ReceivePacket(0, 0)
    * H+ z% Q' K6 ]1 `2 b
  386. #define WiFi_GetBlockSize() _BV((SDIO->DCTRL & SDIO_DCTRL_DBLOCKSIZE) >> 4)- d0 }( W+ k! Q% O6 i$ ~( m2 A
  387. #define WiFi_GetMACAddr(addr) WiFi_MACAddr((addr), WIFI_ACT_GET): \- ]8 h6 q0 w
  388. #define WiFi_PacketArrived() (WiFi_Read(1, WIFI_CARDSTATUS) & WIFI_CARDSTATUS_UPLDCARDRDY)
    + ]! M; x* `  n5 J: t
  389. #define WiFi_ResendCommand(cmd) WiFi_SendCommand(0, (cmd), 0)
    , H* ~% @3 X0 W
  390. #define WiFi_SetMACAddr(addr) WiFi_MACAddr((uint8_t *)(addr), WIFI_ACT_SET)
    % |5 c9 K% t7 `. H3 t# W
  391. #define WiFi_ShowShortResponse() printf("Command response received: CMD%d, RESP_%08x\n", SDIO->RESPCMD, SDIO->RESP1)
    ! ~3 Y+ ^; W! U* K: H" A: p

  392. ( g! q! R0 ~! c1 s- |
  393. uint16_t WiFi_Associate(const char *ssid);# N: d3 o% @  ^, n" D6 \
  394. void WiFi_CheckCmdTimeout(void);; g; m: D; a' ]: _2 A4 @) Y0 y
  395. uint16_t WiFi_Connect(const char *ssid, const char *password);; i! F) h( Z* h
  396. uint8_t WiFi_DownloadFirmware(void);
    6 N; l7 k! S5 V6 ?; N
  397. uint16_t WiFi_GetPacketLength(void);
    2 A4 U/ X+ O) X* ^. X' R. R
  398. void WiFi_Init(void);" G" j1 B" V9 @4 g/ i
  399. uint16_t WiFi_KeyMaterial(MrvlIETypes_KeyParamSet_t *keys, uint16_t size, uint8_t action);
    * H5 u! p+ G$ f2 Z
  400. void WiFi_MACAddr(uint8_t addr[6], uint8_t action);- F1 O! i2 K" P9 p- `  c
  401. void WiFi_MACControl(uint16_t action);
    1 o# a8 n# S6 a: V' G8 t
  402. uint16_t WiFi_PacketPending(void);9 T" K. H) Z6 V( L: G5 Y: K
  403. void WiFi_PrepareTimer(uint16_t nms);8 @4 c9 H5 T* _, C/ x
  404. uint8_t WiFi_Read(uint8_t func, uint32_t addr);
    ; Y# \; Q+ e- U9 S4 |
  405. void WiFi_ReadData(uint8_t func, uint32_t addr, uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags);
      V9 M8 V6 y; n$ d# O; c
  406. uint16_t WiFi_ReadPort(void *buf, uint16_t size, uint16_t bufsize);
    9 e. N6 n; E3 V9 w0 v& o- o- F, }
  407. uint16_t WiFi_ReceivePacket(void *buf, uint16_t bufsize);
    7 I& H% x5 z4 r- ^  z
  408. uint16_t WiFi_ReceiveResponse(void *buf, uint16_t bufsize);
    $ @4 q7 q; d- u
  409. void WiFi_Scan(void);
    5 s. L- H3 V+ l7 M
  410. uint8_t WiFi_ScanSSID(const char *ssid, WiFi_SSIDInfo *info, uint8_t *buffer, uint16_t bufsize);
    $ ]6 W& y3 `+ \: {
  411. void WiFi_SendCMD52(uint8_t func, uint32_t addr, uint8_t data, uint32_t flags);
    7 r3 K  u7 U0 S- d% R+ {- e6 _
  412. void WiFi_SendCMD53(uint8_t func, uint32_t addr, uint16_t count, uint32_t flags);
    0 P' _9 z  @+ \% |) c6 g# o8 r. _
  413. void WiFi_SendCommand(uint16_t com_code, void *data, uint16_t size);  }* N0 c" b' y, T5 |/ I, A
  414. uint8_t WiFi_SendPacket(WiFi_DataTx *packet, uint16_t packet_len);* t# N1 y9 o4 T. m6 v8 ?4 s  i
  415. void WiFi_SetBlockSize(uint8_t func);) k0 B& y- F+ p/ r; U3 E
  416. uint8_t WiFi_SetKeyMaterial(uint16_t type, uint16_t info, const uint8_t *key, uint16_t len);
    & n5 Z6 i0 p7 j/ x" |
  417. void WiFi_ShowCIS(uint8_t func);9 s9 H5 i7 c+ J0 W! W! E: Q, K
  418. void WiFi_ShowKeyMaterials(void);2 B" f& Z% j3 X) E! k
  419. uint8_t WiFi_StartADHOC(const char *ssid);
    4 \7 l5 f" b3 w2 Z5 W4 f
  420. uint8_t WiFi_Wait(uint8_t status);
    ) n: q7 E, _( V9 r; @
  421. uint8_t WiFi_Write(uint8_t func, uint32_t addr, uint8_t value);4 E& b4 A2 }8 Y0 a7 s
  422. void WiFi_WriteData(uint8_t func, uint32_t addr, const uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags);
    $ g1 m/ _  O% L3 Q' k8 ]
  423. uint8_t WiFi_WritePort(const void *data, uint16_t size);7 s- U" M0 ^+ }' M0 y: X
复制代码
【WiFi.c】5 V5 y5 A& f$ Q0 p3 g1 @
  1. #include <stdio.h>1 T* p6 z, s# x
  2. #include <stm32f10x.h>
    % ~2 l- |( ^# D1 U, d
  3. #include <string.h>
    " b% J  l4 P/ d9 S
  4. #include "WiFi.h"
      M$ x/ m. w8 ~' h) c+ U
  5. 5 v5 i, ^" T6 w3 s& U# \$ L
  6. extern const unsigned char firmware_helper_sd[2516];; `+ f$ Y1 _# m7 j1 M! y$ @
  7. extern const unsigned char firmware_sd8686[122916];2 ?' j6 I  ?& o: j9 v; u2 H

  8. $ D1 M: i6 a7 @) b9 l$ e
  9. //const uint8_t wifi_mac_addr[] = {0x62, 0x1d, 0x2f, 0x00, 0x4e, 0x2d}; // MAC地址的第一个字节必须为偶数! 否则为多播地址
      z7 c- q+ T8 Y
  10. 8 u/ h4 S3 _; |
  11. static uint16_t rca;
    , z; D" a# P# F" s4 P% n
  12. static uint16_t wifi_timeout = WIFI_DEFAULTTIMEOUT;7 I+ [- {8 ?6 i3 z4 N0 H1 z7 s
  13. static uint32_t io_addr;
      O* F3 p# R9 B6 y, w7 h
  14. static uint16_t wifi_pending_size = 0; // 未读的数据包大小
    7 J, [/ s/ E5 b! g! V' X5 o
  15. ! @+ d4 n- ?, V: _
  16. void delay(uint16_t n);0 L" g0 |. e; g% X8 ^  N' w& O- d
  17. void dump_data(uint8_t *data, uint16_t len);$ w; s2 m- ^4 B0 ~$ [- E

  18. / s& H$ b0 ]2 j) U* @. ?
  19. /* 关联一个热点 */5 [+ F. K0 F+ Y+ q4 I" ^' r6 q
  20. uint16_t WiFi_Associate(const char *ssid)/ {# h7 D" I0 H0 Q/ Z/ c
  21. {) G( L6 d. P( V+ B6 `
  22.         uint8_t buffer[2048];9 B! f" L* ], C8 }) A+ c# ?
  23.         WiFi_SSIDInfo info;6 Z; Y! P* {" D1 K: @
  24.         WiFi_CmdRequest_Associate *cmd = (WiFi_CmdRequest_Associate *)buffer;6 t; Y# M. A- a* r( @' B
  25.         WiFi_CmdResponse_Associate *resp = (WiFi_CmdResponse_Associate *)buffer;
    & k& T4 A/ n) ^2 q3 l- G* w
  26.         MrvlIETypes_DsParamSet_t *ds;5 \2 ?0 Y$ t* Q: @- K9 Y) H
  27.         MrvlIETypes_CfParamSet_t *cf;9 \: u; z6 m! H* u- i
  28.         MrvlIETypes_AuthType_t *auth;6 G7 N& n/ Q6 N% ^- C8 P$ t
  29.         MrvlIETypes_RsnParamSet_t *rsn;
    4 k: N2 a* N$ a: n. W

  30. , L$ g- `* o( @$ n! Y3 R1 t/ ^/ v
  31.         if (!WiFi_ScanSSID(ssid, &info, buffer, sizeof(buffer)))+ U0 v' }! k7 M; r8 s
  32.         {
    0 S0 w* L1 L- w1 i8 _
  33.                 printf("Cannot find AP: %s!\n", ssid);* U' y* P; v$ n( j6 o0 Z: G
  34.                 return WIFI_ASSOCIATION_NOTFOUND;
    ; Y' s' H3 S  Z0 J6 [  J6 [
  35.         }
    % H! |) m& h8 l9 N( L: ~
  36.         / x6 H/ T3 n/ d( c; i0 ]/ Y
  37.         memcpy(cmd->peer_sta_addr, info.mac_addr, sizeof(info.mac_addr));! p- X" A- c# ]- [2 q
  38.         cmd->cap_info = info.cap_info;" n2 h* u/ E( X7 F1 F7 z, Z  i4 c
  39.         cmd->listen_interval = 10;1 n. R2 j, z# B. F4 i6 O- ]# L
  40.         cmd->bcn_period = info.bcn_period;6 O5 u8 r$ d5 R' ]4 u
  41.         cmd->dtim_period = 0;% S, h, E8 Y% C) V* O. N
  42.         memcpy(cmd + 1, &info.ssid, MRVLIE_STRUCTLEN(info.ssid));1 a: n% V( L6 e$ }# a
  43.         
    4 L( t& }' A2 K9 J6 a; f7 k
  44.         ds = (MrvlIETypes_DsParamSet_t *)((uint8_t *)(cmd + 1) + MRVLIE_STRUCTLEN(info.ssid));
    ( q# y- \2 L; i' B+ I8 n1 D
  45.         ds->header.type = MRVLIETYPES_DSPARAMSET;' B" r8 a' L  i( K+ y# L( R( p, }6 g
  46.         ds->header.length = 1;0 Z' k& F$ ?) @% a; y8 ~9 |3 x
  47.         ds->channel = info.channel;
    $ P9 i; q" z' C9 U8 P  s0 R
  48.         
    0 c; M' r- c1 R! J9 ?  b; S
  49.         cf = (MrvlIETypes_CfParamSet_t *)(ds + 1);
    / y! @" c2 A2 M+ W
  50.         memset(cf, 0, sizeof(MrvlIETypes_CfParamSet_t));
    * q/ {9 U( E$ N
  51.         cf->header.type = MRVLIETYPES_CFPARAMSET;* [% D) r- q& N& a( H
  52.         cf->header.length = MRVLIE_PAYLOADLEN(*cf);
    9 E  C" f! E* Z
  53.         + y3 z3 D3 z2 s! n1 G; |6 ]
  54.         memcpy(cf + 1, &info.rates, MRVLIE_STRUCTLEN(info.rates));" S. C! t8 F$ l! t5 E/ S
  55.         auth = (MrvlIETypes_AuthType_t *)((uint8_t *)(cf + 1) + MRVLIE_STRUCTLEN(info.rates));! y1 r1 e, C" {; c6 E# X
  56.         auth->header.type = MRVLIETYPES_AUTHTYPE;; }/ ^4 D" [( P
  57.         auth->header.length = MRVLIE_PAYLOADLEN(*auth);$ {! [* c! d+ Y! r, A5 y; w
  58.         auth->auth_type = AUTH_MODE_OPEN;
    + B, ~9 b$ h& K6 ~
  59.         3 P3 |0 I7 C0 p" Q: U
  60.         rsn = (MrvlIETypes_RsnParamSet_t *)(auth + 1);
    " I! n: w# n8 e1 n* V3 s; I/ \
  61.         if (info.rsn.header.type)0 w/ }  ]& ^. }7 Q# b. V) q; s
  62.         {
    7 w3 F* K& c' C5 R* ?  W
  63.                 // WPA2网络必须在命令中加入RSN参数才能成功连接  A9 P2 C6 {" ?8 u
  64.                 memcpy(rsn, &info.rsn, MRVLIE_STRUCTLEN(info.rsn));
    8 L& W9 V4 H% i
  65.                 WiFi_SendCommand(CMD_802_11_ASSOCIATE, buffer, (uint8_t *)rsn - buffer + MRVLIE_STRUCTLEN(info.rsn));
    . i% y; _3 R' R% p
  66.         }
    7 Y! Z: T, C, @* _4 G
  67.         else$ W- i7 b9 p" }& k' c6 o
  68.                 WiFi_SendCommand(CMD_802_11_ASSOCIATE, buffer, (uint8_t *)rsn - buffer); // 其余网络不需要RSN参数- a7 k: p5 x9 }5 E: K4 ?/ b
  69.         
    ' Z* S$ F/ @5 a4 v+ B. b  M
  70.         if (!WiFi_ReceiveResponse(buffer, sizeof(buffer)))
    : r: f( e( Y) ?. D$ {
  71.         {4 i: ]. z. b" J8 Z7 O6 K
  72.                 printf("Association with %s failed!\n", ssid);
    2 n: B# M, ?. d: R
  73.                 return WIFI_ASSOCIATION_ERROR;
    ( ^* X* w& C% B3 q1 Z
  74.         }# D9 h) }) c: t& S8 {
  75.         + T) l3 ^/ h7 r! i
  76.         //printf("capability=0x%04x, status_code=0x%04x, aid=0x%04x\n", resp->capability, resp->status_code, resp->association_id);
    + w+ m9 C* {# [; `2 ^- b' t- r8 b# o  P
  77.         if (resp->association_id == 0xffff)! W& d9 H, v4 I" \+ I
  78.                 return ((-resp->capability) << 8) | resp->status_code;' M$ R  T) S* u. P! _2 m
  79.         return WIFI_ASSOCIATION_SUCCESS;2 c" s# l$ P2 ~. A. Y- E) I1 F! P. i7 c
  80. }5 I5 E- M. C+ z) q  r. ]: q+ a
  81. 2 W' z; p0 I' u5 |0 R
  82. /* 检查命令是否收到了回应, 若没收到则重发命令 */% C" n1 z; Q" y) m8 C. X* n
  83. void WiFi_CheckCmdTimeout(void)" y% I$ h2 F: k* b$ A" c
  84. {" Q! i7 i3 ~8 P  _; e( v/ e
  85.         while (SDIO->STA & SDIO_STA_CTIMEOUT)
    ) f8 k: |) W4 ?5 \( b/ n
  86.         {- u7 ]' Q% x7 n& o
  87.                 SDIO->ICR = SDIO_ICR_CTIMEOUTC; // 清除标志5 I7 X2 O( a2 w9 U! |  Q
  88.                 SDIO->CMD = SDIO->CMD; // 重发
    # \% C2 l; |3 }2 ?
  89.                 printf("Timeout! Resend CMD%d\n", SDIO->CMD & SDIO_CMD_CMDINDEX);
    , R6 l9 t( k7 u0 K
  90.                 while (SDIO->STA & SDIO_STA_CMDACT);
    + A4 d' @7 M( k) J4 m  P
  91.         }1 D: b- f3 o3 d; a) B
  92. }
    2 y6 U% p% s8 x+ X' Z

  93. 0 Y7 q- ^  @- B& c0 p
  94. /* 连接WiFi热点, 并输入密码 */4 z/ b7 j3 g4 y  R( h- _
  95. uint16_t WiFi_Connect(const char *ssid, const char *password)
    $ R( m( z9 Z' I7 L0 s* _* @, ~/ K
  96. {
    $ V. h" f6 }2 |4 H
  97.         uint16_t ret;
    ( Q+ Z2 @/ P- z: ~
  98.         do
    % e. J5 I3 h! _/ `: P. u7 @
  99.         {9 C6 {, p% p3 Y; e* p
  100.                 ret = WiFi_Associate(ssid);
    9 O7 c3 l3 j" k; _# M3 s6 r7 X
  101.                 if (ret != WIFI_ASSOCIATION_SUCCESS). w/ F8 P( [! @( b1 Y" s9 f. H
  102.                 {( \, n: s. I' i9 l
  103.                         printf("WiFi_Associate returned 0x%04x\n", ret);& k, A2 ]0 L2 |) X; Y9 \2 W
  104.                         delay(2000); // 等待一段时间后重连
    % e% f6 r# T6 u4 f
  105.                 }6 G! X3 |$ ^# J6 Y& w
  106.         } while (WIFI_ASSOCIATION_TIMEOUT(ret) || ret == WIFI_ASSOCIATION_NOTFOUND); // 若连接超时, 或未扫描到热点, 则重连
    % {6 z. j1 S* M1 t; Q
  107.         3 b- M. T/ G" C0 Y+ \5 g
  108.         if (ret != WIFI_ASSOCIATION_SUCCESS)
    6 u' ~( {* `& P8 d/ b4 C( n  s! E
  109.                 return ret;, R  s. N! _, e9 z/ B8 ~
  110.         ( |1 A8 ^  @/ R5 t
  111.         printf("Connected to %s!\n", ssid);4 W, d; Q! q- W4 `4 M2 p# m6 z
  112.         return ret;1 e3 M5 N2 o7 Q0 ^$ X2 |
  113. }
    / ^! d: I+ L$ Z% p

  114. 6 k, l0 [# u. F( p
  115. /* 下载固件 */
    & |/ e& [1 `- l' y1 Z
  116. // 参考文档: marvell-88w8686-固件下载程序说明.doc( I# L. M4 F' N
  117. uint8_t WiFi_DownloadFirmware(void)/ A! v) u! @" H9 s) D
  118. {
    9 t! R4 P  w' i; Y) g
  119.         uint8_t helper_buf[64];% _0 Q& D  Q4 g: a) o2 a6 x$ l
  120.         const uint8_t *data;
    / L. m: @" s1 J# j
  121.         uint16_t size;" m& h9 c# j. o" e0 h( Y
  122.         uint32_t len;  I6 D6 p! l2 p* ~6 n# R7 ]9 m# b9 ~
  123.         
    ) w' g3 n) f; T- E3 A
  124.         // 块大小设为32' I% t# i! m0 R  u/ S
  125.         SDIO->DCTRL = (SDIO->DCTRL & ~SDIO_DCTRL_DBLOCKSIZE) | SDIO_DCTRL_DBLOCKSIZE_2 | SDIO_DCTRL_DBLOCKSIZE_0;
    6 K/ A6 Q* f+ V- O
  126.         WiFi_SetBlockSize(1); // 应用到Function 1
    5 x9 N* J1 B9 z, J
  127.         
      t' b6 i0 w' n2 d& n
  128.         // 下载helper( d" O- t8 {. l; v+ i4 B
  129.         io_addr = WiFi_Read(1, 0x00) | (WiFi_Read(1, 0x01) << 8) | (WiFi_Read(1, 0x02) << 16);# v& |2 Y% w, z6 T7 A% N
  130.         data = firmware_helper_sd;0 w3 }9 m2 d* j
  131.         len = sizeof(firmware_helper_sd);* g2 |- Q( L; ^1 q( x
  132.         while (len)! s6 `3 {' ^; f3 p0 a
  133.         {
    6 Z* {6 ?8 |4 }9 h' C4 j# ?1 M
  134.                 // 每次下载64字节, 其中前4字节为本次下载的数据量4 C  n- ~% N2 T: y* ?
  135.                 size = (len > 60) ? 60 : len;% m% o3 O3 C  t' J# U. L5 n0 t
  136.                 *(uint32_t *)helper_buf = size;1 v) E/ Y9 V8 ~7 Y; [! ^0 s+ t
  137.                 memcpy(helper_buf + 4, data, size);7 G6 F( x" a% t  Y9 C
  138.                
    1 A( M5 g1 G0 N2 W4 l
  139.                 WiFi_Wait(WIFI_CARDSTATUS_DNLDCARDRDY);( B2 _: l8 {9 q& [+ m- f" H
  140.                 WiFi_WritePort(helper_buf, sizeof(helper_buf));
      ^1 T7 V1 g. M5 J
  141.                 len -= size;  i" k6 |0 L5 V: z5 W/ ]! S# D. p
  142.                 data += size;7 }& H- H4 M# `& f
  143.         }3 r$ ]! z( A5 @/ f, c
  144.         *(uint32_t *)helper_buf = 0;0 v; {$ f. L( E4 E; Q) A
  145.         WiFi_WritePort(helper_buf, sizeof(helper_buf)); // 以空数据包结束- n: e- u- p( b& @7 f+ H6 B* C
  146.         $ D# \% }; W$ ^2 T( v
  147.         // 下载固件
    # c; \* s  B! @9 q+ H1 Y6 O# N! i
  148.         data = firmware_sd8686;
    5 N6 p0 z! g* |* W; B# r
  149.         len = sizeof(firmware_sd8686);
    % m6 s7 N8 t1 x5 L* b0 j0 Q  {6 L
  150.         while (len)! R1 d' U  x" ^1 n1 I
  151.         {2 j( B6 \. V( G
  152.                 WiFi_Wait(WIFI_CARDSTATUS_DNLDCARDRDY);( |6 s/ {; L- U: E
  153.                 while ((size = WiFi_Read(1, WIFI_SQREADBASEADDR0) | (WiFi_Read(1, WIFI_SQREADBASEADDR1) << 8)) == 0); // 获取本次下载的字节数. Z6 Q) Q  ^1 r6 {; W1 t
  154.                 //printf("Required: %d bytes, Remaining: %d bytes\n", size, len);3 L2 l' |3 |7 n# z/ w1 A- K
  155.                
      r4 m: H& g- S) s
  156.                 if (size & 1), o; `5 \4 A* j/ {. e
  157.                 {9 r- l$ k* j" W: y7 T) W' m9 q: C
  158.                         // 若size为奇数(如17), 则说明接收端有CRC校验错误, 应重新传送上一次的内容(这部分代码省略)' n3 U1 p& |. B" g: |1 o6 v3 K/ z
  159.                         printf("Error: an odd size is invalid!\n");  n4 n# r- \( f! e
  160.                         return 0;
    ! s0 ?( O1 D8 H/ i+ t$ @
  161.                 }1 z, {9 H/ n: K$ W& O% C
  162.                 if (size > len)
    % Q- F( q" a! W9 U) z1 t# X
  163.                         size = len;) K) U# k; a9 z4 E
  164.                   s; Z$ j7 g! Y2 ?0 S  b4 _
  165.                 if (!WiFi_WritePort(data, size))
    ' s% r5 c2 x7 t5 w4 e; ~
  166.                 {
    & j; u6 _4 d; Z: M* J
  167.                         printf("Data transfer error! SDIO->STA=0x%08x\n", SDIO->STA);
    3 T9 y# @' z& \0 Y6 S$ ]
  168.                         return 0;* m! j' _6 ~/ O2 Z0 e  R* m5 l: L
  169.                 }! r; t! N; t" u5 C' ~7 ^; h
  170.                 ) R" r/ W+ D) J; t8 O( c
  171.                 len -= size;
    1 H0 v+ p8 F" _9 m8 y
  172.                 data += size;
    # N. t; ^) ?2 g0 L8 k
  173.         }. G' U; N  X2 d' v; n# D
  174.         
    " `0 P2 F- ^& e# H2 I& F6 _
  175.         // 等待Firmware启动$ S4 {7 o' }2 _0 m8 z
  176.         while (WiFi_GetPacketLength() == 0xfedc);
    3 [' h# ^+ j8 E5 P* F: @
  177.         printf("Firmware is successfully downloaded!\n");8 Y0 w8 t) w& p0 d2 P
  178.         return 1;' N; A3 e3 F) }- b$ V
  179. }
    0 @& @+ z  O: Y) {$ E0 r( l* d

  180. 0 @1 J- Z: X8 _3 a/ v0 F5 v2 }; `
  181. /* 获取数据帧大小 */
    4 q  w' d! J3 I+ d2 q# a" K
  182. uint16_t WiFi_GetPacketLength(void)" Q9 Z  a' G% h. e2 y& h0 y
  183. {- j# ?9 @* D& |; o" f
  184.         return WiFi_Read(1, 0x34) | (WiFi_Read(1, 0x35) << 8);
    % G( ~; `) W* K
  185. }' |3 J% \7 Y: ?& A: T7 ?

  186. $ _. v5 v) E6 h& l" D" o
  187. /* 初始化WiFi模块 */
    $ L- _5 p) \6 I' g8 n& U
  188. // SDIO Simplified Specification Version 3.00: 3. SDIO Card Initialization
    # Y3 n7 D$ C' [4 U7 U
  189. void WiFi_Init(void)7 e9 s! q: a8 K/ f: H$ Z( f
  190. {
    , s/ n) G( ?/ N6 \* h" B
  191.         printf("Initialization begins...\n");
    ' v$ `* g$ `2 ]) D: Z
  192.         SDIO->POWER = SDIO_POWER_PWRCTRL;6 N, e" z0 R' i9 n. X" Z
  193.         SDIO->CLKCR = SDIO_CLKCR_CLKEN | 178; // 初始化时最高允许的频率: 72MHz/(178+2)=400kHz. Q; H6 c2 x8 _  n3 h" Q  X
  194.         delay(5); // 延时可防止CMD5重发( j' n# x: J* h4 X$ d9 B4 E
  195.         
    & Z; e/ p. u) O" p; n. ^/ E
  196.         // 不需要发送CMD0, 因为SD I/O card的初始化命令是CMD52
    # H* j5 _# N0 E2 P
  197.         // An I/O only card or the I/O portion of a combo card is NOT reset by CMD0. (See 4.4 Reset for SDIO)
    0 l& a. s3 d3 ^/ }% `' Q$ d
  198.         9 p) H; I+ j0 W$ J' |
  199.         /* 发送CMD5: IO_SEND_OP_COND */
    & m* [5 ]& I( l+ b
  200.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 5;; m2 [9 g( R, S! A
  201.         while (SDIO->STA & SDIO_STA_CMDACT);- ?# f9 Q' J$ o
  202.         WiFi_CheckCmdTimeout(); // 为了保险起见还是要检查一下是否要重发命令4 C8 e0 s+ i4 C+ l9 H
  203.         if (SDIO->STA & SDIO_STA_CMDREND)6 T! n5 `. J/ ^1 N! W' s! _
  204.         {- @2 a% W. z) ~, K3 P8 ~5 M
  205.                 SDIO->ICR = SDIO_ICR_CMDRENDC;6 D2 ^+ Q" @# B$ a2 s: X* U) U: ]
  206.                 WiFi_ShowShortResponse();! B; e" m+ \1 f  t0 D
  207.         }  S: i4 c1 M% X
  208.         2 m5 ~, B8 G' i0 z
  209.         /* 设置参数VDD Voltage Window: 3.2~3.4V, 并再次发送CMD5 */
    ; \/ w8 j7 p; ]; o0 v7 ?5 {( C5 ]- Q
  210.         SDIO->ARG = 0x300000;
      C1 p5 L4 J5 I# X, P: H
  211.         SDIO->CMD = SDIO->CMD;; |) @5 f/ }0 E( k2 g4 b# o
  212.         while (SDIO->STA & SDIO_STA_CMDACT);" @% q$ R, H$ N% u3 Z
  213.         if (SDIO->STA & SDIO_STA_CMDREND)# \4 ^  O1 C) g% j
  214.         {, o6 `/ G5 _) }# G* W1 h3 q; |
  215.                 SDIO->ICR = SDIO_ICR_CMDRENDC;) _+ Z/ u5 k6 t) C3 ?/ E  z  f
  216.                 WiFi_ShowShortResponse();
    ) O# t5 x% n- s9 h8 l+ d1 b) c
  217.                 if (SDIO->RESP1 & _BV(31)); ]+ x% E$ T& {  R0 k1 g7 i
  218.                 {
    5 O: s; E  c; r' G: D" H
  219.                         // Card is ready to operate after initialization
    $ p! Q2 D. I, S- d  ^: ?
  220.                         printf("Number of I/O Functions: %d\n", (SDIO->RESP1 >> 28) & 7);( r, @7 o) o2 D0 H7 I
  221.                         printf("Memory Present: %d\n", (SDIO->RESP1 & _BV(27)) != 0);+ ^5 S9 o1 |7 i% X7 J2 y- Q4 h
  222.                 }
    . Y! t1 s# r: Z$ B
  223.         }1 Q9 T7 V  {$ {8 b0 Z" q, d1 M% y. k, J
  224.         
    & M( x# K+ [2 P7 X0 T7 u
  225.         /* 获取WiFi模块地址 (CMD3: SEND_RELATIVE_ADDR, Ask the card to publish a new relative address (RCA)) */( j# I# x( t6 W# Z
  226.         SDIO->ARG = 0;
    0 y( D% K% F+ R* f
  227.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 3;
    * H, A0 `; U. `* t7 n9 ]. s5 ?1 Y
  228.         while (SDIO->STA & SDIO_STA_CMDACT);
    ' v6 c4 w" {2 g# }& B7 G# ^
  229.         if (SDIO->STA & SDIO_STA_CMDREND)
    9 |" E; o* r& [' S0 l' S
  230.         {) o, U7 w4 l1 D6 M; e
  231.                 SDIO->ICR = SDIO_ICR_CMDRENDC;
    ' X- _# t4 T! A0 u) e2 w; M
  232.                 rca = SDIO->RESP1 >> 16;& z( _6 ~5 G5 Z" H
  233.                 printf("Relative card address: 0x%04x\n", rca);' Y1 q/ w0 @1 Q
  234.         }. J6 E3 {; Z0 u5 N  U+ I( Y+ W
  235.         
    0 N% Z0 ]: ~2 R: r, w
  236.         /* 选中WiFi模块 (CMD7: SELECT/DESELECT_CARD) */
    : r0 J& M8 a$ x7 ?6 D) U& W) {6 s
  237.         SDIO->ARG = rca << 16;
    9 _! M1 D  O, d* D- @
  238.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 7;
    : _0 h/ g6 G4 a
  239.         while (SDIO->STA & SDIO_STA_CMDACT);' }# n/ X) Y. b4 E: D* F
  240.         if (SDIO->STA & SDIO_STA_CMDREND)- S, O7 c) N; p5 j& g% Y& E' M
  241.         {
    8 l+ l6 R- T$ P: I; Z# P
  242.                 SDIO->ICR = SDIO_ICR_CMDRENDC;. `& ?: y; P$ f6 ?. n3 S1 ?
  243.                 printf("Card selected! status=0x%08x\n", SDIO->RESP1);/ N) K* `' c- j+ l% [% B8 ?- {  ~
  244.         }
    2 q! ~: U/ ^. e! b3 P6 Y4 n* U. t4 ^3 {
  245.         $ P2 r$ H* @* ]7 o% i0 x
  246.         // 提高时钟频率/ i4 q/ ]' a; m  o- X2 l  {) v
  247.         SDIO->CLKCR = (SDIO->CLKCR & ~SDIO_CLKCR_CLKDIV) | 70; // 72MHz/(70+2)=1MHz
    / S. D. w8 o- V- B& [9 `
  248.         SDIO->DTIMER = 1000000; // 当频率为1MHz时, 超时时间为1秒
    . u$ X- M3 h% b! u: |
  249.         //SDIO->CLKCR = (SDIO->CLKCR & ~SDIO_CLKCR_CLKDIV) | 1; // 72MHz/(1+2)=24MHz3 ~1 j! C1 ^8 a" S% _/ I
  250.         1 J" J+ ^% [0 a$ m! O$ T& {4 t. L
  251.         /* 选择总线宽度 (Wide Bus Selection) */
    . O, {. a) d1 I; B. [. a* b! k4 I
  252.         // For an SDIO card a write to the CCCR using CMD52 is used to select bus width. (See 4.5 Bus Width)# z5 A8 P2 I0 [( |2 m. u4 a
  253.         // CMD52: IO_RW_DIRECT, CCCR: Card Common Control Registers: |: C2 K) n3 f- p
  254.         WiFi_Write(0, 0x07, WiFi_Read(0, 0x07) | 0x02); // Bus Width: 4-bit bus" t7 }' t. d8 H" D
  255.         SDIO->CLKCR |= SDIO_CLKCR_WIDBUS_0;
    2 ~6 y1 d. R& q5 q' o
  256.         0 ^2 \9 ?" T! T+ r
  257.         // 初始化Function 13 ]3 c* w: p. C; k
  258.         WiFi_Write(0, 0x02, 0x02); // IOE1=1 (Enable Function)
    / C) x$ F. E8 F& A0 z
  259.         while ((WiFi_Read(0, 3) & 0x02) == 0); // 等到IOR1=1 (I/O Function Ready)
    4 T- O; s- a3 u
  260.         * A1 [$ b# V+ C6 q0 o+ R8 c
  261.         // 显示CIS信息8 d% [# O' Y7 D+ x) B+ @) W  q
  262.         //WiFi_ShowCIS(0);
    8 @, p) c! [: B- K/ G
  263.         //WiFi_ShowCIS(1);
    7 W; w* d* y7 q: Z$ p
  264.         9 e. b  L7 r/ ~* u  s* S
  265.         // 下载固件$ s6 Z: ^( R. P4 _! U
  266.         WiFi_DownloadFirmware();8 U  Y' Y" j' t1 B1 W1 u
  267.         
    2 K& q3 t$ {/ D, F) y8 u
  268.         // 设置数据块大小为256字节
    ) E) p$ p9 C/ K( e
  269.         SDIO->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3;. Q( x4 T8 c) f& M
  270.         WiFi_SetBlockSize(0);) x& W8 d' L: i) f( p  P
  271.         WiFi_SetBlockSize(1);# M' {/ V# A  q
  272.         
    ! i+ A# x; \& u0 b6 \8 C
  273.         // 允许发送和接收- X. V  D' u4 p% Q& p  x
  274.         // 不使用带有LLC子层的802.2SNAP帧格式, 这样LLC和SNAP这8个字节的内容就不会夹在数据链路层的源地址字段与数据字段之间
    5 o% M& y2 |4 U% O$ X
  275.         WiFi_MACControl(WIFI_MACCTRL_ETHERNET2 | WIFI_MACCTRL_TX | WIFI_MACCTRL_RX);
    - z! s. U+ r" ?0 f5 p/ W" K
  276. }
    $ V. d0 S4 J1 R

  277. : m  `" z" M! j  I$ M; ]
  278. /* 获取或设置密钥 */
    . g3 \" O8 J8 `4 [8 q! {
  279. uint16_t WiFi_KeyMaterial(MrvlIETypes_KeyParamSet_t *keys, uint16_t size, uint8_t action): _" g9 p' Z/ z( A( L
  280. {
    ; D6 E2 A4 H* d
  281.         uint8_t buffer[256];
      ^; O0 b+ V& P2 F3 o9 z2 D  b
  282.         uint8_t ret_size;$ a1 s( u" R+ `
  283.         WiFi_Cmd_KeyMaterial *cmd = (WiFi_Cmd_KeyMaterial *)buffer;$ e- i: R. s* s" x
  284.         cmd->action = action;
    : v' }+ ?1 j' p5 Z- m
  285.         if (action == WIFI_ACT_SET)
    5 H7 S3 H/ [) `9 _% u3 ?/ X
  286.         {
    # ^! Y  k3 K) c3 {( d
  287.                 memcpy(cmd + 1, keys, size);. t5 j0 N. O1 a9 D
  288.                 WiFi_SendCommand(CMD_802_11_KEY_MATERIAL, buffer, sizeof(WiFi_Cmd_KeyMaterial) + size);/ V! }: p, Y! e, z6 h- _/ D
  289.         }! G% ^( }. K( v3 R$ u/ \
  290.         else
    7 I4 i' z' ]7 |3 h) i
  291.                 WiFi_SendCommand(CMD_802_11_KEY_MATERIAL, buffer, sizeof(WiFi_Cmd_KeyMaterial));9 W* F3 J  Q9 K6 @! z
  292.         WiFi_ReceiveResponse(buffer, sizeof(buffer));! U7 z5 e! ]' c
  293.         
      Q" T- o( @- V& d) Z
  294.         if (action == WIFI_ACT_GET)) |7 Q7 r9 [+ p5 Z2 n
  295.         {9 H+ C9 z, \* Y0 n# q# T
  296.                 ret_size = cmd->header.size - sizeof(cmd->header) - sizeof(cmd->action);
    2 _' }4 X% N3 M$ j9 E
  297.                 if (ret_size <= size)
    , ?0 H: C% J* H, K6 }6 o/ O
  298.                         memcpy(keys, cmd + 1, ret_size);. `. X  S; ?1 L9 V5 \
  299.                 else
    & h% h8 ~, w& i9 H- ^6 d0 [
  300.                         printf("WiFi_KeyMaterial: Buffer size is too small! %d bytes required!\n", ret_size);
    ) `4 U6 ?! B" X. @% D( N
  301.                 return ret_size; // action=get时返回读取的数据大小
    # {$ C: q" S2 B" N# W, _
  302.         }
    5 P/ @1 r4 b) a  i% T3 I7 F7 h
  303.         else. [& T/ g% G; n  j, B" a, X3 o2 @
  304.                 return cmd->header.result; // action=set时返回命令执行结果值6 _5 u- Q" U1 g& h+ _
  305. }
    6 u: n3 t6 U# ?: c1 h3 R, D$ U

  306. & d- H% w: j8 ^9 A9 {3 `; ]
  307. /* 获取或设置MAC地址 */3 @& N) G) t# z
  308. void WiFi_MACAddr(uint8_t addr[6], uint8_t action)
    5 O2 m* |+ K6 w
  309. {3 ]& P9 v, D/ N4 J1 a3 I. a
  310.         WiFi_Cmd_MACAddr cmd;
    ; J9 n: f  ]* G4 L7 c
  311.         cmd.action = action;' ^2 g% y! ]0 |; Y, }( e
  312.         if (action == WIFI_ACT_SET)! V8 V* [0 Z; g& j
  313.                 memcpy(cmd.mac_addr, addr, 6);6 Y6 l  A: |& _& a: ^
  314.         
    " ^8 C7 `, ?4 ~& R' [
  315.         WiFi_SendCommand(CMD_802_11_MAC_ADDR, &cmd, sizeof(cmd));
    ; {+ B3 m3 _; x* u. O( A
  316.         WiFi_ReceiveResponse(&cmd, sizeof(cmd));
    7 b2 r, `! e4 p  C/ v
  317.         if (action == WIFI_ACT_GET)
    4 V$ e+ d( f$ B5 v5 H
  318.                 memcpy(addr, cmd.mac_addr, 6);0 ^/ e' b2 E9 p# K& v  Q: X- t4 v  F
  319. }6 o& g8 Q# }7 }, D5 b
  320. # @- ^! N* K( M+ l$ p+ @
  321. /* 配置MAC */+ G% ?. G9 V" q# Q- W4 @; W, ^5 h
  322. void WiFi_MACControl(uint16_t action)
    " \. X$ W7 T) n7 {) U8 {6 D% a
  323. {
    ( H$ k. A: A6 b$ V3 F3 X
  324.         WiFi_Cmd_MACCtrl cmd;- C& T; s. T+ Y" R) K$ M2 J3 {# _
  325.         cmd.action = action;
    # g- h, m) Z! ]; e8 V& \
  326.         cmd.reserved = 0;
    ) _; a8 Y$ T+ }2 Q/ _, s5 R( m9 J6 t: x& i
  327.         WiFi_SendCommand(CMD_MAC_CONTROL, &cmd, sizeof(cmd));+ R" s1 F: U( [+ J; s
  328.         WiFi_ReceiveResponse(&cmd, sizeof(cmd));
    7 z: R2 s! T, A9 C2 O, I. Y
  329. }
    + Y3 @1 \7 B' Q; V' s

  330. ; U- S$ }# d' t% q1 ^, Z" w
  331. /* 获取滞留的数据包大小 *// ?5 I- w5 n" s$ G2 Q- C
  332. uint16_t WiFi_PacketPending(void)
    ' `8 r4 ~, r! b3 h- e
  333. {
    5 i2 Y7 V  o$ V) b& j
  334.         return wifi_pending_size;
    ) m/ Y  F3 @. |+ b% D8 u+ z
  335. }6 s: ^4 D( T4 K$ C5 r

  336. / o* Z9 E7 o! A! u* o  V6 c9 k& v
  337. /* 准备好超时计时器 */
    0 ]6 M: ~1 o/ A$ a
  338. void WiFi_PrepareTimer(uint16_t nms)
    ' T7 F$ L7 U' m4 C
  339. {# I4 H2 @2 _2 X! V9 B
  340.         TIM6->ARR = 10 * nms - 1;
    # W5 z* w0 A. v0 R
  341.         TIM6->PSC = 7199; // 72MHz/7200=10kHz
    6 b" ]! p& w9 k4 P
  342.         TIM6->EGR = TIM_EGR_UG; // 保存设置
    4 t; Y1 a+ D7 E' c( I
  343.         TIM6->SR &= ~TIM_SR_UIF; // 清除溢出标志位. U+ a, ?9 k6 l  t& x
  344.         TIM6->CR1 = TIM_CR1_OPM | TIM_CR1_CEN; // 开始计时, 模式为非循环模式
    ; S' }9 I' V  ?' P: p
  345. }3 g5 ^5 y  {4 I+ z: d
  346. % F7 k& e& P$ i& z
  347. /* 读寄存器 */8 s9 N2 ~6 ?, O  f- l" J
  348. uint8_t WiFi_Read(uint8_t func, uint32_t addr)
    ! }8 n- A7 F* ?5 H7 D5 l
  349. {- X; q0 {- {* ]$ I- a% @7 ]" L1 b
  350.         WiFi_SendCMD52(func, addr, NULL, NULL);+ y# {9 K( Y. u* ~4 k" F4 h+ f
  351.         if (SDIO->STA & SDIO_STA_CMDREND)1 d4 v4 W# o. l- i* r
  352.         {. M4 @5 d0 ~0 G8 I: H) J5 h
  353.                 SDIO->ICR = SDIO_ICR_CMDRENDC;
    ! Q( }3 j* f4 b* @  S
  354.                 return SDIO->RESP1 & 0xff;6 @8 P) o  y: t, o8 D
  355.         }
    . {* f8 K2 |. L) u( `( o; A/ W& I
  356.         else  ]5 Z8 M! E; t9 B( v
  357.         {% P& \+ h' o, O* D- V+ [' K4 x
  358.                 printf("WiFi_Read failed, SDIO->STA=0x%08x!\n", SDIO->STA);1 p; R- W. d1 |" d" z
  359.                 return 0;
    ; D2 \+ s$ j3 W: ?
  360.         }: U7 ~' _# h5 `! j. g. Y
  361. }8 V; i: y9 B9 A7 H

  362. - t' x* ~: t5 `: S- P+ f
  363. /* 读数据 */0 E! F: R' Q( d
  364. // count为要发送的字节数或块数, bufsize为data缓冲区的大小/ x2 o7 q- K$ g& F0 Y" r* s( t
  365. // bufsize=0时, 只读取数据不存入缓冲区6 }% P5 x6 E" _4 W" d" q6 I
  366. void WiFi_ReadData(uint8_t func, uint32_t addr, uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags)
    $ o9 w7 M/ |8 y4 C5 d$ v# R
  367. {
    $ o3 j1 z- H" |3 F1 y6 _: a+ n
  368.         uint32_t len, temp;3 q& }0 {$ W2 f
  369.         if (flags & CMD53_BLOCKMODE)
    . p: ^# ^2 I- [* P. K3 z8 v
  370.         {1 ?9 b7 W3 [( q  @2 A# @5 v
  371.                 len = count * WiFi_GetBlockSize(); // count表示数据块数
    7 t) \2 k7 A) s/ m% d. z
  372.                 SDIO->DCTRL &= ~SDIO_DCTRL_DTMODE; // Block模式
    0 R9 V4 v) f8 O8 S
  373.         }; I  c- O* Y7 X0 x9 W9 g
  374.         else
    $ M* ]/ b. n6 s/ h3 u- e
  375.         {
    $ e$ p/ ]& C7 S" x
  376.                 len = count; // count表示字节数
    4 F0 [) M5 s2 x2 ?$ e6 l
  377.                 if (len % 4 != 0)8 b" t  K5 n  k. B8 p9 v& `% c
  378.                 {) |1 ?" h4 X1 a1 t
  379.                         len += 4 - len % 4; // WiFi模块要求写入的字节数必须为4的整数倍
    ) x. L$ |3 M5 m& R/ g
  380.                         count = len;
    ; i4 M7 a& N* }0 Z' a) M8 G
  381.                 }+ V3 a3 S$ A, `* X$ ~! ~5 V
  382.                 SDIO->DCTRL |= SDIO_DCTRL_DTMODE; // Multibyte模式' G& B2 |5 F7 E; s0 K
  383.         }8 W' ~& p+ Y7 F0 Z2 S
  384.         SDIO->DLEN = len;
    8 l$ V. L$ c# @- r6 G- S8 x; }
  385.         SDIO->DCTRL |= SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTEN; // 设置传输方向为从模块到主机+ p; P6 u# A; @
  386.         
    & O9 v' y* v5 y; i
  387.         WiFi_SendCMD53(func, addr, count, flags);( _% M7 q* K8 B% C. x
  388.         while (len)# t+ S$ @9 A( C# E: \% E
  389.         {
    ! q; t' x1 u1 Y) l' q
  390.                 if (SDIO->STA & SDIO_STA_RXDAVL)
    , w' _5 C' y, T9 w
  391.                 {/ l4 n2 S; B# z6 Z
  392.                         // 若有数据到来就读取数据2 A0 J/ d9 q2 ?
  393.                         len -= 4;2 @$ B) c" Q" {% |5 W5 ]% D
  394.                         if (bufsize >= 4)6 n0 M: M8 h; `) A; p9 h+ d- k
  395.                         {
    / h: A1 a( p# k% C; v
  396.                                 *(uint32_t *)data = SDIO->FIFO;
    : P. J5 l2 F* B" l5 m4 P7 M
  397.                                 data += 4;
    ! q6 D6 c- a4 y' q  m* _' r
  398.                         }( r  ]* x8 e, U' a# K* a
  399.                         else
    - U# g$ S* w' y, n6 v: {$ b
  400.                         {& [# Y- A2 l1 Z6 d9 P
  401.                                 temp = SDIO->FIFO;
    % l" m6 E7 q3 q" ~; X
  402.                                 if (bufsize > 0)
    - {5 s0 a% Z8 `1 S. \
  403.                                 {  r7 V% s7 y: e7 x9 f% V, V0 W
  404.                                         // 写入缓冲区最后1~3字节8 y1 r9 s) O( p# u$ k
  405.                                         memcpy(data, &temp, bufsize);4 ?0 _+ B: X2 t* u# X% G
  406.                                         bufsize = 0;" G( ^3 q' H/ L. `# W% H7 x
  407.                                 }2 `, x- n# k7 F  }) {6 r+ y' s. l
  408.                         }
    5 M" f5 y4 W' A% Y5 ?$ x. ]; R
  409.                 }! n1 m  f7 [$ ~
  410.                
    5 s; Y  s' l  X1 L; N0 _
  411.                 if (SDIO->STA & SDIO_STA_DTIMEOUT), @7 u$ S1 e1 U
  412.                 {1 q9 Y- L4 f6 s/ [+ x1 V
  413.                         printf("Data Timeout!\n");
    * k: w8 m0 q' o% F* S7 l% A
  414.                         break;
    ) H: f4 ?. V6 U: T; l/ o9 d
  415.                 }! J- R7 J1 c* [+ N7 k
  416.                 else if (SDIO->STA & SDIO_STA_DCRCFAIL)" H3 D, s' l& A5 M6 t& i7 K% e
  417.                 {/ `  U7 M4 R8 \7 W7 e+ A
  418.                         printf("Data CRC check failed! %d bytes are lost\n", len);
    0 D, ]$ U6 z1 S6 N# h- r& C8 w" [
  419.                         break;
    . i1 ^8 n6 f  a) r6 Z. Z2 v
  420.                 }6 [7 B7 i! p# D7 q# j0 U0 J- R
  421.         }
    ( j; O9 V, P" X) @' j
  422.         
    # [9 D( R0 J( Y& E7 k% B
  423.         while (SDIO->STA & (SDIO_STA_CMDACT | SDIO_STA_RXACT));6 z% y$ H3 ]4 R7 [: d$ q/ k! |
  424.         SDIO->DCTRL &= ~SDIO_DCTRL_DTEN;
    " K# t0 P( v0 ^6 v5 E
  425.         
    : F( V' R9 {% M/ N. W
  426.         SDIO->ICR = SDIO_STA_DATAEND | SDIO_ICR_CMDRENDC;
    + b- @2 U7 o' m7 ~# A
  427.         if (flags & CMD53_BLOCKMODE)1 \/ j6 L% F- x) b
  428.                 SDIO->ICR = SDIO_ICR_DBCKENDC;6 h$ c6 L% e& g. Y" c
  429.         6 _6 Q5 Y, ^( f; U8 e" ^# j
  430.         // 通过判断SDIO->STA是否等于0可知传输是否成功: l( M8 E* T) M/ G  ^
  431. }# W3 {6 _) a2 q

  432. 6 ]+ I1 z" J/ B
  433. uint16_t WiFi_ReadPort(void *buf, uint16_t size, uint16_t bufsize)* p7 R3 _; V' y. R' b+ `" C
  434. {
    ; b8 S/ S9 g$ w; Q( F
  435.         uint16_t block_num, block_size;
    & m) z* S" J9 `8 x9 s
  436.         block_size = WiFi_GetBlockSize();; N1 Q5 C% ^1 o/ s; m5 |
  437.         4 I2 K7 `8 L% T$ o. G$ Z4 W+ O) z
  438.         // 读取数据$ C3 ^) V! G5 W" r0 G( Y
  439.         WiFi_Wait(0); // 发送CMD53前必须IOReady=1& E% E; G: i2 U( r! f
  440.         if (size >= 512 || size % block_size == 0)
    1 w( p" T' {1 {9 ?
  441.         {
    % z& I  b! |4 b7 U, i1 j
  442.                 // 采用Block模式传输
    ) f2 Y, R8 n# E" N% S2 \+ Q
  443.                 block_num = size / block_size;
    ! r/ m( w& I3 h8 k4 {! W- v& K( s
  444.                 if (size % block_size != 0)
    1 j2 W/ y; s  P0 f2 @5 D
  445.                         block_num++;' c8 T8 g; O# X% f  |
  446.                
    # x9 O) O# s1 G# i. J1 w4 A1 h( r9 i& i
  447.                 WiFi_ReadData(1, io_addr, buf, block_num, bufsize, CMD53_BLOCKMODE);
    ! P( U5 ^4 Z# h& [8 E' s
  448.         }& E; q* J# o5 s% a
  449.         else- C& D" v; B  ]5 |  i$ N7 C; A
  450.                 WiFi_ReadData(1, io_addr, buf, size, bufsize, 0);
    7 D6 @3 g& ?( e# ~& J; H- O
  451.         
    / d2 D2 q& g- [7 C
  452.         return SDIO->STA == 0;
    & [" _% D" R; z  \: l' k. P
  453. }1 P; h+ ^' X! R8 F6 Z& B( u

  454. % m2 R# m8 D% t1 I
  455. /* 接收数据帧 */- d  e% G* l' g3 u+ b
  456. uint16_t WiFi_ReceivePacket(void *buf, uint16_t bufsize)
    ; @' `& q- }8 ^
  457. {2 O# J, v* Z1 v0 |! ]- G3 Z
  458.         uint16_t size;
    5 p9 D2 X3 I3 @/ ]( Q. G6 U" l9 S% x
  459.         if (wifi_pending_size)8 @7 ^6 T! u4 X1 Z. Z/ G8 g2 \5 H% C
  460.         {
    7 e) i8 n" _" u  Z2 s& _
  461.                 size = wifi_pending_size; // 先读取滞留的数据包
    ) X) K& r- t# Q
  462.                 wifi_pending_size = 0;: x, i7 e/ |( ]5 F
  463.         }
    2 m3 V2 q9 H( T! _3 x1 V% @
  464.         else
    4 o2 y( k" W. x8 h5 Y( w  k
  465.                 size = WiFi_GetPacketLength();" ], \- a4 G% F2 t: Y7 W7 z) r
  466.         return WiFi_ReadPort(buf, size, bufsize);# h4 s0 t, j, t8 X* E7 b* c0 e' ~% l
  467. }
    - e9 ]% C) ^% ^1 I) h; P6 s! a

  468. % i+ d# A+ m$ j+ }* _0 p
  469. /* 接收WiFi命令的回应 */
    % j' w- o. |7 w; `3 V' y
  470. uint16_t WiFi_ReceiveResponse(void *buf, uint16_t bufsize)+ P( _: R' w' X" ]9 \
  471. {" o7 u4 j% l! R" u. u$ \0 g# k4 ]
  472.         uint8_t retry_cnt = 0; // 重试次数3 d- Z* A' x4 n; d/ P( D2 T
  473.         uint8_t wait_status, resend;
    1 J9 u4 s% S1 T9 d
  474.         uint16_t size;
    * N9 l5 B1 X% w/ A6 E) g$ E2 {
  475.         WiFi_CommandHeader *cmd = (WiFi_CommandHeader *)buf;3 l  }8 t* k, N0 a& z  Z
  476.         WiFi_SDIOFrameHeader temp;
      V& ^  j8 H3 f, I; U- A" F
  477.         
    / q4 V9 f" w0 q5 q8 Q2 G# H% u0 {0 C
  478.         // 等待数据准备好
    , }; L2 k9 y9 p, P; e* @
  479.         do+ \' a6 l1 F" {  d
  480.         {
    & J3 Z, |+ u1 Z9 M
  481.                 wait_status = WiFi_Wait(WIFI_CARDSTATUS_UPLDCARDRDY);$ O& M* Z- ^3 w' y0 Y# L9 C* A
  482.                 5 U9 }: f4 z. G5 @- j
  483.                 WiFi_ReadPort(&temp, sizeof(temp), sizeof(temp)); // 试着读取头部信息2 s0 G- p9 c. j2 v0 `
  484.                 if (temp.type == WIFI_SDIOFRAME_DATA && temp.length > 0) // 若读取到一个数据帧的头部
      }- @  {, J& D+ v6 B
  485.                 {9 `  t$ M+ P5 U5 V3 |* v( g1 K
  486.                         // 若读到的是一个数据帧, 不是命令回应
    ' X/ J. b6 D# J  }* }4 u
  487.                         // 则直接丢掉该数据帧, 然后重发命令, 保证命令执行成功
    1 S1 x% i# d8 i. }& T) D5 L5 v8 k; S
  488.                         printf("A packet of %d byte(s) preempted the command!\n", temp.length);
    . C; r, F# m+ |, Q! j8 Y
  489.                         wifi_pending_size = temp.length;
    ! X! v& @6 |; a( D- }* b
  490.                         WiFi_DropPacket(); // 必须读取完整个数据包, 只读完头部不算
    + V7 e  w# L8 ^5 `
  491.                         resend = 1;
    4 n* I" t$ e4 J
  492.                 }
    # R3 V6 ~; |* i) J6 o# n. b, U  X
  493.                 else if (wait_status == 0)
    ( p/ t3 Z$ H. p
  494.                 {$ l+ V! G$ ]8 ~% x+ `9 y6 k
  495.                         // 若WiFi_Wait返回0, 则说明超时 (状态位在规定的时间内未置位)5 }, B, c+ f1 b6 Z) R- C+ j
  496.                         resend = 1;4 \# J5 l! t6 O6 p: y+ `7 B1 Z
  497.                         retry_cnt++;  Z% _4 {8 P* V
  498.                         if (retry_cnt >= 5)
    0 K, p" t/ \4 v4 _( b
  499.                         {$ b4 R4 F1 g7 U: N
  500.                                 printf("No response!\n");
    % ~( U6 Y0 l1 o7 v
  501.                                 return 0;
    5 e: _  u) L- k5 k6 D' u
  502.                         }
      a) N& ~2 |: Q  R
  503.                 }" Z6 W# S0 n7 h5 p
  504.                 else
    * _  d$ `6 g' m8 F" L/ W- B
  505.                         resend = 0;
    ' \" h' @& s6 c6 b* b- E1 l6 a
  506.                 # g& @" Y1 Q7 t7 F: i9 L
  507.                 if (resend)
    5 n  W: p. m' n5 m2 j  D
  508.                 {+ a. k% q# R6 S" O* @2 T2 |
  509.                         if (cmd->frame_header.type == WIFI_SDIOFRAME_COMMAND)' w/ G& X4 ?; G6 l$ X- h# F
  510.                         {# i# G/ o* L& W
  511.                                 // 若超时后还没收到数据, 则重发命令, 然后再次执行WiFi_Wait  a: u2 h# `, R+ J+ x
  512.                                 printf("Resend WiFi command 0x%04x! size=%d\n", cmd->cmd_code, cmd->frame_header.length);3 r" ~: T+ r$ e' @7 P
  513.                                 WiFi_ResendCommand(buf);/ V& B% Y2 Q' ]/ t& [5 N. H" G& E
  514.                         }. z. M2 r. s/ J8 E, W+ C/ x, |
  515.                         else5 I) ?' @' z- B5 f' l
  516.                                 return 0; // 若buf中的内容不是命令, 则直接退出% t" n% W$ X, I- h6 U, @
  517.                 }: p! b) w9 T" y& l% Q. T" {
  518.         } while (resend);
    0 V- g$ S% k' N6 Q
  519.         ) p7 a/ a8 `0 @' A/ k& B
  520.         size = WiFi_GetPacketLength();' V; [" x6 ]% L% L
  521.         if (size > bufsize); W2 l3 r! [, R
  522.                 printf("WiFi_ReceiveResponse: Buffer size is too small! %d bytes required!\n", size);+ `( j- M6 f" b/ u/ X) r  O
  523.         return WiFi_ReadPort(buf, size, bufsize);9 D9 m) n( U' ~' D8 K
  524. }
    / r, @0 i7 A/ m6 f. x) v# _

  525. " U% X- N! g8 R0 O' e; u
  526. /* 扫描全部热点 (仅显示) */
    3 Z- L6 G; r2 p5 ~0 k" k3 O) M7 e
  527. void WiFi_Scan(void)
    : f/ m7 V) K9 R% u* D8 a$ {
  528. {
    + r; E( v4 k4 Q# O- s- W. H- K
  529.         // 必须把STM32启动文件*.s中的Stack_Size改大, 否则函数中无法创建大数组
    " O( v; b. g: x6 p6 S& O/ D* I
  530.         // Stack_Size=0x00000c00& Z' k+ `+ s; {6 S4 W$ Y
  531.         uint8_t buffer[2048]; // 用于接收返回的WiFi接入点信息, 需要较大的内存空间来存放8 j7 U) j: Y8 J5 @  a: U% Z
  532.         uint8_t i, j, n;
    : ?5 S' z; U: N* c
  533.         uint8_t ssid[33], channel, wpa;
    ) H5 T" B9 |6 k) l
  534.         uint16_t ie_size;
    0 c$ @! Y6 F7 X% F9 S/ C/ _* a
  535.         
    1 q1 o$ B7 [# Z& S1 ^- \
  536.         WiFi_CmdRequest_Scan *cmd = (WiFi_CmdRequest_Scan *)buffer; // 用buffer空间来存放要发送的命令
    6 Q' k; |) j9 e
  537.         MrvlIETypes_ChanListParamSet_t *chanlist = (MrvlIETypes_ChanListParamSet_t *)(buffer + sizeof(WiFi_CmdRequest_Scan));; _' [2 v1 j* R7 _! M9 a
  538.         
    ( C# {  `5 m$ a" }
  539.         WiFi_CmdResponse_Scan *resp = (WiFi_CmdResponse_Scan *)buffer;
    - q$ Y( A3 d0 n( z; n1 \5 ^
  540.         WiFi_BssDescSet *bss_desc_set;
    # f, a  A; u2 j& i* Z
  541.         WiFi_VendorHeader *vendor;
    + P! l: g7 H  L" g
  542.         IEEEType *ie_params;) Q+ d: g' y6 B* b2 W$ y
  543.         //MrvlIETypes_TsfTimestamp_t *tft_table;
    $ I" _. q6 B) V  o3 i
  544.         
    % E: |) M( B9 r# T/ T
  545.         // 分4次扫描14个通道( H! v4 I* P; Q. x& _
  546.         for (i = 0; i < 4; i++)
    ! \$ E3 }# C! J) n0 I1 R2 t
  547.         {. {( j+ c; ]  n' G& b
  548.                 cmd->bss_type = BSS_ANY;
    " U- P3 a5 R; c; f* U
  549.                 memset(cmd->bss_id, 0, sizeof(cmd->bss_id));- Y) Q; ?& t7 g+ A" U! j7 a
  550.                 / e4 I4 g8 p5 l
  551.                 // 通道的基本参数
    * {# i  R# }/ ^! N  V
  552.                 n = (i == 3) ? 2 : 4; // 本次要扫描的通道数
    7 M2 X7 z  |1 s' J4 D8 U, ~
  553.                 chanlist->header.type = MRVLIETYPES_CHANLISTPARAMSET;
    3 d$ e( u5 c* e/ Q  u; U7 v
  554.                 chanlist->header.length = n * sizeof(chanlist->channels);. m. e( s6 X+ t/ V5 o) R( [$ s
  555.                 for (j = 0; j < n; j++)* }* a' a3 o" A5 P0 v# X/ ?" R6 S
  556.                 {
    " l& Z# `, _8 H( h
  557.                         chanlist->channels[j].band_config_type = 0;
    2 J+ r8 |# i  J$ {
  558.                         chanlist->channels[j].chan_number = 4 * i + j + 1; // 通道号
    ' ~7 C6 v* X5 `. B+ P1 s) k9 S
  559.                         chanlist->channels[j].scan_type = 0;5 ^+ B) Z5 H+ ~0 V+ r
  560.                         chanlist->channels[j].min_scan_time = 0;
    6 E! I( N# |1 w8 C$ ^7 g9 z
  561.                         chanlist->channels[j].max_scan_time = 100;
    . N$ \4 q  n  p- F2 Y: S
  562.                 }+ z) ?) v6 }9 E3 y9 r$ j7 A) `% f2 o
  563.                 " ?' \, q: R4 A9 x
  564.                 // 发送命令并接收数据
    % Q9 \0 a7 t, R) t8 L* q) z. u
  565.                 WiFi_SendCommand(CMD_802_11_SCAN, buffer, sizeof(WiFi_CmdRequest_Scan) + sizeof(chanlist->header) + chanlist->header.length);( l8 {3 k, I! l2 A7 u% [6 d
  566.                 WiFi_ReceiveResponse(buffer, sizeof(buffer)); // 接收的数据会将cmd和chanlist中的内容覆盖掉
    3 ]0 z, s0 G( `5 ^$ h# L! H
  567.                
    9 n. R  {. Y2 ]$ w- v
  568.                 // 显示热点信息, num_of_set为热点数
    $ D7 Z8 _9 D0 ~: e, R
  569.                 if (resp->num_of_set > 0)
    ; p. ]; [* ~7 s" Z* A+ t: s- k
  570.                 {
    ; o- n. s9 X  K3 j  O3 H2 F6 @
  571.                         bss_desc_set = (WiFi_BssDescSet *)(buffer + sizeof(WiFi_CmdResponse_Scan));
    ! i6 c; m* R' G* d: v7 |
  572.                         for (j = 0; j < resp->num_of_set; j++)' ^7 m2 @7 J, y
  573.                         {
    1 \9 i% h) p9 t1 V, e! a1 s
  574.                                 wpa = 0;
    / ]/ G/ l* T/ f' k* w0 o9 J* S# v
  575.                                 ie_params = &bss_desc_set->ie_parameters;
    # B0 ~0 B2 R% n. a2 `& A; E
  576.                                 ie_size = bss_desc_set->ie_length - (sizeof(WiFi_BssDescSet) - sizeof(bss_desc_set->ie_length) - sizeof(bss_desc_set->ie_parameters));" O3 a8 G* W# a2 o( I$ q
  577.                                 while (ie_size > 0)
    * d, S* R6 E  n- Q. ~
  578.                                 {
    * X" O4 k# |6 q+ M3 u7 b
  579.                                         switch (ie_params->type)8 ]9 E: e6 x9 \3 y
  580.                                         {
    2 G; m! k* P7 Z. w$ {- z0 _5 a
  581.                                         case MRVLIETYPES_SSIDPARAMSET:1 v  k) O0 L& t; w, m
  582.                                                 // SSID名称
    : F4 l# Y4 Q0 l/ O4 X
  583.                                                 memcpy(ssid, ie_params->data, ie_params->length);, R/ _8 P: {& {1 i$ N
  584.                                                 ssid[ie_params->length] = '\0';5 t6 n4 e  J* ]7 B7 r  \1 E% Z  ?
  585.                                                 break;
    ! j+ F* y/ z) q7 `% s! n
  586.                                         case MRVLIETYPES_DSPARAMSET:
    * c2 c* }) m* T$ e9 a
  587.                                                 // 通道号
    ( p+ e4 q; w  J: G
  588.                                                 channel = ie_params->data[0];9 x: _1 d7 R. b5 R+ I6 v
  589.                                                 break;1 j. r9 k! g# b
  590.                                         case MRVLIETYPES_RSNPARAMSET:+ j; B) P+ D0 e
  591.                                                 wpa = 2;: s2 l3 S, D. T- h
  592.                                                 break;
    & K' L7 ^: c! C
  593.                                         case MRVLIETYPES_VENDORPARAMSET:1 l% e6 p$ e4 a: Y# L
  594.                                                 if (wpa == 0)5 L0 v( e7 f- M+ Z( a6 ?8 s2 @
  595.                                                 {: D9 R1 p; U* L
  596.                                                         vendor = (WiFi_VendorHeader *)ie_params->data;) C; ^) a& a6 ?8 u! X
  597.                                                         if (vendor->oui[0] == 0x00 && vendor->oui[1] == 0x50 && vendor->oui[2] == 0xf2 && vendor->oui_type == 0x01)) r  P2 Q8 B0 G) G
  598.                                                                 wpa = 1;
    . q: b8 e$ a9 W" G$ M
  599.                                                 }
    1 b6 J" G/ N& f, z# U5 O
  600.                                                 break;( I) Q) T. l* `* P
  601.                                         }. z4 D6 W' ~4 E9 c; |3 |
  602.                                         ie_size -= ie_params->length + 2;" J# X" J# U( E# ^8 f) d: {  `
  603.                                         ie_params = (IEEEType *)((uint8_t *)ie_params + ie_params->length + 2);
    $ c5 e+ C# X, ^$ V' f
  604.                                 }
    / o% E8 l" X: H- @6 d
  605.                                 if (ie_size != 0)  b2 Z0 {. i% U7 B3 A5 z9 X( L* Y. Q
  606.                                         printf("ie_parameters error!\n");
    / W# p$ @" j( z# O! L
  607.                                 - J" E* f5 X4 R
  608.                                 printf("SSID '%s', ", ssid); // 热点名称2 c2 ?$ {/ ~- [6 M: R
  609.                                 printf("MAC %02X:%02X:%02X:%02X:%02X:%02X, ", bss_desc_set->bssid[0], bss_desc_set->bssid[1], bss_desc_set->bssid[2], bss_desc_set->bssid[3], bss_desc_set->bssid[4], bss_desc_set->bssid[5]); // MAC地址
    & h5 d5 u# t5 Y0 B4 S& j
  610.                                 printf("RSSI %d, Channel %d\n", bss_desc_set->rssi, channel); // 信号强度和通道号: f- T9 _1 j! C( n+ \* O
  611.                                 //printf("  Timestamp %lld, Beacon interval %d\n", bss_desc_set->pkt_time_stamp, bss_desc_set->bcn_interval);9 O1 v; n6 b$ w, V( m$ q# }# L, R
  612.                                 3 r' v2 }4 l. }  y) \( e( u
  613.                                 printf("  Capability: 0x%04x", bss_desc_set->cap_info);
    , y' p5 V0 M% G8 ^. N. a) N
  614.                                 if (bss_desc_set->cap_info & WIFI_CAPABILITY_PRIVACY); H+ j# S0 C1 I7 Q+ [
  615.                                 {' \+ h# G! {7 Q/ |: z. V
  616.                                         if (wpa == 1)3 c- V% e" c$ C# U: b
  617.                                                 printf("(WPA: ON, ");
    " [7 ^  d( O) Z9 S4 t
  618.                                         else if (wpa == 2)
    3 h3 ?8 f/ w- F' j4 W/ G
  619.                                                 printf("(WPA2: ON, ");3 w: a: n- p1 D- b
  620.                                         else5 ?; u# a7 ~% e# ?& ]- p/ `; s
  621.                                                 printf("(WEP: ON, ");1 T. w8 h0 ^' i: H/ z6 ^8 o
  622.                                 }$ P1 l- h. |8 z# D9 h
  623.                                 else0 s4 M1 p5 |8 e( h- S. h6 j
  624.                                         printf("(WEP: OFF, ");# f. o! u) N+ P8 d# V8 b: S
  625.                                 , x% H8 E6 Z. M1 U: \+ v: p7 d
  626.                                 if (bss_desc_set->cap_info & WIFI_CAPABILITY_IBSS)) x0 u* m, }  j" F; y8 Z
  627.                                         printf("mode: Ad-Hoc)\n");
    / {( R1 c( K. V# \+ K) l
  628.                                 else
    9 I/ B1 N4 y. D! s# i4 d
  629.                                         printf("mode: Infrastructure)\n");0 P* E2 L% k4 a) T" I4 X) l
  630.                                 & D/ E& P( N/ j5 Q6 r
  631.                                 // 转向下一个热点信息/ T9 w( R' d. M
  632.                                 bss_desc_set = (WiFi_BssDescSet *)((uint8_t *)bss_desc_set + sizeof(bss_desc_set->ie_length) + bss_desc_set->ie_length);5 ~; E4 q+ v( g' Q2 k
  633.                         }# R) P$ e* J- _/ f2 Z- B
  634.                         
    / K7 H- B; [( r7 Q6 c7 Q$ V  Z
  635.                         // resp->buf_size就是bss_desc_set的总大小
    * L% g5 A3 Y. E' T# }( `# ?- ^
  636.                         // 因此tft_table == buffer + sizeof(WiFi_CmdResponse_Scan) + resp->buf_size/ e5 s7 H& u5 D9 f+ o+ y. s
  637.                         /*tft_table = (MrvlIETypes_TsfTimestamp_t *)bss_desc_set;
    ) T) A( j2 j2 C# n7 Q
  638.                         if (tft_table->header.type == MRVLIETYPES_TSFTIMESTAMP && tft_table->header.length == resp->num_of_set * sizeof(uint64_t))% y  r; D: _: F2 b
  639.                         {
    / j7 e* U$ a# c. P( s; n
  640.                                 printf("Timestamps: ");5 J( e. j+ W$ X- _
  641.                                 for (j = 0; j < resp->num_of_set; j++)
    5 M- O/ G! f) z( N9 O! g5 G
  642.                                         printf("%lld ", tft_table->tsf_table[j]);
    1 a1 I! Q. i5 Q; t  T$ j
  643.                                 printf("\n");
    # a7 Q' ?/ n$ C4 m+ O& R
  644.                         }*/8 t7 W( f* l7 p
  645.                         4 j4 I* |8 r7 s/ q
  646.                         // TSF timestamp table是整个数据的末尾, 后面没有Channel/band table
    ) l4 D  g# ~3 B5 g4 {
  647.                         //if (((uint8_t *)tft_table - buffer) + sizeof(tft_table->header) + resp->num_of_set * sizeof(uint64_t) == cmd->header.frame_header.length)3 ?7 R2 w& T" f
  648.                         //        printf("data end!\n");
    6 p8 O5 |% E+ `! h
  649.                 }
    3 b& r  \' T2 D# g4 Q# |2 g
  650.         }
    7 h& w1 l0 v5 Q" v3 _5 b
  651. }4 d; F6 Q' d3 N

  652.   `8 M% i- L3 p  \$ {9 ~( ?( V
  653. /* 扫描指定名称的热点 */( g; g7 v! A% [; I: ~
  654. // buffer用来存放返回的全部结果, 因此bufsize应该足够大4 ], c- k/ \. q3 G9 c
  655. // info用来存放从buffer中提取出来的一些常用信息# D3 @# F8 x8 _$ B% U$ p
  656. uint8_t WiFi_ScanSSID(const char *ssid, WiFi_SSIDInfo *info, uint8_t *buffer, uint16_t bufsize)) {* S& o2 K& ]; u8 B* w) a
  657. {0 J( m) h5 c- A7 L3 ~" d8 l
  658.         uint8_t i;/ |- _/ B7 w7 n& S$ {! e% O
  659.         uint16_t ie_size;
    + ~, u! l& f9 \! Q% q' f
  660.         WiFi_CmdRequest_Scan *cmd = (WiFi_CmdRequest_Scan *)buffer;. o2 u& t' w$ @3 U. Y
  661.         WiFi_CmdResponse_Scan *resp = (WiFi_CmdResponse_Scan *)buffer;1 [7 t$ L9 u  j' L7 U1 _) l
  662.         WiFi_BssDescSet *bss_desc_set = (WiFi_BssDescSet *)(resp + 1);; q$ t/ |3 |" _0 d! K, C- B
  663.         MrvlIETypes_ChanListParamSet_t *chan_list;1 {0 W) {% p' D1 e
  664.         IEEEType *ie_params;
    # F- w; m- c' u% g) L6 O
  665.         WiFi_VendorHeader *vendor;' L, v! s! v) r, I
  666.         0 q% {* l8 a# J! Q# m. z- w
  667.         cmd->bss_type = BSS_ANY;# ^1 n! a8 I9 m
  668.         memset(cmd->bss_id, 0, sizeof(cmd->bss_id));" }& ^! B4 C) t7 r2 M% ?: z
  669.         * @" W0 }. O; N) b& }
  670.         // 添加ssid参数& p8 Y3 r* n1 w  P2 t* x& i
  671.         info->ssid.header.type = MRVLIETYPES_SSIDPARAMSET;) ?7 b: J/ H$ V: x
  672.         info->ssid.header.length = strlen(ssid);
    5 |$ q6 H5 b) u0 o! A  l* I
  673.         memcpy(info->ssid.ssid, ssid, info->ssid.header.length);; l; j4 a+ z1 |% I4 i7 M
  674.         memcpy(cmd + 1, &info->ssid, MRVLIE_STRUCTLEN(info->ssid));0 _; P8 m4 I+ v" C7 r6 m$ p6 u
  675.         
    8 R8 ]3 E3 l9 E% j' X: Z
  676.         chan_list = (MrvlIETypes_ChanListParamSet_t *)((uint8_t *)(cmd + 1) + MRVLIE_STRUCTLEN(info->ssid));
    # K( D* W) R" |- x+ v- I3 Q, G
  677.         chan_list->header.type = MRVLIETYPES_CHANLISTPARAMSET;5 z5 }5 b  A. n$ m% S
  678.         chan_list->header.length = 14 * sizeof(chan_list->channels); // 一次性扫描14个通道$ ]. l/ Q( C$ I
  679.         for (i = 0; i < 14; i++)
    ( q5 N; s- `+ l/ g' L; O  M
  680.         {
    1 b" J2 N. z2 T4 P
  681.                 chan_list->channels[i].band_config_type = 0;
    : T# w( E# t$ m& v
  682.                 chan_list->channels[i].chan_number = i + 1;0 |2 K7 s; m1 Q/ z4 K# u
  683.                 chan_list->channels[i].scan_type = 0;7 K( N( ?7 T/ n8 t" Z: X  U
  684.                 chan_list->channels[i].min_scan_time = 0;
    + s2 g2 e( j+ U& f/ @# m9 ?, A
  685.                 chan_list->channels[i].max_scan_time = 100;0 R. z# ?# X% e! J  m+ D  t  H
  686.         }% [0 @8 N$ v- j5 o1 P
  687.         
    8 T) x$ r; J4 u# {
  688.         WiFi_SendCommand(CMD_802_11_SCAN, buffer, ((uint8_t *)chan_list - buffer) + MRVLIE_STRUCTLEN(*chan_list));1 {8 n2 X1 B: U. K
  689.         wifi_timeout = 3000; // 延长超时时间
    - i" M) \. }, P+ F# `$ }
  690.         WiFi_ReceiveResponse(buffer, bufsize);1 Y8 s2 l& T% ]. _
  691.         wifi_timeout = WIFI_DEFAULTTIMEOUT;. e; m1 Y' v# U2 T( S
  692.         ) A( t! O3 l: q: c- d
  693.         if (resp->num_of_set == 0)
    8 }- P- t& E& I, o: J5 Y4 Z7 `% q) l) B
  694.                 return 0; // 失败
    - }  ~; Y. m3 }) o
  695.         . v2 `5 _; m# ~- M1 }; Q$ @
  696.         // bss_desc_set以扫描到的第一个信息项为准
    . ^/ N1 B8 V, i1 \/ x
  697.         memcpy(info->mac_addr, bss_desc_set->bssid, sizeof(info->mac_addr));
    * m1 e+ |/ ~2 A! W& j- w
  698.         info->cap_info = bss_desc_set->cap_info;  C" G9 E1 @$ g9 K) U
  699.         info->bcn_period = bss_desc_set->bcn_interval;
    3 E5 ?+ z+ b7 W  f, y  a
  700.         
    1 O" M- y: N( ^" V
  701.         // 若type=0, 则表明没有该项的信息 (除SSID结构体外, 因为SSID的type=MRVLIETYPES_SSIDPARAMSET=0)
    8 {7 a  B; w& p( C9 g9 r
  702.         info->rates.header.type = 0;& G% }5 t4 A6 U* Y) Y4 @
  703.         info->rsn.header.type = 0;& g" w; ?* {( J) L) |, a' K+ \
  704.         info->wpa.header.type = 0;$ D5 c0 w$ M' u+ R2 t; \' S
  705.         info->wwm.header.type = 0;* \) I! k, l8 e9 l/ z1 H5 x6 Q
  706.         info->wps.header.type = 0;5 ^' R! ?) T( `
  707.         3 m4 W9 O0 c% n$ Q; F4 u  r
  708.         ie_params = &bss_desc_set->ie_parameters;3 x+ C# t6 F& H5 l) s% w+ Y" b
  709.         ie_size = bss_desc_set->ie_length - (sizeof(WiFi_BssDescSet) - sizeof(bss_desc_set->ie_length) - sizeof(bss_desc_set->ie_parameters));: D$ k4 d  U6 k+ z
  710.         while (ie_size > 0)
    ' u( U4 j) i1 l& J( H
  711.         {; ~0 C: H% ~0 i2 O- e, Z
  712.                 switch (ie_params->type); t7 r3 g# R2 ~3 g8 b* y' a
  713.                 {
    0 I5 I# z9 Y. ^8 l) Y
  714.                 case MRVLIETYPES_RATESPARAMSET:3 P7 y- u! z4 i* B. B" g9 U" |
  715.                         // 速率. D) H4 k+ n+ ]
  716.                         info->rates.header.type = MRVLIETYPES_RATESPARAMSET;2 S6 t/ [  ^; o1 t: I& C# m8 c& O+ ]% Q
  717.                         info->rates.header.length = ie_params->length;2 z  U) x# G% _
  718.                         if (info->rates.header.length > sizeof(info->rates.rates))# l# I; U: G4 z& X3 A, ]7 B  W
  719.                                 info->rates.header.length = sizeof(info->rates.rates);
    0 p$ @: H- ?. h: T
  720.                         memcpy(info->rates.rates, ie_params->data, ie_params->length);
    : a7 i1 u/ ^2 ^" M8 K
  721.                         break;
    ) J0 d9 L* d) _8 \- N% s
  722.                 case MRVLIETYPES_DSPARAMSET:
    " v6 b. y- Q" N( i  K( r% J  ~# G# ~
  723.                         // 通道号8 M, h7 v' T# D5 j4 t- Y
  724.                         info->channel = ie_params->data[0];  j1 R6 c7 L8 E, H- i( ~% M1 m4 S
  725.                         break;
    3 d7 ^0 n5 \  N: w$ J
  726.                 case MRVLIETYPES_RSNPARAMSET:7 O/ ^8 U3 b4 s, d) e6 v  }2 A
  727.                         // 通常只有一个RSN信息 (与WPA2相关)
    6 L2 p* @' m2 J0 N4 v* v% U
  728.                         // printf("RSN len=%d\n", ie_params->length);
    ) t6 G, r6 ?7 y# V7 |* G& b
  729.                         info->rsn.header.type = MRVLIETYPES_RSNPARAMSET;
    ' ]2 q) M: n9 |
  730.                         info->rsn.header.length = ie_params->length;
    2 T: ^& \' s) g% ]! t/ V
  731.                         if (info->rsn.header.length > sizeof(info->rsn.rsn))' n1 T* K4 E3 |  l
  732.                                 info->rsn.header.length = sizeof(info->rsn.rsn);+ S" `" S0 m- C; v  _* b
  733.                         memcpy(info->rsn.rsn, ie_params->data, info->rsn.header.length);
    ! b0 U3 I6 H: b; C: H
  734.                         break;
    * T8 D" U0 D+ H7 }: t; O
  735.                 case MRVLIETYPES_VENDORPARAMSET:
    6 f+ G! c5 n# H7 `& U" s
  736.                         // 通常会有多项VENDOR信息 (与WPA相关)+ m3 s. o) Z/ t! e7 j
  737.                         vendor = (WiFi_VendorHeader *)ie_params->data;6 {3 l( G, S) H
  738.                         if (vendor->oui[0] == 0x00 && vendor->oui[1] == 0x50 && vendor->oui[2] == 0xf2)
    4 j8 p( p& g: \4 r4 W/ i" [
  739.                         {0 d8 w& \9 Z, O: i6 b2 C' B* ]
  740.                                 switch (vendor->oui_type)
    5 ~; C. J/ d0 X  [, y" v8 R4 z
  741.                                 {
    - O6 ~6 j: l1 g8 U- g  T
  742.                                 case 0x01:
    4 B* O) m: X7 H( W6 V( G3 F0 A
  743.                                         // wpa_oui
    4 |! B1 i3 ?$ `6 H, H  S& T
  744.                                         info->wpa.header.type = MRVLIETYPES_VENDORPARAMSET;
    ! r7 e2 H: Z" t7 R
  745.                                         info->wpa.header.length = ie_params->length;
    7 G( s( K/ L. @; b4 T3 E
  746.                                         if (info->wpa.header.length > sizeof(info->wpa.vendor))0 h0 W6 {4 ~7 R2 _( g
  747.                                                 info->wpa.header.length = sizeof(info->wpa.vendor);7 p( {; K  F6 k# b) d1 R
  748.                                         memcpy(info->wpa.vendor, ie_params->data, info->wpa.header.length);
    " k* l4 I' k) q& p  J6 Q
  749.                                         break;- Y0 Z( B5 \1 z
  750.                                 case 0x02:
    - D# k  v5 f* l2 ^
  751.                                         // wmm_oui
    ; L# b; _3 O" x0 |
  752.                                         if (ie_params->length == 24) // 合法大小
    , R" @( x. X% n5 p  c( ]6 e7 F0 r& Z0 d
  753.                                         {
      [& y# c0 N5 G5 U
  754.                                                 info->wwm.header.type = MRVLIETYPES_VENDORPARAMSET;
    : V; \, L( I& `0 T
  755.                                                 info->wwm.header.length = ie_params->length;
    8 P: D5 Q% D& V3 [7 x5 V6 ]
  756.                                                 memcpy(info->wwm.vendor, ie_params->data, ie_params->length);# p! }2 j, ?" h% U, R7 r
  757.                                         }/ P: z5 ]+ H9 m; {
  758.                                         break;
    4 ]8 e, z" S+ @
  759.                                 case 0x04:$ K! v  o* \' y) j: Z# {; F9 l$ d
  760.                                         // wps_oui4 s! d: }: L5 }  I# h1 G
  761.                                         info->wps.header.type = MRVLIETYPES_VENDORPARAMSET;
    ( y' I3 c' V) @4 |* z
  762.                                         info->wps.header.length = ie_params->length;9 V* P1 M- p/ F7 h4 w3 E
  763.                                         if (info->wps.header.length > sizeof(info->wps.vendor))
    ! H+ r2 N- M4 k" U( Z& k
  764.                                                 info->wps.header.length = sizeof(info->wps.vendor);
    ! A, x* j9 o/ a4 A" X! m
  765.                                         memcpy(info->wps.vendor, ie_params->data, info->wps.header.length);
    . |7 U0 U/ h, `/ c
  766.                                         break;3 G5 Y. [. R; R& m, n6 \  ^) J, g
  767.                                 }# D' a3 E! v6 e3 M, u6 S, g
  768.                         }1 v7 |1 T7 J# P
  769.                         break;
    * o' d' B9 `2 T: j
  770.                 }
    + ^% B9 {! N3 _$ n
  771.                 ie_size -= ie_params->length + 2;! E4 l" M5 y$ o4 N" O4 j
  772.                 ie_params = (IEEEType *)((uint8_t *)ie_params + ie_params->length + 2);" K; \& |( l5 m) f5 T$ q2 P( t
  773.         }
    8 G& t& e' u. P, r. Q: \
  774.         
    / v4 t, h9 o  @# F- F' \
  775.         return 1; // 成功. `$ n' p# w9 V# ]1 j- B! v
  776. }
    . C9 x/ ~' B1 @* a  @# M5 k
  777.   C# G( ~; x- P$ M, J
  778. void WiFi_SendCMD52(uint8_t func, uint32_t addr, uint8_t data, uint32_t flags)& O' @+ l& [5 u8 K
  779. {: A: h1 n! R3 t
  780.         SDIO->ARG = (func << 28) | (addr << 9) | data | flags;
    / |3 k2 ~/ R* {) Z7 R$ l
  781.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 52;
    # g, z+ l% Z1 T9 F7 t
  782.         while (SDIO->STA & SDIO_STA_CMDACT);
    # m" [; Q- c3 z' v7 J
  783. }+ t/ Q: X# G- Y" H
  784. ( e$ S% R! \4 n- b+ b
  785. void WiFi_SendCMD53(uint8_t func, uint32_t addr, uint16_t count, uint32_t flags): m# e2 q/ ?6 Y, A2 C! `
  786. {5 H# R5 n% q% L: Q
  787.         // 当count=512时, 和0x1ff相与后为0, 符合要求. O3 I6 g2 K. Y, F
  788.         SDIO->ARG = (func << 28) | (addr << 9) | (count & 0x1ff) | flags;* L- p: W5 y( x4 n$ p1 d+ }
  789.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 53;3 i2 s5 U5 p* M6 z5 G+ X
  790. }7 k" Q0 |3 V$ N

  791. $ j! \, T: B. d  a, k
  792. /* 发送WiFi命令 */
    0 s, z5 V. ]$ b/ z, b
  793. void WiFi_SendCommand(uint16_t com_code, void *data, uint16_t size)* r7 Q( `7 \! f# a
  794. {; e) J$ D$ P% @* V5 T
  795.         static uint16_t seq_num = 0;
    8 c' x, t  @& Q# o+ m# ]
  796.         WiFi_CommandHeader *cmdhdr = (WiFi_CommandHeader *)data;' n4 y) k% _! G0 s" n2 Q9 y
  797.         
    : Q: j1 K& |8 V5 v' u
  798.         if (size != 0)+ r$ s, z5 p+ G6 f  ^& z
  799.         {
    $ O2 W! O- Z1 k6 X
  800.                 cmdhdr->frame_header.length = size;& M. n; p7 j4 [" q: g: f/ s
  801.                 cmdhdr->frame_header.type = WIFI_SDIOFRAME_COMMAND;
      a) d3 W# o' W* q% r4 S- _0 ~
  802.                 cmdhdr->cmd_code = com_code;
    1 b, L0 ]. O6 m( g, U
  803.                 cmdhdr->size = size - sizeof(WiFi_SDIOFrameHeader); // 命令大小包括命令头部, 但不包括SDIO帧头部
    " l0 n9 a6 o! \/ P/ T
  804.                 cmdhdr->seq_num = seq_num++;
    1 G! T" A7 T5 |8 B+ Q
  805.                 cmdhdr->result = 0;
    * I# s& |% k5 c8 s; t- O
  806.         }
    9 m* ?0 j% T5 k  z1 [
  807.         else- w& E* a% z6 Y9 ?% `& b# _
  808.                 size = cmdhdr->frame_header.length; // 重发命令时不填写cmdhdr7 S! Y$ y, T# [# b8 A
  809.         
    8 t8 l/ Q7 G7 b/ i- J/ ?3 p3 K5 \
  810.         // 发送命令前若恰好有数据帧到来, 则直接丢弃
    6 i$ o1 G, ~$ ^/ K) K; q+ |
  811.         if (WiFi_PacketPending() || WiFi_PacketArrived())
    1 g8 ?6 R0 K, I
  812.         {
    3 ?7 a; ^: u( H: o0 H! C
  813.                 printf("A new packet happends to arrive when sending command! Drop it!\n");
    / c0 I( j- @" F2 @- _
  814.                 WiFi_DropPacket();0 b) X3 I% l2 G; m+ ~2 ^7 ^# ^
  815.         }
    - E% Q4 C8 \$ \: A/ V6 Z3 o
  816.         
    5 ]8 s2 q9 }9 |; z& G! e( F
  817.         WiFi_WritePort(data, size);
    8 b- ?7 K% z/ V/ L9 }2 D
  818. }
    ' g' [. N/ h) W& W
  819.   ?: e% F) u4 V! x+ L
  820. /* 发送数据帧 */
    : [2 V$ V4 ~: M1 Q8 u
  821. uint8_t WiFi_SendPacket(WiFi_DataTx *packet, uint16_t packet_len)
    1 J! ?4 C% d% K. j- x0 h( {9 Y
  822. {* p. g5 i1 L( s- x  B6 {3 f
  823.         uint8_t ret;# e2 E" f+ S* ^8 Z& A# a
  824.         1 T  E3 B4 r6 b- I6 t6 R
  825.         // 有关发送数据包的细节, 请参考Firmware Specification PDF的Chapter 3: Data Path' _& P( m" e- \( d1 T5 }3 v' ]9 T& u
  826.         packet->header.length = sizeof(WiFi_DataTx) - sizeof(packet->payload) + packet_len;' {. X+ O8 G; J* W! [
  827.         packet->header.type = WIFI_SDIOFRAME_DATA;
    " h( o7 t& P& M9 |: s* h0 Y% }  L& Y
  828.         0 O. f; s$ D* |
  829.         packet->reserved1 = 0;
    2 z  I3 {! x5 I( E/ ~' Y* A8 @
  830.         packet->tx_control = 0; // 控制信息的格式请参考3.2.1 Per-Packet Settings
    ) I1 ?* U8 b6 ]$ U6 }+ [& ?( G3 R
  831.         packet->tx_packet_offset = sizeof(WiFi_DataTx) - sizeof(packet->payload) - sizeof(packet->header); // 不包括SDIOFrameHeader1 n9 C9 T* m! Z9 k
  832.         packet->tx_packet_length = packet_len;
    $ A& V, S5 Y3 t  g
  833.         memcpy((void *)&packet->tx_dest_addr_high, packet->payload, 6);2 B, L  k! k$ g; \! H% c; g7 K
  834.         packet->priority = 0;4 i" K- }7 c8 m( w2 r8 G5 E; y
  835.         packet->flags = 0;
    $ x3 H5 W5 |$ x4 k# |8 E
  836.         packet->pkt_delay_2ms = 0;" f8 `$ j# M9 E$ m* D
  837.         packet->reserved2 = 0;( ~  p% l  J) h/ u
  838.         3 y7 `/ |8 O+ P% B9 G
  839.         // 若现在有新收到的数据帧, 则暂存数据包大小
    8 g" q0 P4 J- ?
  840.         // 未读取之前不会收到新的数据帧/ W9 ~5 t# R0 H$ C4 b  T2 t
  841.         if (WiFi_PacketArrived())
    0 `4 H1 N/ f0 W) o* U' |1 U$ z: ]
  842.                 wifi_pending_size = WiFi_GetPacketLength();; {; ^5 H% M* K& ^: v$ k
  843.         4 G  P8 Y- [; N
  844.         ret = WiFi_WritePort(packet, packet->header.length);/ \; Z4 `0 q" j1 z" R
  845.         WiFi_Wait(WIFI_CARDSTATUS_DNLDCARDRDY); // WiFi模块收到数据后, 会将该位置1
    3 M  t" I0 Q3 M; T
  846.         return ret;0 |5 W4 }, h" J9 o& i" ~0 Q
  847. }5 k% H- g9 @# t6 L& ~

  848. # g( `3 E6 Z% J
  849. /* 将SDIO->DCTRL中的块大小信息应用到WiFi模块指定的功能区上 */
    8 P* R: s/ c2 L6 O1 m% M4 h% i4 u, S
  850. void WiFi_SetBlockSize(uint8_t func)
    ! s5 ^2 ]; J- F9 O/ A- c% {9 P
  851. {
    ! W5 S) S6 M" n( Q- t$ v; S% Z7 Z
  852.         // Part E1: 6.9 Card Common Control Registers (CCCR), 6.10 Function Basic Registers (FBR)1 H) A! }* l: R8 c
  853.         uint16_t size = WiFi_GetBlockSize();
    " c- q; }& F5 r5 f# K
  854.         WiFi_Write(0, (func << 8) | 0x10, size & 0xff);# U8 B4 m6 A/ W" |1 q
  855.         WiFi_Write(0, (func << 8) | 0x11, size >> 8);1 p; y" P9 i4 |* A6 P8 X. J* x" E/ p
  856. }
    ( M3 g& p% |( z5 v- |, F2 T
  857. ; D1 s. q' p! @/ K( _7 x
  858. /* 设置密钥 */' |! B. c$ f3 X$ @; z$ o6 _
  859. uint8_t WiFi_SetKeyMaterial(uint16_t type, uint16_t info, const uint8_t *key, uint16_t len)- X- X& Y$ L; s# E  [5 W3 C  J$ Z* R
  860. {
    - z0 D, ]/ y3 }; h( R! x* o
  861.         MrvlIETypes_KeyParamSet_t key_param;
    " a0 W2 m% m+ i) x. K
  862.         if (len > sizeof(key_param.key))$ f4 k# X5 J# H
  863.                 return CMD_STATUS_ERROR;, ?5 Q7 ?6 Y' G0 A9 Q/ x
  864.         key_param.header.type = MRVLIETYPES_KEYPARAMSET;
    3 q2 i+ v/ Y. z# ~" Z/ _# R
  865.         key_param.header.length = (key_param.key - (uint8_t *)&key_param) - sizeof(key_param.header) + len;& m+ I+ D, O( a/ t" M$ w2 X* h1 |
  866.         key_param.key_type_id = type;
      }4 }0 p& O7 e) J* z+ \
  867.         key_param.key_info = info;, ]) M1 A1 q& J8 P% s; V7 b2 f0 g
  868.         key_param.key_len = len; // 当len=0时可保留key的值, 只更新key_info
    ) [/ Q1 {  y/ e
  869.         if (len)
    . N2 S( @0 H- R' d$ e+ K
  870.                 memcpy(key_param.key, key, len);4 a# {0 d, L) U! L' `
  871.         return WiFi_KeyMaterial(&key_param, MRVLIE_STRUCTLEN(key_param), WIFI_ACT_SET);
    2 n- n1 x+ H. p* l9 U4 s
  872. }( R  y! e( U9 U

  873. ' C( h5 z4 b  [( F: r
  874. /* 显示WiFi模块信息 */
    3 M9 f; b2 {  Q8 h' o( k& f: z8 \
  875. void WiFi_ShowCIS(uint8_t func)
    : n" _! [2 z; _. F& [
  876. {
    ' ?: q* T' A2 B1 X3 _
  877.         uint8_t data[255];
    4 q3 }  t" n5 S# s# R. b: r
  878.         uint8_t i, len;  J8 Z$ b* R  n
  879.         uint8_t tpl_code, tpl_link; // 16.2 Basic Tuple Format and Tuple Chain Structure
    6 [( U6 H# Z; p
  880.         uint32_t cis_ptr;/ ]( g- m6 W# q, w
  881.         5 F' F+ Q- {- o4 T7 Z
  882.         // 获取CIS的地址5 L1 U3 j2 T8 z8 d( [
  883.         cis_ptr = (func << 8) | 0x9;1 e8 A4 I' K5 i1 `7 E. r0 z, H
  884.         cis_ptr        = WiFi_Read(0, cis_ptr) | (WiFi_Read(0, cis_ptr + 1) << 8) | (WiFi_Read(0, cis_ptr + 2) << 16);& O- J, x8 B4 s" N' k8 U
  885.         printf("Pointer to Function %d Card Information Structure (CIS): 0x%08x\n", func, cis_ptr);
    7 z4 k: e( K- `) g; C
  886.         7 A: r  P0 L4 q
  887.         // 遍历CIS, 直到尾节点7 n, A- c( L) h( c* [& A
  888.         while ((tpl_code = WiFi_Read(0, cis_ptr++)) != CISTPL_END)" x* M0 P- i* Q( ^! Q$ r0 z
  889.         {
    ' x; r! g6 v( a2 U  o, O6 ^% q
  890.                 if (tpl_code == CISTPL_NULL)
    $ O( m" d" e. }
  891.                         continue;  W+ V8 z9 E7 w7 u2 |, s/ ~& c/ C
  892.                
    , \) j9 q6 W6 n& p9 e0 I- t; w9 x
  893.                 tpl_link = WiFi_Read(0, cis_ptr++); // 本结点数据的大小" g; [7 x$ ~& K3 }, F" Z; W0 |
  894.                 for (i = 0; i < tpl_link; i++)9 h# X1 O( O: T3 \7 A* T
  895.                         data[i] = WiFi_Read(0, cis_ptr + i);1 i& z/ k7 h0 p
  896.                 8 @2 Z( h4 k4 Q$ u9 u5 Y( a4 i
  897.                 printf("[CIS Tuple 0x%02x] addr=0x%08x size=%d\n", tpl_code, cis_ptr - 2, tpl_link);
    ! L7 u5 {9 G  v
  898.                 dump_data(data, tpl_link);/ d* f" t% C& V
  899.                 switch (tpl_code)
    / Q1 }9 a3 [* ?% s
  900.                 {
    7 b) |0 e0 a- d" O- w8 M2 y) m, X3 ^
  901.                 case CISTPL_VERS_1:& K3 b0 p) k* @+ }
  902.                         i = 2;) y, n9 M* B; A/ x7 u5 w
  903.                         while (data[i] != 0xff)9 L0 b! i5 W# i2 `1 p
  904.                         {
    3 p" P& y; y* c. [
  905.                                 len = strlen((char *)&data[i]);
    + x  ~6 o2 H( C6 D
  906.                                 if (len != 0)
    3 R- E) y7 U8 c% w$ z( N
  907.                                         printf("%s\n", data + i);
    - Q/ l5 o; C* g2 \) J
  908.                                 i += len + 1;7 [; r4 A7 A  q4 r( O7 ?
  909.                         }
    * V2 x* k# x9 I! p* z; U
  910.                         break;
    ; B. J; }! z% X1 F( Y
  911.                 case CISTPL_MANFID:( l2 o3 t$ _, {9 v* a; |: [
  912.                         // 16.6 CISTPL_MANFID: Manufacturer Identification String Tuple7 T3 X  ]1 l4 @/ X) o, X  G" |3 J
  913.                         printf("SDIO Card manufacturer code: 0x%04x\n", *(uint16_t *)data); // TPLMID_MANF
    : y3 e: x; [( j. J% S0 n% F# l2 I5 h  U
  914.                         printf("manufacturer information (Part Number and/or Revision): 0x%04x\n", *(uint16_t *)(data + 2)); // TPLMID_CARD
    1 X$ O( H$ e$ b% I( m8 K7 V/ G% q
  915.                         break;
    " _. _7 U9 G7 J' F9 y3 U+ b/ q
  916.                 case CISTPL_FUNCID:
    ! Z5 w% g! T9 \/ Y: c
  917.                         // 16.7.1 CISTPL_FUNCID: Function Identification Tuple! F8 O0 f- v4 O- r
  918.                         printf("Card function code: 0x%02x\n", data[0]); // TPLFID_FUNCTION
      O8 e) e9 V' U/ T
  919.                         printf("System initialization bit mask: 0x%02x\n", data[1]); // TPLFID_SYSINIT" D5 E8 V3 [  I$ B; F. }; a
  920.                         break;3 j  E: f! g: T6 @" T& b) P
  921.                 case CISTPL_FUNCE:' P+ u3 p! h. F. H1 Y; ~
  922.                         // 16.7.2 CISTPL_FUNCE: Function Extension Tuple
    ) z/ \* F2 t$ k
  923.                         if (data[0] == 0)
    ! ~3 P# Q( `  O# Y5 z2 y
  924.                         {
    ! z" g; T# ?& \9 ?" |$ X
  925.                                 // 16.7.3 CISTPL_FUNCE Tuple for Function 0 (Extended Data 00h)
    0 a1 |' \& ]9 M# _
  926.                                 printf("maximum block size: %d\n", *(uint16_t *)(data + 1));% D  P) L( ~+ f. a$ {
  927.                                 printf("maximum transfer rate code: 0x%02x\n", data[3]);0 q  y+ V7 F& H0 u3 E
  928.                         }
    0 C) Q* V6 B9 h, h
  929.                         else( \1 A: ^6 [0 t& g. w1 D3 X" O
  930.                         {
    - w8 a; Q' R  q/ {- O; a* p& s) f
  931.                                 // 16.7.4 CISTPL_FUNCE Tuple for Function 1-7 (Extended Data 01h)
    1 t+ v9 p  G5 F2 E
  932.                                 printf("maximum block size: %d\n", *(uint16_t *)(data + 0x0c)); // TPLFE_MAX_BLK_SIZE4 k3 r* n7 C% D+ p) \) O
  933.                         }' B" ^3 W, o( H% o
  934.                 }
    7 L/ E% E& s8 V* o6 l0 `- b" e
  935.                
    * j4 ^4 W1 E) r0 l) r/ @
  936.                 cis_ptr += tpl_link;$ Q8 H+ ?: h; F& r# J. p/ {
  937.                 if (tpl_link == 0xff)% K5 |; a; ^' h! ]* }  h
  938.                         break; // 当TPL_LINK为0xff时说明当前结点为尾节点
    * ~, j+ O8 A) W/ M2 N- N
  939.         }
    $ A7 M; n# L& N9 E
  940. }
    * Q( ^' R- @  q: G) B) C- A5 a7 ^
  941. 4 V2 F) J) E/ s+ {4 {' ?" P  ]
  942. /* 显示所有密钥 */
    5 \: i9 D3 V# e7 E- f6 J; Q
  943. void WiFi_ShowKeyMaterials(void)& t; R) E1 r& W7 z+ q3 z
  944. {
    ( {6 M- Z" N7 e' {, c5 ?
  945.         uint8_t buffer[256];
    3 M4 u# h5 N/ d
  946.         uint16_t size;- D8 k& L! }" m& N; N
  947.         MrvlIETypes_KeyParamSet_t *key = (MrvlIETypes_KeyParamSet_t *)buffer;
    & P9 Y0 q# D9 r; k2 n  h
  948.         % ~/ n6 p; [+ i6 I) z' M
  949.         size = WiFi_KeyMaterial(key, sizeof(buffer), WIFI_ACT_GET);5 E! K$ G3 ?7 k8 z  ?' B# I- D( i
  950.         while (size); }" \( `3 ]" T9 Z
  951.         {" \7 }, S) d& u. o( h5 K
  952.                 printf("Type %d, Info 0x%04x, Len %d\n", key->key_type_id, key->key_info, key->key_len);
    % m% }( X1 D3 {+ g
  953.                 dump_data(key->key, key->key_len);
    ' }0 d/ D9 m, O0 d, ?. s
  954.                 size -= MRVLIE_STRUCTLEN(*key);6 K. \8 h3 ?; }
  955.                 key = (MrvlIETypes_KeyParamSet_t *)((uint8_t *)key + MRVLIE_STRUCTLEN(*key));1 o( ^4 h: w+ U9 n. l- A5 n  X, }
  956.         }
    ) D4 G. U# b6 O# Y5 b
  957.         if (size == 0)7 f# q3 |7 p  e
  958.                 printf("data end!\n");
    4 [; S" n  B4 U6 y
  959. }  U% L' K) C9 P( m. n
  960. . d5 T* e& d2 Y1 _
  961. /* 创建一个Ad-Hoc型的WiFi热点 */
    # T1 ?. H! M" b2 A
  962. uint8_t WiFi_StartADHOC(const char *ssid)4 L, ^. Q0 K% o( F6 ~0 }5 S! O
  963. {
    5 i( H0 v- R* ?. i
  964.         WiFi_CmdRequest_ADHOCStart cmd;
    ) H8 o+ v7 U( Y* Z
  965.         memset(&cmd, 0, sizeof(cmd)); // 由于命令中含有Reserved区域, 所以必须先清零7 _  R% |& C. Z1 L! Q* z; q
  966.         3 {  [& }/ P! _, u
  967.         strncpy((char *)cmd.ssid, ssid, sizeof(cmd.ssid));
    " v  F* P5 |" T! [0 g: Q
  968.         cmd.bss_type = BSS_INDEPENDENT;
    $ o9 h: U0 J0 K/ u# a
  969.         cmd.bcn_period = 100;
    7 c5 H7 X& E. f
  970.         cmd.ibss_param_set.header.type = MRVLIETYPES_IBSSPARAMSET;! u, _9 l& `4 M+ Z- Z. h$ K- T
  971.         cmd.ibss_param_set.header.length = MRVLIE_PAYLOADLEN(cmd.ibss_param_set);
    ( g3 `+ r9 F) c% o6 F9 g# |+ {
  972.         cmd.ibss_param_set.atim_window = 0;, G2 [+ a4 s- H( W7 l) B! l
  973.         cmd.ds_param_set.header.type = MRVLIETYPES_DSPARAMSET;
    * J9 D  \. k' y) X5 i' Y) a
  974.         cmd.ds_param_set.header.length = MRVLIE_PAYLOADLEN(cmd.ds_param_set);
    1 `: r# z0 V+ {& V& x/ x4 O
  975.         cmd.ds_param_set.channel = 1;& Y/ P+ c8 r; j8 |
  976.         cmd.cap_info = WIFI_CAPABILITY_IBSS/* | WIFI_CAPABILITY_PRIVACY*/;6 i1 Z( v3 j9 T9 u. B, b# E
  977.         *(uint32_t *)cmd.data_rate = 0x968b8482;, P% H* F" t' ?0 k& u! B( D
  978.         
    5 h  Q6 u3 e  a
  979.         WiFi_SendCommand(CMD_802_11_AD_HOC_START, &cmd, sizeof(cmd));# @) L) K9 G2 M8 `9 `$ U
  980.         WiFi_ReceiveResponse(&cmd, sizeof(cmd));2 U( r! x; T) d# y5 \
  981.         return cmd.header.result;: R8 D& g5 z( A/ k$ M
  982. }
    ! y3 i- G7 `- A7 @4 H

  983. ( h# o2 g3 E% R9 J" _0 s7 c" w
  984. /* 在规定的超时时间内, 等待指定的卡状态位置位(自动包括IO Ready位), 若成功则返回1 *// ]2 _% Z; t; ?1 I$ B% d) ~
  985. uint8_t WiFi_Wait(uint8_t status)2 i* a7 c5 O7 w% g  n: O( b
  986. {
    - }4 ^7 {- G& F: _! E0 p
  987.         status |= WIFI_CARDSTATUS_IOREADY;  _1 Q& W7 n) s# L
  988.         WiFi_PrepareTimer(wifi_timeout);+ t7 f; b/ @, F0 d; x* |* v
  989.         while ((WiFi_Read(1, WIFI_CARDSTATUS) & status) != status)
    5 Q" t4 ], K5 {+ H$ c
  990.         {7 h! {# f" d) U+ b. J2 T0 H7 q  F
  991.                 if (TIM6->SR & TIM_SR_UIF)
    * X' I" M1 c% f/ u# u
  992.                 {" ^, J& J$ X& P+ `! B
  993.                         // 若超时时间已到
    0 _: Q- z) j. q/ r6 F( E+ W
  994.                         TIM6->SR &= ~TIM_SR_UIF;
    , Z' W4 M* h6 D1 L" r# l( A
  995.                         printf("WiFi_Wait(0x%02x): timeout!\n", status);
    & E  q0 s' ^" n( T- B
  996.                         return 0;3 _6 s, R9 M/ H. e  X, S* i
  997.                 }
    1 z! d! Q2 @7 N( p! l9 |6 _2 G
  998.         }
    ( ^0 p* g; U, M7 D. N* n5 P! k! Q
  999.         TIM6->CR1 &=~ TIM_CR1_CEN; // 关闭定时器
      g; l  H* b2 |; G, z
  1000.         return 1;$ l/ W" \3 t0 K6 y  ~0 c$ S5 b5 X
  1001. }( i, w8 R7 d0 q6 @9 `

  1002. 8 n% [! @. q  n+ P8 c! P8 D  ^
  1003. /* 写寄存器, 返回写入后寄存器的实际内容 */4 s, ]; w: E) t# R5 _
  1004. uint8_t WiFi_Write(uint8_t func, uint32_t addr, uint8_t value)6 `- F+ p/ ^7 R6 k3 Z5 Y' G" U
  1005. {
    : {6 k/ ]' b5 [7 Z; I% m* S
  1006.         WiFi_SendCMD52(func, addr, value, CMD52_WRITE | CMD52_READAFTERWRITE);
    4 J( J1 p; H9 g2 ^! h  B7 N+ T
  1007.         if (SDIO->STA & SDIO_STA_CMDREND)
    4 R+ M7 z/ l0 b( r# q9 X6 z
  1008.         {
      D7 ]1 j7 m& m6 D% Z" \
  1009.                 SDIO->ICR = SDIO_ICR_CMDRENDC;& g' o( |- @( E( g) d
  1010.                 return SDIO->RESP1 & 0xff;
    9 v- G* m7 J+ q
  1011.         }. N2 x: `# {2 w* r$ G* M
  1012.         else
    2 l9 e) R, f- h& T' |/ f0 E4 w6 C9 U
  1013.         {$ U! \4 k) F& V7 g; F/ T
  1014.                 printf("WiFi_Write failed, SDIO->STA=0x%08x!\n", SDIO->STA);
    9 C$ H- [6 ^1 Q9 s, a
  1015.                 return 0;
    / C( f! j9 W+ O* ~& b; d8 F
  1016.         }
    ( X6 R1 D: Q% i- K% Y  q
  1017. }
    ; S* v0 G7 |1 c$ M
  1018. 4 R7 M" ^# H3 \7 f3 ?
  1019. /* 写数据 */! {  Q4 T# k' r7 z# Q
  1020. // count为要发送的字节数或块数, bufsize为data缓冲区的大小
      Q% [+ C7 v$ f+ G% A, B5 N
  1021. void WiFi_WriteData(uint8_t func, uint32_t addr, const uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags)- e, B, ^- @3 L! w2 v
  1022. {* t$ o2 p9 J$ O4 H/ z0 ]
  1023.         uint32_t len, temp;4 U. [9 }! C! ^, Y( I, h
  1024.         if (flags & CMD53_BLOCKMODE)
    ! M0 n9 H) S, c7 h
  1025.         {
    " i! y- t5 o7 K
  1026.                 len = count * WiFi_GetBlockSize();- \& W/ r9 p' p6 X$ L' U, T' u5 ]7 ?
  1027.                 SDIO->DCTRL &= ~SDIO_DCTRL_DTMODE;7 M8 p3 k7 t) l' \1 f1 m  B
  1028.         }
    - N' e# |( |1 r5 J. u" u
  1029.         else1 Z, g6 l( `/ l( [/ E
  1030.         {2 @$ M3 M% p3 a# ^7 b* \6 z
  1031.                 len = count;: z% Q1 n" r. e. [& f' L& U- s
  1032.                 if (len % 4 != 0)
    9 c" h" m( J' {/ ?- J4 c
  1033.                 {
    1 \# g- S" Z2 T% H2 o; a
  1034.                         len += 4 - len % 4; // WiFi模块要求写入的字节数必须为4的整数倍5 a& {2 g7 {" @: l  r
  1035.                         count = len;6 ?! r0 K: Z% Q: ]
  1036.                 }
    6 }( B( z6 l/ E; ]
  1037.                 SDIO->DCTRL |= SDIO_DCTRL_DTMODE;5 B( l& ]1 h0 |" Z
  1038.         }
    ! s1 m# b$ |* O$ P8 L5 h
  1039.         SDIO->DLEN = len;
    * M, H0 [9 P* Z! w
  1040.         SDIO->DCTRL &= ~SDIO_DCTRL_DTDIR; // 设置传输方向: 从主机到模块% U3 B) g5 N5 f6 R. L
  1041.         
    % d$ X6 Q6 K4 N0 @
  1042.         WiFi_SendCMD53(func, addr, count, flags | CMD53_WRITE);0 F& B% v' V* v, }" C2 Y8 S1 k
  1043.         while (SDIO->STA & SDIO_STA_CMDACT);! C7 n( Q+ \0 I9 ?! N9 g
  1044.         if ((SDIO->STA & SDIO_STA_CMDREND) == 0)
    - I" ]9 Z! N6 _. A1 m3 {" g( ~0 V5 M
  1045.         {5 O# U. E1 W/ h) ~4 h( m  D' F
  1046.                 printf("WiFi_WriteData: CMD53 no response!\n");
    % O: g2 E0 j9 y# h
  1047.                 return;
    6 O. o0 D: z+ q6 F3 g
  1048.         }
    ; z' \: |& q  @9 Y1 w4 K' u
  1049.         SDIO->ICR = SDIO_ICR_CMDRENDC;% a% d1 ]7 X) Q1 N0 U
  1050.         
    3 n' p: y) \2 s& Y) p
  1051.         SDIO->DCTRL |= SDIO_DCTRL_DTEN; // 开始发送数据: z* Z2 K% g* l+ j+ s: w
  1052.         while (len)* u" g/ }' R% E; x" A, Q( ?( e  B1 ]
  1053.         {; A8 K& k2 g* Y5 [
  1054.                 len -= 4;
    3 c+ U, `* A: X" q4 _: B
  1055.                 if (bufsize >= 4)0 n0 Y' }7 r2 a) F: L1 P# v8 }
  1056.                 {
    % U  ^5 o; K' M2 y$ ?0 G4 t! N
  1057.                         SDIO->FIFO = *(uint32_t *)data;
    2 d3 R: U# ~8 M: ^0 c9 M) P9 _
  1058.                         data += 4;
    & q% G2 K+ x7 J" W" z' M
  1059.                         bufsize -= 4;
    # z3 s: N  ^/ S8 c
  1060.                 }( e, M! t0 B& a9 i- f
  1061.                 else if (bufsize > 0), @( J- ?  y  A4 S5 s5 H$ N# q
  1062.                 {
    0 D5 L: ^6 I2 m5 B* O/ ?2 @
  1063.                         // 发送缓冲区最后1~3字节
    - ]7 R8 u! M, U1 k3 \. z8 v
  1064.                         temp = 0; // 不足的位用0填充+ p% q& K- q+ P9 M
  1065.                         memcpy(&temp, data, bufsize);: a+ X& N: s, g7 C0 S: b
  1066.                         SDIO->FIFO = temp;
    2 {& Q6 K' v: f8 D
  1067.                         bufsize = 0;& U2 M: ?2 J1 E/ D
  1068.                 }# |; W0 z/ U- w8 F! O- k
  1069.                 else
      W, S/ k" R% X6 [# `; G$ {# R2 C
  1070.                         SDIO->FIFO = 0; // 缓冲区已用完, 因此发送0
    - l* V# O7 N5 J) A  u- u4 H' l
  1071.                 while (SDIO->STA & SDIO_STA_TXFIFOF); // 如果FIFO已满则等待& G9 W0 ~& D) w% h/ R% L7 S7 i
  1072.         }
      m" c0 E0 W+ S1 I. z' Q* ]
  1073.         5 o4 L9 |0 R' [+ A
  1074.         while (SDIO->STA & SDIO_STA_TXACT); // 等待发送完毕
    9 c6 q5 p# i$ E) t& D5 }3 [6 j, t6 w
  1075.         SDIO->DCTRL &= ~SDIO_DCTRL_DTEN; // 数据传输完毕后DTEN应及时清零, 防止后续对DCTRL寄存器操作后误启动数据传输导致超时或CRC校验错误4 q" ?, q2 F  `3 K$ z/ V* o
  1076.         
    # \/ }$ O2 S: r+ N9 ?3 E. @; _6 \
  1077.         // 清除相关标志位
    + }1 ~  a( ?! M$ [. P
  1078.         SDIO->ICR = SDIO_ICR_DATAENDC;  x! w$ o1 S3 j
  1079.         if (flags & CMD53_BLOCKMODE)
    2 K( j5 v! e. r; E
  1080.                 SDIO->ICR = SDIO_ICR_DBCKENDC;" x% K. o/ d3 i, H- S. c& u
  1081. }
    # U& }/ m6 K; F2 R$ S" G
  1082. & ~3 U: _- L5 _
  1083. uint8_t WiFi_WritePort(const void *data, uint16_t size)
    4 w: K1 I2 v! M+ O* x2 y' k
  1084. {% j$ I5 w8 n: m9 h  R4 k
  1085.         uint16_t block_num, block_size;8 B' s" x- ^+ i
  1086.         block_size = WiFi_GetBlockSize();, l3 l! S# i7 J2 o% ?
  1087.         
    # _/ |, u7 H! n6 Z) U; J. R8 M
  1088.         WiFi_Wait(0); // 发送CMD53前必须IOReady=1
    ' V3 b- A- b: U! @* j8 i8 [( }/ C5 t
  1089.         if (size >= 512 || size % block_size == 0)
    $ j2 A! ]9 V4 V+ }; U9 k
  1090.         {
    5 O6 o9 ?7 H+ A9 p5 j$ \2 m
  1091.                 // 采用Block模式传输( K; B. h2 h8 c6 L1 E) ?
  1092.                 block_num = size / block_size;
    # {8 p/ E8 T  ^0 u' T8 W
  1093.                 if (size % block_size != 0)  a& B+ _' d0 ~
  1094.                         block_num++;
    $ ^& i) |! r3 P2 o! Y
  1095.                
    & [7 M, P3 F$ Y5 u: G7 _
  1096.                 WiFi_WriteData(1, io_addr, data, block_num, size, CMD53_BLOCKMODE);* ?8 M- d& ]4 ^
  1097.         }
    2 `# v% {1 d  A3 e# f
  1098.         else
    % R- C6 ]8 W* c2 L
  1099.                 WiFi_WriteData(1, io_addr, data, size, size, 0);
    % q- Z. P( J8 M) {* U5 ^/ H
  1100.         return SDIO->STA == 0;
    # o! D- c' G% w* j* X6 x
  1101. }, X2 l5 K. Y" p; j2 v
复制代码

4 Z5 x! s. ~% H8 ~+ ?6 u& j6 d3 M1 ^/ m7 s! z
在工程的所在文件夹创建一个lwip文件夹。
* g& M% T6 h/ n" w' @  ^) F然后在lwip的官方网站下载lwip-2.0.2.zip,打开压缩包中的lwip-2.0.2/src文件夹,解压以下文件夹到工程的lwip目录下。
) \7 t9 K) m' y; ?0 _4 Y: w7 L. K. V+ E- l+ Q, d! ^2 L
core/
. n1 d$ v- g' o9 z6 V1 ccore/ipv4
9 l( |. u+ s# ?2 Winclude/lwip
5 ?5 y  u1 x, e! \# R3 c% cinclude/netif# K2 I* Q+ {* z" Y! v; i4 y% r
netif/ethernet.c
, k4 \2 V' w  ^. \6 Xnetif/ethernetif.c
$ \( x# i5 b) u) p- p- M6 U9 O
+ B1 {+ }' n8 ~. l# r解压后,将里面的c文件都添加到工程的lwip分组下。
8 N& J$ _5 e1 z" O$ }! B# L1 U具体添加的文件请看下图:
1 d( ^& E& P9 ]3 O0 z7 v8 Q
# K1 H! L  H: T7 i$ d( F
- E! c# r  }! X; i接下来,创建lwip/include/arch/cc.h文件,内容如下:/ N% Q* L& K4 q8 [( ^$ c0 @; G
  1.     #define PACK_STRUCT_BEGIN __packed // struct前的__packed  
复制代码
创建lwip/include/lwipopts.h文件,内容如下:
' f1 U7 r; b; ?8 X* ]
  1.     #define NO_SYS 1 // 无操作系统  
    ! a& x8 ]# K( E/ i$ P
  2.       
      U; n+ y4 ~; @; ]
  3.     #define LWIP_NETCONN 0  
    , `" y; l2 {' A) g/ G0 E0 f' V
  4.     #define LWIP_SOCKET 0  ) U4 p# f( H+ N- R: ]: |3 C" r6 A& T
  5.     #define LWIP_STATS 0  ' G1 i- C: p+ A* {: t2 E- E
  6.       * D3 A/ ^5 h2 v3 y  I) S+ w
  7.     #define MEM_ALIGNMENT 4 // STM32单片机是32位的单片机, 因此是4字节对齐的  ) M8 k3 A  C1 p  f' Q
  8.       + \0 L6 C9 L# y/ {$ m0 W/ z% m
  9.     #define SYS_LIGHTWEIGHT_PROT 0 // 不进行临界区保护 (在中断中调用lwip函数时要小心)  
复制代码
打开lwip/netif/ethernetif.c文件,按照下面的中文提示修改代码:4 l5 {; `  z: k+ h1 a0 x
  1. /**) K& ]5 f4 Q1 @  J) |, Q
  2. * @file! ]. N4 A- S2 `6 i
  3. * Ethernet Interface Skeleton
    $ M  f- Q; u; v# W
  4. *
    # s% a9 b: s! E+ O- C1 h. B* e
  5. */$ K1 Q2 f2 Y0 F4 I- L& L
  6. 8 O1 U  R, J- r' Z2 E" c* H
  7. /*& ?- G5 V; Y, X2 E$ I& }( b- J6 `- `
  8. * Copyright (c) 2001-2004 Swedish Institute of Computer Science.( p% X6 [8 R" C3 g# ]5 F2 ]+ M
  9. * All rights reserved.- T2 L9 T( j4 c% z2 Z# p4 M( y' H
  10. *% |  d+ }$ x2 R5 X1 C& R; w: S
  11. * Redistribution and use in source and binary forms, with or without modification," R" E3 v! w- h3 d' H- U
  12. * are permitted provided that the following conditions are met:" w/ l: X' O9 y$ @
  13. *3 B. B9 K" S8 ^% `7 C! f
  14. * 1. Redistributions of source code must retain the above copyright notice,- V8 ?# W$ U  v4 B4 D/ N1 \
  15. *    this list of conditions and the following disclaimer.
    # q  O+ d; X9 v* t
  16. * 2. Redistributions in binary form must reproduce the above copyright notice,& `- t) p- r' c, G
  17. *    this list of conditions and the following disclaimer in the documentation; ~7 s& @- T/ O$ G
  18. *    and/or other materials provided with the distribution.- |8 q7 F# J( e* M; @" Y& i9 a
  19. * 3. The name of the author may not be used to endorse or promote products
    - K. N1 A- E) m+ Q+ p
  20. *    derived from this software without specific prior written permission.6 I& g  h5 ?1 Z
  21. *
      c2 c& h4 y/ N: j& d7 q
  22. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
    & m/ ?% j  k7 h9 I1 G' @
  23. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    2 Y. O( r- T) A" i  G/ F- ^) M: j
  24. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT5 ^( w5 r; F+ U5 y; \$ n
  25. * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,% P$ g. W1 h- S
  26. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT6 q+ L* _. C" G" U" ], ]
  27. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    - R" S" n5 R- G9 \
  28. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN& {! K4 b; }# u
  29. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    $ z& r5 b+ D# k! l" C
  30. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
    ! J! B8 n3 `* _! L- ]- {, B
  31. * OF SUCH DAMAGE.
    5 y# A3 p; b! u1 C; G" X7 _! t
  32. *
    ) x, H- w3 \6 ]& {( ^4 o! ^
  33. * This file is part of the lwIP TCP/IP stack.
    : r5 w# O2 b4 L/ J
  34. *
    $ ]+ [' Y% H+ F# q1 o1 A2 Z% Z. g
  35. * Author: Adam Dunkels <adam@sics.se>) Q7 W& N7 t, K, k! ^- b7 J
  36. *
    & U1 z8 n  l* D- l8 V
  37. */
    # }  l4 E" j* ]7 n. U% r& U

  38.   C" K3 V8 ?1 c9 {& @5 c) M
  39. /*
    / h: Z) t% N! \. G9 e& X1 m
  40. * This file is a skeleton for developing Ethernet network interface
    , ]: @7 |2 E; }7 r8 R
  41. * drivers for lwIP. Add code to the low_level functions and do a3 s# f/ c1 t, I0 i) Z! p1 ]# y
  42. * search-and-replace for the word "ethernetif" to replace it with
    / G2 R8 U% {. F* e
  43. * something that better describes your network interface.
    $ P. [- r7 U5 u' o% V- e% {5 l
  44. */  l, w2 `9 c. ]' K9 v0 _
  45. . |' O3 n% T0 H7 t: O6 x) w
  46. #include "lwip/opt.h"# R0 U* A, W# R0 n

  47. , i7 A; B/ o- V: C
  48. #if 1 // 允许编译器编译该文件
    4 ]& |& @4 w! M# S# ^
  49. & s& j+ X3 w0 I1 q2 x3 \
  50. #include "lwip/def.h"5 |1 d8 T9 i  D! e% h- @' A
  51. #include "lwip/mem.h"
    % Z0 p2 N; K7 e: p0 f% C/ o
  52. #include "lwip/pbuf.h"
    . z# _# d# f  f' ^
  53. #include "lwip/stats.h"8 v) i( h1 |' S. g4 T
  54. #include "lwip/snmp.h"6 S. z. O( S  B% J
  55. #include "lwip/ethip6.h"
    - w& e2 ?6 F/ C; T, S# p1 Q: W
  56. #include "lwip/etharp.h"
    ) v% B9 M% d: l0 C( }% M- z
  57. #include "netif/ppp/pppoe.h"
    ) K( Q' m- s& I% L0 V

  58. , c# X; A( _1 m: j6 l: z
  59. /* Define those to better describe your network interface. */3 b" S1 F/ ?) L
  60. #define IFNAME0 'e'
    7 L9 U! k8 V0 P& n
  61. #define IFNAME1 'n'
    1 l8 V) Z" M3 g- x

  62. , y4 M, M3 }; m# p! z$ [
  63. #include <string.h> // memcpy函数所在的头文件
    5 s$ n5 v- `2 M5 c7 E
  64. #include "WiFi.h" // WiFi模块驱动程序头文件
    8 }( y$ [& G# T8 _
  65. $ ~- l7 K4 e4 I2 `  L& A
  66. void dump_data(uint8_t *data, uint16_t len);
    ' b9 J' W# R; _  P$ U

  67. 6 P* O# d6 C& g9 j4 I0 E
  68. /**0 o8 Z* L0 |& Y7 p
  69. * Helper struct to hold private data used to operate your ethernet interface.
    % ^1 ^3 }1 i2 t9 J
  70. * Keeping the ethernet address of the MAC in this struct is not necessary
    ( W* O3 f9 b% F$ R3 }
  71. * as it is already kept in the struct netif.5 j5 l- w8 Z, H
  72. * But this is only an example, anyway...
    + }! ?3 P  F% _- v
  73. */, X6 N, ?4 q8 m8 o- C6 M! x8 {& L
  74. struct ethernetif {0 T6 Q% c) t- C1 Y
  75.   struct eth_addr *ethaddr;
    ) Z! c5 D6 x  u6 t/ j( ~6 i
  76.   /* Add whatever per-interface state that is needed here. */+ v* |* w5 o2 h
  77. };
    & I* L6 Q, U' h* k& n& f# }- r
  78. ; x* f, c" `6 t
  79. /* Forward declarations. */
    ( {5 h$ x2 |4 z, l1 W
  80. // 这里必须去掉static2 `# N& ]' m- F7 I
  81. /*static */void  ethernetif_input(struct netif *netif);( s/ b) t: L) ?/ q9 A" j
  82. % [: O3 Z! U) I, c9 P( y1 ?7 L
  83. /**# r/ R- c0 B" H( B" N* U: s
  84. * In this function, the hardware should be initialized.
    ( ^$ `) [' ~  ]: s. `7 ~
  85. * Called from ethernetif_init().: J( `/ J6 n/ U+ C" a
  86. *: ~( `8 _$ C- ?0 i7 E8 i' }) o
  87. * @param netif the already initialized lwip network interface structure) T9 b7 Y, ?8 w- d
  88. *        for this ethernetif5 R4 P( S( q0 F
  89. */
    * ?! c  n2 y$ D' z. N
  90. static void
    9 O: Y3 i0 k' Z6 I0 {- r
  91. low_level_init(struct netif *netif). w& ]8 |6 ?; ^6 t: B  ?5 R0 X
  92. {2 F# `5 ~0 ]$ o7 b6 g& s! F% T
  93.   struct ethernetif *ethernetif = netif->state;
    # W1 a" |8 f( j1 c: i

  94. " u3 u9 P0 l& S' ?4 g9 _( w2 ^* n
  95.   /* set MAC hardware address length */
    % o, i3 z) p/ j: S+ I
  96.   netif->hwaddr_len = ETHARP_HWADDR_LEN;/ _- o2 \5 ?1 S& D3 M

  97. % k0 j" z# y. p  ?6 `
  98.   /* set MAC hardware address */5 B0 ^/ J6 z8 {  y" d
  99.   WiFi_GetMACAddr(netif->hwaddr); // 获取网卡的默认MAC地址1 a" H1 }" u$ s+ C' `! N
  100.   printf("MAC Addr: %02X:%02X:%02X:%02X:%02X:%02X\n", netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5]);7 k8 N; c- b- p& ?$ R6 n+ Y  Y

  101. 6 ?' `! m& K8 C1 K
  102.   /* maximum transfer unit */# h6 w! U% U# e- _' f: q/ @- A
  103.   netif->mtu = 1500;
    4 N: K3 p# l4 M

  104. ! V8 p1 ]( o4 O: F; W( S, g. [1 K
  105.   /* device capabilities */. {$ Q- r7 y  u9 {. N
  106.   /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */( [* l; `2 j  s
  107.   netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;9 b- z/ R5 L" O+ R9 H

  108. 6 {& N- Q( r" Y3 w# r
  109. #if LWIP_IPV6 && LWIP_IPV6_MLD
    ) `% T$ m; w: w0 z% W
  110.   /*
    - \+ S1 `  Q$ O6 c% H$ w# V2 h2 D
  111.    * For hardware/netifs that implement MAC filtering.
    ' C- S+ l  [% x8 E( V
  112.    * All-nodes link-local is handled by default, so we must let the hardware know. H. d/ J/ ~1 i  j- K( @. b
  113.    * to allow multicast packets in.
    5 s" N" h5 D3 f0 B3 A- A
  114.    * Should set mld_mac_filter previously. */0 B' H- G2 J6 O0 v. Y: {
  115.   if (netif->mld_mac_filter != NULL) {
    ) X' X* h2 y1 K2 b) h
  116.     ip6_addr_t ip6_allnodes_ll;
    . T! r& f7 k; ~7 ]( j/ u
  117.     ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
    ( Z# U+ e! L1 f: L
  118.     netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER);5 j' V( h4 _0 H- N1 \
  119.   }
      J5 R% p( P) Y9 a6 M
  120. #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
    9 C- r6 V9 C, R& j( w
  121. 7 |2 }4 y' h1 w7 J7 Z( U
  122.   /* Do whatever else is needed to initialize interface. */8 y5 M) p) Q  V' I3 l) w  N: ~
  123. }
    % |8 ~% d/ O9 w: t5 Q+ I/ K2 w4 ~

  124. $ k% s  `! p3 S5 a) `
  125. /**" h: p3 ]" P5 u9 c; R! p3 ^
  126. * This function should do the actual transmission of the packet. The packet is
    3 O, U6 }: [4 w9 ^
  127. * contained in the pbuf that is passed to the function. This pbuf5 v# w! j/ n% J
  128. * might be chained.
    0 q2 ?% {7 a4 F( b6 D
  129. *
    # {- n; Y, I, i1 Y
  130. * @param netif the lwip network interface structure for this ethernetif! `9 s% K" y. Y! Z9 C
  131. * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)6 J: s2 m1 w* {# X3 v' c
  132. * @return ERR_OK if the packet could be sent4 T, [- p* m; }0 {" S+ e
  133. *         an err_t value if the packet couldn't be sent
    0 ^  S3 X+ c6 M9 l. `8 R% g# j
  134. *7 Q) Y" I2 O. t: C
  135. * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
    . w$ ?* b4 G  @) S& r
  136. *       strange results. You might consider waiting for space in the DMA queue) X0 S4 ^  A1 U+ j( p- h. c
  137. *       to become available since the stack doesn't retry to send a packet, R4 }" r0 \! W$ I  |% N
  138. *       dropped because of memory failure (except for the TCP timers).
      n) D+ }( j2 W3 z/ J  M
  139. */
    0 m8 _3 A( _, w+ z3 D

  140. 7 q2 T: K5 Q  T+ e* M- ^2 @! F
  141. static err_t
    % B. C% O# @+ F5 ^; y
  142. low_level_output(struct netif *netif, struct pbuf *p)4 n) F( y6 I) L. S' ~/ Q' K
  143. {* F2 N: r' ~' f' \+ S$ ^8 k5 ~4 v, |
  144.   struct ethernetif *ethernetif = netif->state;* D$ d; [4 H& ?) I" c1 C
  145.   struct pbuf *q;
    ! E- l6 ~4 z7 i# O9 Q) f
  146.         " e. B: ?( g; z" a- o9 b8 B) M; S
  147.   // 添加的变量* Q" m& P, U, N4 \2 t, r1 N+ {. Z
  148.   uint8_t buffer[1792];3 T  j" J( C3 u" d' z# z. B: P
  149.   WiFi_DataTx *packet = (WiFi_DataTx *)buffer;1 j" V. r2 x' {9 o. t. }
  150.   uint8_t *bufptr = packet->payload;. m4 F" g, @2 M* x8 d. `

  151. ) J( H0 ~! M6 \2 o/ t
  152.   //initiate transfer();' b* b8 r1 A0 j+ f' X

  153. 4 i* t9 e; x7 M9 Y4 s) c' p
  154. #if ETH_PAD_SIZE7 ^8 A+ g. |* [" x! o
  155.   pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */; p2 ?7 ]8 l$ e$ k, e: {' b
  156. #endif  V  n2 Y4 C5 h* k9 C1 [' H) Q
  157. " J' G( F( d! }8 h
  158.   for (q = p; q != NULL; q = q->next) {* _$ o4 m8 }0 x. _2 Y* E* f
  159.     /* Send the data from the pbuf to the interface, one pbuf at a
    4 `& v* C; r) \, y, j5 A4 L
  160.        time. The size of the data in each pbuf is kept in the ->len
    7 U3 V# j6 Z4 Z0 c
  161.        variable. *// K8 Z6 f6 o) A1 m1 h
  162.     //send data from(q->payload, q->len);
    + Z  m( E6 b1 s
  163.         memcpy(bufptr, q->payload, q->len); // 复制数据包内容& G' x) l+ M7 x1 ]- t3 |
  164.         bufptr += q->len; // 指针前移" e* K* ]+ C" V8 G( A' x% u
  165.   }
    0 `1 k$ l4 o3 H1 ?" L
  166. 9 c7 Y& d3 E$ P8 `) z4 [4 n% Q
  167.   //signal that packet should be sent();
    2 h4 y. Q" {! Q+ Q3 e# I
  168.   WiFi_SendPacket(packet, bufptr - packet->payload); // 发送数据包$ Q& a3 O' m" v! R) }) Z5 M
  169.   + u( F8 S6 M0 R1 y
  170.   // 打印数据包内容
    ) c3 o  u0 C9 A6 p' u3 w+ N9 r
  171.   printf("[Send] size=%d\n", packet->tx_packet_length);# r# _+ h" g2 ^4 E
  172.   dump_data(packet->payload, packet->tx_packet_length);
    ) J0 E. t2 M8 c7 c! I

  173. : F$ o! v. n2 z8 X3 `
  174.   MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
    7 i. J" X" m6 O7 G
  175.   if (((u8_t*)p->payload)[0] & 1) {
    1 c0 O# E4 J  v( j( d
  176.     /* broadcast or multicast packet*/  d9 b; Y2 ^' `& _" K( l
  177.     MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);+ n1 l- p; J/ j, c3 [+ ~2 Q
  178.   } else {( m' U3 s* D1 T: @' L. T+ W& G
  179.     /* unicast packet */2 k* T2 c9 V! h4 {" @: }+ c
  180.     MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
    # C; N$ _* d$ @6 O
  181.   }$ e- r: [8 [' w2 q
  182.   /* increase ifoutdiscards or ifouterrors on error */8 ~3 I! z' m  ]! M/ o7 x7 x2 K
  183. $ C( D, \  A8 y/ E' }
  184. #if ETH_PAD_SIZE
    ! J. m# X: I8 X- l) T9 P
  185.   pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */0 T" q- d! p- |
  186. #endif
    + ^4 A4 g  k7 G( N
  187. ( ?' X  r4 F, ^8 C; j
  188.   LINK_STATS_INC(link.xmit);
    6 K( M: z' d6 A
  189. 2 R+ u1 @1 O; |6 u5 P/ B+ [4 r
  190.   return ERR_OK;
    : _. B" S0 D% `
  191. }* |2 r# J' r! W6 b2 u& J
  192. 0 ^2 d# v! f: Z* }$ x% s
  193. /**
    # U2 M) L, ]. p1 q- P
  194. * Should allocate a pbuf and transfer the bytes of the incoming
    8 {3 `8 q$ E" ~+ A1 Y9 m  T
  195. * packet from the interface into the pbuf.# [2 c& J6 ^7 P* B6 z- g; O
  196. *9 v; g- H7 h* x' D5 E" D6 T
  197. * @param netif the lwip network interface structure for this ethernetif
      s! @. l) G4 s8 O% f6 y
  198. * @return a pbuf filled with the received packet (including MAC header)
    9 O* X, j) p' \8 W% v% {
  199. *         NULL on memory error
    3 Q5 W) R& ^! V1 T) E5 [
  200. */
    : s% a* o$ |9 _+ _) F$ ]
  201. static struct pbuf ** C; k/ X. d8 o4 P* F  C
  202. low_level_input(struct netif *netif)
    1 p0 H. w7 `; ^5 H" e1 R* d
  203. {0 V+ g  T# H9 o! r( |  B8 r' X
  204.   struct ethernetif *ethernetif = netif->state;
    1 D. I3 r. {1 g( m# I/ m, c) c- {
  205.   struct pbuf *p, *q;9 m  r& i8 h8 T0 K+ {2 \
  206.   u16_t len;# B. e! y! k* @$ T! q$ E
  207.         * r' c8 a1 ]4 ?6 J; R
  208.   // 添加的变量/ ~+ y1 {! I! u- ~4 Q$ y
  209.   uint8_t buffer[1792]; // 由于WiFi模块本身不支持使用多个CMD53命令读取数据包, 所以必须建立一个缓冲区, 一次性读取完
    " |6 w$ F: P" B! x6 X# G3 Y9 o1 z
  210.   WiFi_DataRx *packet = (WiFi_DataRx *)buffer;4 P; d0 g, K/ C
  211.   uint8_t *bufptr = packet->payload;
    1 l( n7 X7 L& b& [' i

  212. " o; G5 |9 e4 b# j1 t2 S
  213.   /* Obtain the size of the packet and put it into the "len"
    , C* G6 l: I: R' x
  214.      variable. */
    1 N7 ~3 H5 m2 g- S. U4 R, y
  215.   len = WiFi_ReceivePacket(buffer, sizeof(buffer)); // 读取整个数据包, 返回值包含头部大小/ h$ d; J" U6 Y; \
  216.   if (len == 0)
    , s% |3 @* ]6 }) q
  217.   {  B) F; ?1 O# j3 z
  218.           // 若读取失败, 则不分配pbuf, 退出本函数
    7 Q( p6 \% p& z1 D4 w( h8 l) L! H
  219.           p = NULL;- s& b6 u0 J/ G- b0 [  P6 v: P& a' h
  220.           goto after_alloc;) R' i$ z$ ]7 I* }: V+ L, o, n
  221.   }9 U7 M! B6 o; ~! k7 }# B: I9 c
  222.   len = packet->rx_packet_length; // 获取数据包的大小
    # K% |# Q2 I# D$ |2 |. @
  223.         5 u" l  v# e- f/ }" k4 C
  224.   // 打印数据包内容
    / k. \4 ]# t% [5 k
  225.   printf("[Recv] size=%d\n", len);8 f8 z0 U0 X. E
  226.   dump_data(packet->payload, len);
    + k1 B- _! u- z, D9 B
  227. 6 L) w* m. }8 d: t* g* {+ V
  228. #if ETH_PAD_SIZE+ I3 v# M+ g" N1 ~3 p. U
  229.   len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
    0 V/ O* S* l" J/ }! X+ {
  230. #endif9 [6 z' S9 R) T. \" @
  231.   J4 n$ ?8 F) X+ M
  232.   /* We allocate a pbuf chain of pbufs from the pool. */5 G" i8 u& g8 ^9 s" e: v5 G( b( M
  233.   p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);2 c+ L, ?8 h0 y0 N& R- t
  234.   
    3 A5 ~0 p$ [3 t
  235. after_alloc: // 添加此标记
    4 A$ B/ ]9 d9 P8 {3 q) i- Q& s
  236. % t1 S: j" j! i) y3 G5 l# {" A0 M
  237.   if (p != NULL) {
    - B( m2 h3 a) V
  238. ; D4 a7 \2 b1 ]3 P" ^1 \
  239. #if ETH_PAD_SIZE) I  `) Y6 q5 D0 {% N  f8 j
  240.     pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */$ d& _; q) F# `/ `
  241. #endif
    ( c0 ^; Y( q. Q- B. }& y' l

  242. - ~8 A6 |9 [% X, Z* k# n
  243.     /* We iterate over the pbuf chain until we have read the entire
    6 K) ]( `1 J' s' @; p
  244.      * packet into the pbuf. */
    6 [7 L" L, [. ^2 b
  245.     for (q = p; q != NULL; q = q->next) {; L3 B* U6 z3 w
  246.       /* Read enough bytes to fill this pbuf in the chain. The+ V4 w# o6 F. H* ~$ ]6 P+ U
  247.        * available data in the pbuf is given by the q->len
    7 p+ S4 e' _0 x) F6 N- X
  248.        * variable.
    : u1 k9 w' }* H. n7 c7 b1 Z  z
  249.        * This does not necessarily have to be a memcpy, you can also preallocate% C8 `  {' \& b; _0 q
  250.        * pbufs for a DMA-enabled MAC and after receiving truncate it to the& _; \, X6 ^" L9 h" ]
  251.        * actually received size. In this case, ensure the tot_len member of the
    7 E. a) p$ t" }2 O/ t* T) @+ \
  252.        * pbuf is the sum of the chained pbuf len members.+ m# }* R) \% `7 U
  253.        */4 y/ s4 n: b  t- J" |, [+ ~
  254.       //read data into(q->payload, q->len);# h* O6 w( V3 A
  255.                 memcpy(q->payload, bufptr, q->len); // 复制数据包内容) {- w" Y- |( Y7 T1 {
  256.                 bufptr += q->len; // 指针前移; Y9 D$ d% T3 S8 p# O1 n( N
  257.     }" r0 C' x8 o; e0 Q
  258.     //acknowledge that packet has been read(); // 无需确认
    , a( U1 d# c$ Y

  259. + ?! r; J- w( E/ t+ `+ u
  260.     MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
    2 i0 R8 R& g* P7 [; [
  261.     if (((u8_t*)p->payload)[0] & 1) {
    4 n$ W3 R7 K8 U2 t
  262.       /* broadcast or multicast packet*/' y9 G* B: d. Y6 J. s0 R
  263.       MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);4 H! m0 D- N' d+ d6 w! U
  264.     } else {
    0 }: t7 s1 |5 Y: t: x; u
  265.       /* unicast packet*/) a+ O2 C& c: i9 z3 t; J# W( @
  266.       MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
    " j5 H( A# ]( B; |
  267.     }, }) ^* e, }: l! w
  268. #if ETH_PAD_SIZE
    4 `3 m& P. z  s
  269.     pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
    & f" t: o9 ^; h$ h
  270. #endif
    . K* f/ K+ }7 G+ _, Z7 y
  271. / Q& l5 n, i- h' @4 s9 j
  272.     LINK_STATS_INC(link.recv);
    9 X* c! e' T9 |, D  y& B& K
  273.   } else {
    1 i; k  B0 t' O7 R2 {7 i
  274.     //drop packet(); // 注释掉此行
    $ }' U" k8 j$ t% y
  275.     LINK_STATS_INC(link.memerr);
    " x8 p% D2 \8 I
  276.     LINK_STATS_INC(link.drop);) {. w/ p' `" R  C6 X' G$ O1 E' Y& V) K
  277.     MIB2_STATS_NETIF_INC(netif, ifindiscards);$ u2 m( B- Q' {& b4 S4 ]
  278.   }
    2 S* V0 m4 Z: Q( v
  279. " E. Q4 y  P8 ~# G4 v8 r8 _4 Q
  280.   return p;, b5 B. u. {8 [; Y1 N2 O
  281. }
    * k* g) y, J" G3 }9 A2 r

  282. 1 l& }9 G8 |" G4 {: r4 p& G2 ^
  283. /**
    / Y6 L- R  r, Q4 F% V9 Z. {
  284. * This function should be called when a packet is ready to be read
    7 d5 U/ X+ f: ]1 J2 D
  285. * from the interface. It uses the function low_level_input() that
    " a4 \( R% x, e6 k0 ^$ H, l
  286. * should handle the actual reception of bytes from the network( F- A- X9 L+ R7 |) u6 |5 @. ~
  287. * interface. Then the type of the received packet is determined and8 ]& G# k9 o! ~& n
  288. * the appropriate input function is called.# _2 g+ l- ]3 ?1 O* }8 Z) k
  289. *# u: v1 |9 c& b4 F0 I+ K
  290. * @param netif the lwip network interface structure for this ethernetif3 r  y) A' X3 c! |9 b
  291. */8 s) S: C) [; |" a! z# b! |1 X; ]$ x
  292. // 必须去掉static
    3 k$ n' u4 V$ k2 \
  293. /*static */void
    # b9 ?# }% d+ ~; N) m
  294. ethernetif_input(struct netif *netif)8 t% L5 M  [* `: U, f+ `
  295. {# p- ~  k' D4 }, |; n
  296.   struct ethernetif *ethernetif;
    1 v' S& ~2 }; n2 _1 e% v7 q
  297.   struct eth_hdr *ethhdr;5 v$ Q3 u! v+ j4 {$ Y( e
  298.   struct pbuf *p;, _' v# g2 v: a- K0 P3 b/ q
  299. $ o2 n- t/ i! u' D1 L- |9 {) ~+ P) d# ]
  300.   ethernetif = netif->state;3 B$ F; d$ F# o& I) }! I
  301. 8 V+ f2 U4 X* n; t  y. n
  302.   /* move received packet into a new pbuf */
    ' H0 S; W$ m' O+ @0 l( G
  303.   p = low_level_input(netif);
    3 h+ F  Z+ S6 |# f- z! b
  304.   /* if no packet could be read, silently ignore this */
    2 C. `5 T4 Y. Z  Y) \' H. d; x
  305.   if (p != NULL) {% O+ g* [- d% `7 q- v
  306.     /* pass all packets to ethernet_input, which decides what packets it supports */8 d! ?2 u' ]! n* i7 J6 z) ]" J
  307.     if (netif->input(p, netif) != ERR_OK) {
    0 }" u8 O1 l' h' S# `: J, ^1 s
  308.       LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));' C( M. J0 e# v( E# T8 C" X
  309.       pbuf_free(p);2 ^' r) H- \( }$ h
  310.       p = NULL;
    6 ^% H2 f& q" p6 _8 @5 L
  311.     }
    $ N8 B5 L  ?/ i! l
  312.   }8 g4 \$ X8 f/ U# `! P
  313. }
    , f0 g* ~/ _3 G# f( Z! B5 {

  314. " t; ^! B4 e; h5 @
  315. /**, A3 T3 W0 i& m. `' m  O
  316. * Should be called at the beginning of the program to set up the% j& w, p  k$ _
  317. * network interface. It calls the function low_level_init() to do the" [8 o9 ~. P% \# q' N6 ^
  318. * actual setup of the hardware.1 w  a& x" j9 U* t5 \, X
  319. *+ M' w5 ~- L/ K5 S
  320. * This function should be passed as a parameter to netif_add().
    ; ?/ d. q! }, M8 {) h6 P/ ]
  321. *1 V* S) D4 G3 l; ?
  322. * @param netif the lwip network interface structure for this ethernetif
    : C. y  o. T( h0 p; M3 g. }
  323. * @return ERR_OK if the loopif is initialized, ]- o9 B6 ^$ q. C: b- }! h
  324. *         ERR_MEM if private data couldn't be allocated' }% f+ B$ ]$ t' g* n; c0 ^. o
  325. *         any other err_t on error8 |- t9 b: l5 E) I2 `8 P2 z2 v# p
  326. */
    5 s7 t0 z( \2 i* ^
  327. err_t& i5 `; j2 C# E& S6 H$ I* Z
  328. ethernetif_init(struct netif *netif)
    2 @) C4 w+ c3 \! o5 D. b9 |
  329. {
    + U6 W& ~8 u9 e* h: @: B
  330.   struct ethernetif *ethernetif;3 Q( ]  U" Q) O; ]5 O6 H: j: n

  331. / J) \- y/ A$ v0 J% F
  332.   LWIP_ASSERT("netif != NULL", (netif != NULL));! ]% k5 ?- \9 q+ {7 L- }3 R6 |, S% E' F
  333. 5 _/ j& P) O, z" E3 u
  334.   ethernetif = mem_malloc(sizeof(struct ethernetif));% N% o3 B5 e/ C; I: S* n
  335.   if (ethernetif == NULL) {
    ! d) u6 {- S& V3 h3 w$ y# _" b
  336.     LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));% [, m: e* d: I. O% y
  337.     return ERR_MEM;
    4 l! A' f6 N- i$ @3 B3 P; Z
  338.   }1 Z- T, l5 t+ o# h/ i2 ?
  339. 4 [* ]) [6 o! Q
  340. #if LWIP_NETIF_HOSTNAME/ B, V- q- p  T7 [( J$ k/ x# B
  341.   /* Initialize interface hostname */: d: u0 V9 r' n& Y, \/ q0 n
  342.   netif->hostname = "lwip";
    3 @( o& ?9 r. v% d
  343. #endif /* LWIP_NETIF_HOSTNAME */
    . h3 t& E& c1 P

  344. & N) N# D0 I  l+ x
  345.   /*
    0 B' F4 H& c7 z% H1 r% N# z
  346.    * Initialize the snmp variables and counters inside the struct netif.( I9 k: @0 U3 r. I# a5 e, T( y
  347.    * The last argument should be replaced with your link speed, in units! N5 ]% m& D4 h! _1 k$ ^! K
  348.    * of bits per second.6 z% }& B) Y$ P$ F4 w! }, |* `8 ]
  349.    */7 f+ q: i+ j4 Z' x2 v/ L1 r9 U1 q
  350.   MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
    ) X6 E5 q1 _! b' f0 W

  351. + d" _" e# E' N- }$ t
  352.   netif->state = ethernetif;7 v9 a! {$ o1 Q0 O
  353.   netif->name[0] = IFNAME0;
    2 B+ b5 L$ h) Y1 w3 b3 x0 v
  354.   netif->name[1] = IFNAME1;% p% `: t2 \' g2 F2 K
  355.   /* We directly use etharp_output() here to save a function call.7 D- N8 O2 o/ J8 Z/ x# Z
  356.    * You can instead declare your own function an call etharp_output()" s" c; W2 c& \4 c
  357.    * from it if you have to do some checks before sending (e.g. if link+ |* W$ H/ J5 |  Z8 O
  358.    * is available...) */  ^/ q7 L1 b/ {; l! M, K
  359.   netif->output = etharp_output;. p/ O: I0 o1 L; Z: E! }! v& _
  360. #if LWIP_IPV6
    + _/ u3 T; W8 _9 B$ z) \% ]% J
  361.   netif->output_ip6 = ethip6_output;
      b# C  ^7 s5 G6 H7 a: t
  362. #endif /* LWIP_IPV6 */
    0 z' v4 d- n6 I- z5 V
  363.   netif->linkoutput = low_level_output;
    8 G, Q0 p$ B  ]7 B

  364. & ~# F' w3 m. o! ~. k
  365.   ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);' v, X: O% k7 O  }" K7 i

  366. ' q  k" {" z) e* D: Y! |/ f
  367.   /* initialize the hardware */
    9 E3 V9 K  B( l
  368.   low_level_init(netif);
    ! N* n2 K! c$ j  P

  369. % ~( l, Y. Q  e5 F' T
  370.   return ERR_OK;/ Z2 x  G9 p+ Z
  371. }) A1 j+ X) n" @: }# V* J/ P

  372. 6 S3 \$ A% `, H. w- |" t
  373. #endif /* 0 */
    6 P; W! c5 K' G7 Y* Z
复制代码
) x3 k3 g" H1 d: u/ S3 V$ @9 T
在项目属性中,设置Include Paths为:.;.\lwip\include
9 M* l& S7 q* o+ m其中点表示工程根目录。
& t# N2 U& L" Q5 I  D% T
& P  i7 k7 o9 I/ i# y, p另外,为了在程序中使用printf函数,Target选项卡下的Use MicroLIB复选框也要勾选上。
5 ?* @8 Q: V9 S- u$ [
/ E# n( M% q# Z  u编译并下载程序,电脑和WiFi模块要连同一个WiFi热点。( ^- R$ d) }3 g. i  l
电脑的IP地址要手动配置。IP地址为192.168.43.71(最后一个数随便),子网掩码为255.255.255.0,网关为192.168.43.1。
$ Q1 i( V4 m+ h9 A4 p3 [5 E0 m配置完成后,即可用电脑上的浏览器访问开发板上面的HTTP服务器。, n( L1 O3 F* J8 E

评分

参与人数 1 ST金币 +6 收起 理由
MrJiu + 6 赞一个!

查看全部评分

收藏 3 评论4 发布时间:2017-7-20 16:34

举报

4个回答
lijain 回答时间:2017-9-11 09:32:08
楼主你好,我最近也在做esp8266数据传输。做了一个stm32控制的tcp server可以传递数据,但是传递时间有点慢。可以和你讨论一下吗?我的qq是1632401541
MrJiu 回答时间:2017-7-21 11:10:56
个人给个建议,大量代码最好用文件的形式...然后将一些注意的地方,和自己整个开发过程的经验!!!!
zero99 回答时间:2017-7-24 15:03:19
版主说的是,不过还是谢谢楼主分享
wofei1314 回答时间:2017-9-11 11:09:22
Mark....! l; A3 G9 ~4 w% w2 o% l% X( z

5 W- A) ^7 }2 i7 Y: u) ?& [多谢分享

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版