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

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

[复制链接]
zlk1214 发布时间:2017-7-20 16:34
本程序所用的单片机型号为:STM32F103RE9 u' n2 c3 z$ t0 x! `0 o
PB12端口为外接的WiFi模块电源开关,当PB12输出低电平时接通电源。
$ s/ C: i. f; v+ W注意:WM-G-MR-09模块的芯片组(Chip Set)就是Marvell 88W8686。
+ E/ j' r' w7 h6 S* ~$ q该程序目前只能连接没有设密码的路由器,创建热点时也无法设置密码。& @5 j% r/ F/ t! x; e
固件内容请参考:http://blog.csdn.net/zlk1214/article/details/74612925
6 F$ a& \1 |; I" Y; k0 d, p+ R* `! w2 |8 _9 D8 ]. s
注意必须把STM32启动文件*.s中的函数堆栈大小Stack_Size改大,否则函数中无法创建大数组!. M0 r  }6 G, o! |/ P, w
  1. Stack_Size      EQU     0x00000c00  
复制代码
【main.c】) R0 l4 W- T" t
  1. #include <stdio.h>' q; y4 m* Z( B+ {. T$ f, I  ~$ |
  2. #include <stm32f10x.h>
    , [" Z: _: P& h
  3. #include <string.h>" S+ `5 y8 a# [8 f# r
  4. #include "lwip/init.h" // lwip_init函数所在的头文件
    / O9 _" `* o, |* t5 {
  5. #include "lwip/timeouts.h" // sys_check_timeouts函数所在的头文件3 [. @, W* y4 g; [1 O) _
  6. #include "netif/ethernet.h" // ethernet_input函数所在头文件
    % ?, c$ G  R' |& Q! ^+ Y
  7. #include "WiFi.h"- H' E8 _$ ^4 o7 }2 Y9 h

  8. 7 Z6 g! v# F* d4 z. v
  9. // 这两个函数位于ethernetif.c中, 但没有头文件声明
    " i$ ~) h7 W4 ]+ G6 N
  10. err_t ethernetif_init(struct netif *netif);7 {9 v; G, b+ N9 d. s4 V" Q6 [
  11. void ethernetif_input(struct netif *netif);9 \9 s  [0 ?: a4 C( _1 {

  12. , C. I( w. C  a* }
  13. // httptest.c中的函数- O/ L  c( x( S9 ]
  14. void init_http(void);! o' K2 m' Z! N* k" }9 F/ \3 F

  15. ( i4 R/ v/ F( Q  ?; |
  16. // 延时n毫秒, c; y" d# \0 K+ T7 ^4 w; A( \6 Z7 H; B
  17. void delay(uint16_t n)
    5 @$ O) i' s* z4 y' N
  18. {
    3 f' u( N* d) H3 A' f
  19.     WiFi_PrepareTimer(n);. i' Q# o* N" S* D
  20.     while ((TIM6->SR & TIM_SR_UIF) == 0); // 等待计时完毕# y$ W0 r6 N7 W1 t, |. M$ y
  21.     TIM6->SR &= ~TIM_SR_UIF; // 清除溢出标志
    % }! ~2 e, h* a- W
  22. }, ~. Y( o$ n: q/ `, l

  23. 2 M% q+ s8 i3 z2 M9 L# D4 w
  24. void dump_data(uint8_t *data, uint16_t len)5 X2 P" Q' ]+ {& {
  25. {
    * V& u5 ?0 N3 i4 c' ~
  26.     while (len--)& q! x% S9 V- A
  27.         printf("%02X", *data++);
    % p' K& e1 \5 Q. D
  28.     printf("\n");$ G' N) P# W" b. |" T  i, f. S* x
  29. }
    1 |5 x, @( ^, N* d# ]% g0 S; d

  30. 1 U' C+ z$ N; R' ~3 c
  31. int fputc(int ch, FILE *fp)
    3 P+ F: U& r& f  k3 j
  32. {0 ^0 r* h+ U. t3 b/ _
  33.     if (fp == stdout)
    . W+ |: }- e# \+ A2 ?
  34.     {
    0 Y3 e( |( j6 [# ~
  35.         if (ch == '\n')
    ; c# o# j" ]" }
  36.         {: s9 G0 A8 [5 [' N, Z1 y2 [2 H
  37.             while ((USART1->SR & USART_SR_TXE) == 0);
    8 w0 p+ P5 D' Q/ L4 {9 ]
  38.             USART1->DR = '\r';! C+ I, e8 Q7 g% G/ h
  39.         }
    , y; b. x/ R, S3 N: N( X
  40.         while ((USART1->SR & USART_SR_TXE) == 0);
    ' {+ I5 ~5 d- J, d
  41.         USART1->DR = ch;2 U& N/ g  S0 A' J
  42.     }
    4 m& b2 U/ j  @" T
  43.     return ch;" `1 l, {3 n& Y4 o- X8 d
  44. }
    : C& n( v% P* N
  45.   A$ K4 _* E$ ~5 U- m3 i2 y
  46. // RTC时间转化为毫秒数
    ! F4 [; g0 h) h# a+ c1 Y* _
  47. uint32_t sys_now(void)7 x0 e+ M  p8 D' i6 @3 V& L) `
  48. {1 R; j% f. P- u' c% c  F3 X
  49.     uint32_t tmp = (RTC->CNTH << 16) | RTC->CNTL; // 秒
    2 V6 E3 b' m' q, C3 W' H5 S
  50.     tmp = tmp * 1000 + (32767 - RTC->DIVL) * 1000 / 32768; // 毫秒5 v6 w" j. d1 P( z8 L  z
  51.     return tmp;
    ( q- u; `% \  C/ e' b1 m
  52. }
    - u$ k, s9 f- h4 b/ c
  53.   r2 S$ z5 Z7 y/ L. g1 S$ @
  54. int main(void)
    " ~. S& X, ]+ g5 {% `- R
  55. {
    % G! K! x  B2 C: m
  56.     struct ip4_addr ipaddr, netmask, gw;
    % Z1 G" t" K$ \. Y: ]& N
  57.     struct netif wifi_88w8686;
    6 l) [" }% s, q) H1 Q; M4 \3 `
  58.     uint32_t last_check = 0;- \% ?5 N  w" D- O6 U+ c
  59.     # k1 O6 J( ^% x9 a/ V+ ~" N
  60.     RCC->AHBENR = RCC_AHBENR_SDIOEN;
    & o9 W7 h3 K) B8 O* N9 b
  61.     RCC->APB1ENR = RCC_APB1ENR_PWREN | RCC_APB1ENR_TIM6EN;% n: t9 d' t" ^. o
  62.     RCC->APB2ENR = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | RCC_APB2ENR_USART1EN;
    9 x! K; Z+ n8 K
  63.     $ J, \( q& F# S5 P+ \% K3 G
  64.     GPIOA->CRH = 0x000004b0;- k3 O5 ?8 b- |
  65.     GPIOB->CRH = 0x00030000; // PB12为外接的WiFi模块电源开关, PB12=0时打开WiFi模块
    1 E$ }* T% {, c3 V& a' L
  66.     GPIOC->CRH = 0x000bbbbb;( ]6 Z+ `2 |3 ~: w5 m4 N
  67.     GPIOD->CRL = 0x00000b00;
    : D) e" W& L4 ?4 \* @7 \
  68.    
    8 j+ ^0 h. C4 w8 A( q
  69.     USART1->BRR = 0x271; // 波特率: 115200. F7 [3 @: }6 G2 l) f/ x* v0 H
  70.     USART1->CR1 = USART_CR1_UE | USART_CR1_TE;
    0 [0 z5 Q# Q+ X0 v) H1 t
  71.     7 Z. {  i; o. i3 H) x2 a% `, Z
  72.     PWR->CR = PWR_CR_DBP; // 允许写入后备寄存器
    ; D6 j" L' [8 }5 F5 a% k( @& H) H
  73.     if ((RCC->CSR & RCC_CSR_LSION) == 0)0 {7 x/ f  n1 O  ?% x
  74.     {
    6 u9 g9 M& Q" ]8 d$ c* y  S
  75.         RCC->CSR |= RCC_CSR_LSION; // 开内部低速晶振LSI, P2 `& V, U0 C1 V% G. C
  76.         while ((RCC->CSR & RCC_CSR_LSIRDY) == 0);
    ! s# o$ B" a; L. T3 H
  77.         //printf("LSI Ready!\n");' G9 N8 E, E: `" W/ l
  78.     }- L" u2 f1 j" z/ w2 O
  79.     if ((RCC->BDCR & RCC_BDCR_RTCEN) == 0)
    2 z( E8 J2 \& U
  80.     {
    ; O0 }5 Z+ {+ I% F# l+ u
  81.         // 若RTC还没有打开, 则初始化RTC
    3 L& J' b3 F5 O5 X
  82.         RCC->BDCR |= RCC_BDCR_RTCEN; // 打开RTC外设, 但暂不开始走时" w5 X+ l' \* V; X* e+ q, G
  83.         
    $ |& p1 l- K1 E: V; t
  84.         RTC->CRL |= RTC_CRL_CNF; // 进入RTC配置模式) V) m- i2 N( c
  85.         RTC->PRLH = 0;
    ! O3 h( [  ?# q
  86.         RTC->PRLL = 39999; // 定时1s (PRLH和PRLL寄存器只能写不能读)
    1 y& W4 v! E! W/ R
  87.         //RTC->CNTH = 0;
    / s" l* l: c9 m. E. u) r
  88.         //RTC->CNTL = 50; // 初始时间: O- K$ M% b& }) y$ L- ~1 l' l
  89.         RTC->CRL &= ~RTC_CRL_CNF; // 保存设置! y$ `$ f# O. B0 ]
  90.         7 o1 Q; T) X' e5 V. F" s% V+ [1 A
  91.         RCC->BDCR |= RCC_BDCR_RTCSEL_1; // 选LSI作为RTC时钟, 准备走时
    ) {% W+ q' @4 r. B
  92.         while ((RTC->CRL & RTC_CRL_RTOFF) == 0); // 等待设置生效7 Y: [7 r8 u, U7 J. u. f
  93.         // RTC从此处开始走时
    / Q- @& j4 ~* `$ |
  94.     }
    - D. S7 I. }# X$ K
  95.    
    7 d4 L  [$ T1 c) p4 e! j
  96.     WiFi_Init();
    2 S% i: C5 R" \6 w1 S7 h
  97.     WiFi_Scan();: |4 y5 V( B2 w- q' U' A7 n5 I. M
  98.    
    * b$ b, G& [# ~% d2 ^
  99.     //WiFi_StartADHOC("Marvell_88W8686"); // 创建一个热点
    ; u) n  M" H8 d
  100.     WiFi_Connect("vivo Y29L", NULL); // 连接一个WiFi热点 (目前还不支持设密码)0 ^& y+ c' X# c
  101.     " I( _4 n/ J6 r
  102.     lwip_init();( s3 M+ e2 F' X+ U3 E9 {
  103.     IP4_ADDR(&ipaddr, 192, 168, 43, 10); // IP地址
    3 J  d; D* W7 b/ A" d
  104.     IP4_ADDR(&netmask, 255, 255, 255, 0); // 子网掩码
    9 y; v7 A# i) Z# ]
  105.     IP4_ADDR(&gw, 192, 168, 43, 1); // 网关/ r6 v0 V  S  w0 I! a7 n1 T2 o( I
  106.    
    % U5 ?6 C) W7 {$ o* A0 c$ q
  107.     netif_add(&wifi_88w8686, &ipaddr, &netmask, &gw, NULL, ethernetif_init, ethernet_input);* k0 A  x, w$ |/ h! I1 h0 A9 A
  108.     netif_set_default(&wifi_88w8686); // 设为默认网卡, K" y0 S7 v0 F
  109.     netif_set_up(&wifi_88w8686);
    . G/ n6 g# c. c. k
  110.     % Z5 R% n' A7 H5 m' L5 w  R
  111.     init_http();) U3 S6 b9 C* O5 k; O( i) J
  112.    
    % ~3 K' }6 R! C
  113.     while (1)" ]' _' `, f* v/ G% e- Y
  114.     {
    3 `& z# G4 x( G9 o* q
  115.         if (WiFi_PacketPending() || WiFi_PacketArrived())
    9 L8 k2 g' I9 N! X
  116.             ethernetif_input(&wifi_88w8686);
    0 a8 W, ]( R- Q: k: P) M
  117.         - i9 \, B4 X* ]# Y4 N
  118.         // sys_check_timeouts函数千万不能调用的太频繁, 否则会出错!(例如开机后要等1~2分钟DHCP才能分配到IP地址)
    0 |. u/ t) d5 n
  119.         if (sys_now() - last_check > 200)$ m, t2 R+ W( c7 \! E% J$ @
  120.         {
    ' l3 p. O: \+ i) b5 U# Q8 n+ q4 l
  121.             last_check = sys_now();
      a' M9 W$ x- D2 s7 |, v% H8 i
  122.             //printf("Time: %d\n", last_check);  f! ]* Y/ ]: Q. a4 q# Z
  123.             sys_check_timeouts();: \5 A# `' f- x9 K: f7 U
  124.         }- {4 P, W  `: j% L9 b0 ~
  125.     }
    ' a, ~) z: p0 H/ C# s
  126. }
复制代码
【httptest.c】7 Q$ [, {! B4 f' \
  1. #include <string.h>* t! N2 O! @$ X/ D) {4 R9 `
  2. #include "lwip/tcp.h" // 一般情况下需要包含的头文件9 w9 W; F6 J0 g, s6 o, ?
  3. ! G, P, _* b9 d& Z9 @  j
  4. #define STR_AND_SIZE(str) (str), strlen(str)0 U- y" F( f+ E
  5. % j+ r% b5 j/ l
  6. err_t http_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
    7 H! [  w$ K* O; \
  7. {
    ' B1 S$ G/ q! x8 h1 O7 F) L, |
  8.         char len[10]; // 存放HTML内容的长度
    ; t8 ?9 w/ l* ^6 Q; J: K2 M$ G
  9.         char str[200]; // 存放HTML内容
    ; ]* b# Q; h. S8 n' b" {  F
  10.         
    4 g: n0 ~  k7 X5 T2 P
  11.         char name[100];9 ?( Z6 H: A& b) R
  12.         char *pstr;
    8 S5 p# f3 g% B: \. ]& H
  13.         uint8_t i = 0;3 U" p6 k9 M7 u+ R8 s* I
  14.         if (p != NULL)
    8 R: N+ A: ^& L& _
  15.         {8 c- C" q+ e! O6 a5 J0 N
  16.                 // 提取页面名称
    & X6 B5 L" ^/ F, a
  17.                 pstr = (char *)p->payload;
    - K% U# @1 i* j7 o3 a$ P, f
  18.                 while (*pstr++ != ' ');- R) o* G. x& A& X. ]
  19.                 while (*pstr != ' ')
    # w" g7 d5 E; Q, q- {# _- Q7 ~
  20.                         name[i++] = *pstr++;
    4 o8 D; y9 r; Z! o& T7 X
  21.                 name[i] = '\0'; // 不要忘了结束name字符串
    9 Z4 W" K2 T# ?4 Z3 c
  22.                 tcp_recved(tpcb, p->tot_len);6 i, r, J* o+ z3 o6 G
  23.                
    7 a  Q1 V; S2 ^0 U+ p$ W7 L
  24.                 // 生成HTML内容
    ( [, N& K& h) t# m  d4 Y& `' c
  25.                 sprintf(str, "<meta charset="gb2312"><title>获取网页名称</title><div style="font-family:Arial"><b>请求的网页文件名称是: </b>%s</div>", name);. O! i1 @6 o, P4 [2 {
  26.                 6 ]9 P, k+ q% H) z
  27.                 sprintf(len, "%d", strlen(str)); // HTML内容的长度
    1 O: C2 r& d' H( @
  28.                 tcp_write(tpcb, STR_AND_SIZE("HTTP/1.1 200 OK\r\nContent-Length: "), TCP_WRITE_FLAG_MORE);
    % O' L# b) X7 o" P; u
  29.                 tcp_write(tpcb, STR_AND_SIZE(len), TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);1 g* q( c. F# D/ R" N
  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);( P( \6 n" h2 Y6 \$ L8 _9 b& Z" Z
  31.                 tcp_write(tpcb, STR_AND_SIZE(str), TCP_WRITE_FLAG_COPY); // 发送HTML内容9 O$ s# B, U1 i8 R5 C" p& L  r
  32.                 pbuf_free(p);
    1 q, H) W& t( E- k0 W
  33.         }3 J/ H) [; I& B  B  ]
  34.         return ERR_OK;! }9 k) f* {. d1 e% h; n
  35. }
    + U0 s0 A: K, b1 k4 e5 c

  36. , S/ j/ }, P* \! ]  X# ^: {- x
  37. err_t http_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
    + H- G1 V3 h6 u7 D7 U
  38. {
      I$ E" g  E- n2 }- u
  39.         tcp_recv(newpcb, http_recv);
    . b" c6 S& {7 @. m- V6 n
  40.         return ERR_OK;+ B0 [! t+ v! C0 R
  41. }
    - W0 H9 n/ s# B9 B! W  q

  42. ( l& C; W8 M; ?3 B* d1 F  n2 t) H
  43. void init_http(void), d7 ?7 E" O$ ~' N
  44. {
    + ^* a) W1 z7 @9 A
  45.         struct tcp_pcb *tpcb = tcp_new();
    9 i4 `  _. e% n% y
  46.         tcp_bind(tpcb, IP_ADDR_ANY, 80);1 w0 d( k* l' |: t/ b% n
  47.         tpcb = tcp_listen(tpcb);' c2 }' f, v. ]/ X$ [& T# Z- k" r1 ^
  48.         tcp_accept(tpcb, http_accept);
    0 y& ]/ c5 D3 H$ p3 |" A
  49. }
复制代码
【WiFi.h】
  p9 e# t, |- z, S- G. ^8 L7 ^( Y
  1. #define _BV(n) (1u << (n))5 B! z# j) a- b

  2. . D& O+ d1 R9 ~4 i6 H
  3. #define CMD52_WRITE _BV(31)
    % E2 S  ]: ]' e1 X5 p; q4 L) [
  4. #define CMD52_READAFTERWRITE _BV(27)1 t0 m! y3 w; [; i! o# m( {* |! W

  5. ; c* b: z( d  j4 R
  6. #define CMD53_WRITE _BV(31)
    8 b$ w! D. K  q( ^, i; Y
  7. #define CMD53_BLOCKMODE _BV(27)5 T8 a+ u/ h: `
  8. #define CMD53_INCREMENTING _BV(26)3 H+ c$ D7 O$ Z9 ~9 M- z

  9. 9 S- r$ q0 u3 J1 y3 H' y
  10. // 16.5 SDIO Card Metaformat
    7 ]: V7 d5 _8 D8 a" \1 \, e
  11. #define CISTPL_NULL 0x00 // Null tuple
    " X% C2 S7 e& X6 h
  12. #define CISTPL_VERS_1 0x15 // Level 1 version/product-information5 s/ J3 {$ f' C. `% k
  13. #define CISTPL_MANFID 0x20 // Manufacturer Identification String Tuple
    % O8 j- R0 x7 \) Z
  14. #define CISTPL_FUNCID 0x21 // Function Identification Tuple
    ' z& |) D: a) I4 g2 [( _
  15. #define CISTPL_FUNCE 0x22 // Function Extensions5 \: L+ ?4 Z- k- f1 b: F- ~; J% e
  16. #define CISTPL_END 0xff // The End-of-chain Tuple
    # y* o/ N) \: [6 q6 }, [5 l
  17. * }% n$ \% ~+ X3 ^" S5 p2 [* i8 t
  18. #define WIFI_DEFAULTTIMEOUT 1500 // WiFi命令回应的超时时间(ms)! {) t0 _( ]- J( }7 _

  19. : M0 |9 A3 o& W" _4 F; u; R
  20. #define WIFI_SQREADBASEADDR0 0x105 _9 j, c  S, y6 d0 x% w7 w
  21. #define WIFI_SQREADBASEADDR1 0x114 v- d" }# Z4 e# R/ k0 `( P5 a
  22. #define WIFI_SQREADBASEADDR2 0x123 m+ q4 X$ n# }, r/ Y9 _7 \6 m7 F
  23. #define WIFI_SQREADBASEADDR3 0x13/ V2 [9 P3 N5 M& f" ~+ L# Q

  24. 8 j- B2 j7 }# I' g( h0 Y
  25. #define WIFI_CARDSTATUS 0x20 // Card Status# i, q1 ?4 f1 J) d
  26. #define WIFI_CARDSTATUS_IOREADY _BV(3) // I/O Ready Indicator9 A5 a( g! f8 z) ?5 N2 q
  27. #define WIFI_CARDSTATUS_CISCARDRDY _BV(2) // Card Information Structure Card Ready
    ( r3 t: |3 P# C# s
  28. #define WIFI_CARDSTATUS_UPLDCARDRDY _BV(1) // Upload Card Ready; g1 K# i; l7 u  _* y1 \' L7 t" o
  29. #define WIFI_CARDSTATUS_DNLDCARDRDY _BV(0) // Download Card Ready+ I  S, ]% o( p; j/ @; X
  30. 6 E, L4 O/ F+ r- H8 S5 Q
  31. #define WIFI_CAPABILITY_BSS _BV(0)# ?  w+ N7 M) m4 {, T  J6 V
  32. #define WIFI_CAPABILITY_IBSS _BV(1)
    / J& N% K) L' M" k8 L
  33. #define WIFI_CAPABILITY_CF_POLLABLE _BV(2)0 t% |. b5 L3 U1 i+ I% `7 b/ w
  34. #define WIFI_CAPABILITY_CF_POLL_REQUEST _BV(3)! |$ x; F% g! r
  35. #define WIFI_CAPABILITY_PRIVACY _BV(4)* q' l: P6 U+ g( m7 e* [
  36. #define WIFI_CAPABILITY_SHORT_PREAMBLE _BV(5)
    ! f: W* K  s% D9 O' M* X9 ?
  37. #define WIFI_CAPABILITY_PBCC _BV(6)4 o: u3 _3 s# r. G. g) Q
  38. #define WIFI_CAPABILITY_CHANNEL_AGILITY _BV(7)" M3 {* s$ I. w
  39. #define WIFI_CAPABILITY_SPECTRUM_MGMT _BV(8)
    + l! @" D/ H( B3 p) k
  40. #define WIFI_CAPABILITY_QOS _BV(9)
    0 L* V$ f- h' v, v
  41. #define WIFI_CAPABILITY_SHORT_SLOT _BV(10)8 S( p  Z3 `, s  a; y; D' @
  42. #define WIFI_CAPABILITY_DSSS_OFDM _BV(13)
    - u# z) N1 J$ l6 Q4 U6 i3 f$ ]/ I

  43. 0 i! d1 V, z: c, L+ i  j( P  X
  44. #define WIFI_SDIOFRAME_DATA 0x00
      [3 g1 s) p# w3 j+ [/ T2 O
  45. #define WIFI_SDIOFRAME_COMMAND 0x01
    , ~- f3 ~; G/ r) k5 b$ k
  46. #define WIFI_SDIOFRAME_EVENT 0x03
    0 M6 W- K- E9 l3 Z" C; ]

  47. 4 q& r- `: L" ?) K& @7 q
  48. /* Command List */9 t8 }* }5 H2 L' u. o# T, L) J
  49. #define CMD_802_11_SCAN 0x0006 // Starts the scan process
    4 P) Y$ d- q/ i3 S8 t
  50. #define CMD_802_11_ASSOCIATE 0x0012 // Initiate an association with the AP) V1 B/ V3 H, V7 ~. z' u
  51. #define CMD_MAC_CONTROL 0x0028 // Controls hardware MAC7 `* v0 Z% D8 T8 d8 j
  52. #define CMD_802_11_AD_HOC_START 0x002b // Starts an Ad-Hoc network
    ( n7 T" @( V0 D+ Z
  53. #define CMD_802_11_MAC_ADDR 0x004d // WLAN MAC address  J% T; S- B. v+ E2 e
  54. #define CMD_802_11_KEY_MATERIAL 0x005e // Gets/sets key material used to do Tx encryption or Rx decryption6 q, `* V* i: a) v; `6 h2 H6 g& L7 B2 g; J
  55. #define CMD_802_11_BG_SCAN_CONFIG 0x006b // Gets/sets background scan configuration
    9 N8 Y1 E! P) D% y! @0 M# ]. M1 ^  I
  56. #define CMD_802_11_BG_SCAN_QUERY 0x006c // Gets background scan results
    0 @# D5 o; z. W) l( t
  57.   o: A5 \% L0 l" J. s: C# m& g% n
  58. /* Command Result Codes */8 R6 a, W; C- s, L. M. _
  59. #define CMD_STATUS_SUCCESS 0x0000 // No error( l8 d/ a& i* Y) l' N' ~3 _
  60. #define CMD_STATUS_ERROR 0x0001 // Command failed. }- A  y$ U7 z; A6 ~: c
  61. #define CMD_STATUS_UNSUPPORTED 0x0002 // Command is not supported2 d, N2 y! p$ j7 T6 g# r3 |

  62. : J- D7 S3 j! }% v8 n
  63. #define WIFI_ACT_GET 0
    5 W- O) I7 u! P' O4 h% }6 u- _
  64. #define WIFI_ACT_SET 10 |: Z$ C! y, ^9 j5 t
  65. 4 |+ o+ K- h3 b& E3 Z) H5 {+ q
  66. /* Authentication Type to be used to authenticate with AP */
    ) e! v* a9 Q: ]2 m+ D0 a
  67. #define AUTH_MODE_OPEN 0x00
    % r. R( Z* K7 X. t9 O9 y
  68. #define AUTH_MODE_SHARED 0x01
    ( Y* G2 C! L3 m" F5 X+ {
  69. #define AUTH_MODE_NETWORK_EAP 0x80
    . H$ ~' i. W5 n7 ~, _

  70. # |( B7 j2 z: `, u0 A5 L
  71. /* WiFi_Associate return value */; Z- Z2 A/ T, @" H. P
  72. #define WIFI_ASSOCIATION_NOTFOUND 0xfffe
    # S8 u* O# W9 s. U/ \
  73. #define WIFI_ASSOCIATION_ERROR 0xffff
    # ~* j4 N. h! K# q' G0 W' Y
  74. #define WIFI_ASSOCIATION_SUCCESS 0x0000 // 连接成功; }, _% t; U5 A9 M$ f8 r
  75. #define WIFI_ASSOCIATION_INTERNALERROR 0x0101
    : L7 E4 j5 j6 m3 }, T
  76. #define WIFI_ASSOCIATION_AUTHUNHANDLED(ret) (((ret) & 0xff00) == 0x200) // 未处理的认证帧2 ]) B. u8 x+ [2 ~; ^( f
  77. #define WIFI_ASSOCIATION_UNSUPPORTEDAUTHALG 0x0213
    & A  b: W/ ~4 I; X; {# s; K4 ^- U; K
  78. #define WIFI_ASSOCIATION_INVALIDSEQUENCENUMBER 0x0214
    . D( }+ g2 J# Z. x/ D5 T
  79. #define WIFI_ASSOCIATION_AUTHREFUSED(ret) (((ret) & 0xff00) == 0x300) // 认证失败
    9 u, m" f, L& G6 ]
  80. #define WIFI_ASSOCIATION_TIMEOUT(ret) (((ret) & 0xff00) == 0x400) // 超时# a1 w5 U$ [; _1 |. ^
  81. #define WIFI_ASSOCIATION_ASSOCTIMEOUT 0x0401 // 连接超时# x% u( H2 ?( p% E! Y! F2 Z
  82. #define WIFI_ASSOCIATION_AUTHTIMEOUT 0x402 // 认证超时- H7 O1 D/ a6 L3 f
  83. #define WIFI_ASSOCIATION_NETWORKJOINTIMEOUT 0x403 // 加入网络时超时
    # j5 H! `& h% @& V' g4 F$ D' l( v

  84. 4 R" U8 S$ I% A
  85. #define WIFI_KEYTYPE_WEP 0
    - e& W$ E; S$ t/ X
  86. #define WIFI_KEYTYPE_TKIP 1& O! h( a' m: Y( _4 k- Y  o2 v
  87. #define WIFI_KEYTYPE_AES 2' S  E8 O1 o) J
  88. 2 Z" O, G8 A, D
  89. #define WIFI_KEYINFO_KEYENABLED _BV(2)& j& `( Q3 n# \7 @; ^$ s4 r& `
  90. #define WIFI_KEYINFO_UNICASTKEY _BV(1)
    2 M1 g2 ]  k* X8 z' J
  91. #define WIFI_KEYINFO_MULTICASTKEY _BV(0)
    : I4 a, u- Z/ T- x
  92. 8 R: K! }  g" z1 }
  93. #define WIFI_MACCTRL_RX _BV(0)1 M3 a* V1 C" p, Q  H
  94. #define WIFI_MACCTRL_TX _BV(1) // 此位必须要置1才能发送数据!!!
    0 g6 P: R/ ]. B% F! X
  95. #define WIFI_MACCTRL_LOOPBACK _BV(2)- a+ ^( K# ?. \' X
  96. #define WIFI_MACCTRL_WEP _BV(3)
    7 l" h4 W. k0 w, Q
  97. #define WIFI_MACCTRL_ETHERNET2 _BV(4)
    9 c( b( u/ v$ v- q! g9 t+ G2 b7 i1 h
  98. #define WIFI_MACCTRL_PROMISCUOUS _BV(7)
    ) d/ w, k* e4 P, b0 \7 Z. x- Y
  99. #define WIFI_MACCTRL_ALLMULTICAST _BV(8)( V( M& z! q; _  @4 @( ~: v
  100. #define WIFI_MACCTRL_ENFORCEPROTECTION _BV(10) // strict protection
    7 ~+ w2 _& b+ T
  101. #define WIFI_MACCTRL_ADHOCGPROTECTIONMODE _BV(13) // 802.11g protection mode: C4 m( Z/ |& ^- N7 u! k

  102. / f/ v+ u3 ~5 `& [5 Y; P) E$ i5 o
  103. /* BSS type */5 K" Z& n" X; b& X
  104. #define BSS_INFRASTRUCTURE 0x01% r5 q2 _9 G: B7 F4 ?
  105. #define BSS_INDEPENDENT 0x02
    ) N- v* G6 S9 |. |
  106. #define BSS_ANY 0x03) X3 l0 K/ h( f' L* H' }7 c1 I
  107. 0 i, c( E; R5 N- D' E, @
  108. /* Table 45: IEEE 802.11 Standard IE Translated to Marvell IE */5 _( i' B/ r2 B: i+ K4 j: l
  109. /* PDF中的表45有一些拼写错误, MRVIIE应该改为MRVLIE */
    . x3 y' ?3 E: \0 |9 {  T7 @
  110. #define MRVLIETYPES_SSIDPARAMSET 0x0000* m5 P5 P& x2 l3 a8 Y
  111. #define MRVLIETYPES_RATESPARAMSET 0x0001
    1 V) V3 P$ D% _& c. d( n. t
  112. #define MRVLIETYPES_DSPARAMSET 0x0003
    ' g+ M; w3 x% z# o
  113. #define MRVLIETYPES_CFPARAMSET 0x0004
    + [7 ?8 i6 a0 N/ G; C( Y
  114. #define MRVLIETYPES_IBSSPARAMSET 0x0006* S7 Q/ X( a( L3 z- d) x
  115. #define MRVLIETYPES_RSNPARAMSET 0x0030
    " u* X2 @/ \5 |$ u/ ?: q0 e* J9 Y
  116. #define MRVLIETYPES_VENDORPARAMSET 0x00dd
    1 W* p* p' o7 d9 `' V8 j# y

  117. 0 h0 t5 I# O$ Y0 c% t
  118. #define MRVLIETYPES_KEYPARAMSET 0x0100! B9 j3 _1 U1 T* q; h0 Z7 \7 {
  119. #define MRVLIETYPES_CHANLISTPARAMSET 0x0101
    # G* z* V% V5 X$ p+ }; v3 h3 d4 U
  120. #define MRVLIETYPES_TSFTIMESTAMP 0x0113
    $ g5 ~8 d& a7 h. h+ J6 E. O+ z
  121. #define MRVLIETYPES_AUTHTYPE 0x011f
    ( U  p4 C1 [" Z2 W
  122. # D% N' N& D1 b- K
  123. #define MRVLIE_PAYLOADLEN(s) (sizeof(s) - sizeof((s).header)) // 已知结构体大小sizeof(s), 求数据域的大小
    2 z0 H) p- L5 Z! U& f
  124. #define MRVLIE_STRUCTLEN(s) (sizeof((s).header) + (s).header.length) // 已知数据域大小, 求整个结构体的大小
    5 q: m: b2 S4 D9 v# l
  125. . B' M  q& Z' D8 [
  126. typedef __packed struct, T- B4 [8 |# W3 S
  127. {9 a* L0 y6 C2 Y! W5 E- F; k. y5 o. [
  128.         uint8_t type;' C+ h# }/ H8 C+ i4 u
  129.         uint8_t length;
      z0 m& r7 t" d8 a+ H8 ]' g
  130.         uint8_t data[1];' u2 _1 ]: u( c: M& j
  131. } IEEEType;
    ; K+ j- x. F1 U0 Z! b

  132. ; ~4 g2 R1 b2 C0 K3 [3 i" Q# n
  133. typedef __packed struct4 d  N% L" x5 D' N9 f* u
  134. {
    5 n, p5 V1 J+ Z+ R( X1 a1 Y
  135.         uint16_t ie_length; // Total information element length
    , `7 x: P. [+ J" H" R: ]
  136.         uint8_t bssid[6]; // BSSID
    ' N' @3 e" x1 u% {8 Q% @
  137.         uint8_t rssi; // RSSI value as received from peer
    5 X& ]2 w% ], l) [1 X
  138.         0 _& F- x3 y8 H0 `
  139.         /* Probe Response/Beacon Payload */
    ! S# ^6 _. Q; {$ V
  140.         uint64_t pkt_time_stamp; // Timestamp
    # f+ q3 J* Y1 p4 |3 K9 Q& H9 ^0 g
  141.         uint16_t bcn_interval; // Beacon interval
    * ]+ T. u) f. B" e
  142.         uint16_t cap_info; // Capabilities information
    ' F4 b% \' t9 j4 H/ I
  143.         IEEEType ie_parameters; // 存放的是一些IEEE类型的数据
    * V5 J5 e. j( t$ Y' @
  144. } WiFi_BssDescSet;
    ' U# ~9 K' {: F9 J5 C# C- Q

  145. + ~2 M( g% G6 Y5 h# X6 v. K0 i' d
  146. typedef __packed struct
    9 {1 ^6 u! ~. A4 v( T0 D; l3 u' m
  147. {$ J5 I0 Q% w$ I" C2 V( ^( c& S
  148.         uint8_t oui[3];
    8 {) ], _. O& g# }  F7 V
  149.         uint8_t oui_type;" z4 |$ p4 z+ Q  `
  150.         uint8_t oui_subtype;
    . s9 B$ N2 O  N) |1 m+ o
  151.         uint8_t version;" L" J& _, X6 o$ l
  152. } WiFi_VendorHeader;% i. U: ?  e- W  r

  153. 3 X' Z4 x7 V! S( ?
  154. typedef __packed struct
    ) o7 y( }1 a2 _
  155. {
    8 O  L: ]% ~" Y4 F$ @
  156.         uint16_t type;
    8 g& M& w# C  K- N  y
  157.         uint16_t length;
    3 b' H0 |, a4 s8 I) h) V- p
  158. } MrvlIEHeader;
    ! |0 c$ \4 x8 Y9 h
  159. " ^  b" b# h' j- ?, P$ n/ f
  160. typedef __packed struct; F8 j) a8 B( d' R2 |. O* ~  k
  161. {
    8 b/ i8 J- O. t1 G
  162.         MrvlIEHeader header;$ V4 t1 l- p+ H. q0 w- w0 G
  163.         uint16_t auth_type;
    3 _& f. W3 H# x
  164. } MrvlIETypes_AuthType_t;
    + ]+ h! M: S5 J4 y; Y

  165. 7 d& d. m9 ?5 F( |" F2 |8 r
  166. typedef uint16_t MrvlIETypes_CapInfo_t; // Section 7.3.1.4: IEEE 802.11-1999 Spec- I. B( Q. D+ p" Y

  167. - Y: z& F2 T& h% ^
  168. typedef __packed struct; v! U& E3 F. g7 _1 K+ Q
  169. {
    * q! h0 \" D* x2 u0 L/ \
  170.         MrvlIEHeader header;1 p6 R9 q' b3 ]9 [! }% S7 K9 [
  171.         uint8_t count;
    0 F4 z$ ]! f2 n" l5 A; a6 P1 U
  172.         uint8_t period;
    3 r/ h/ a/ G* w4 w" i1 b& V$ @
  173.         uint16_t max_duration;& {/ x, b+ B# Y; m! d# }
  174.         uint16_t duration_remaining;
    ! I3 D. }6 O9 v. A7 n6 _, h
  175. } MrvlIETypes_CfParamSet_t;
    ' H$ z/ Y) D: l7 t4 n! Q
  176. ' K- h9 q* X$ A! `: D
  177. /*typedef __packed struct
    % I! m; v! K+ t: P3 Z, X
  178. {  s7 }* n$ ?' y: N: `
  179.         MrvlIEHeader header;
    ! E& |" L- H* m' _( h0 q
  180.         __packed struct
    1 J2 ^& h- n* X2 w. L- X* R6 I) D9 g
  181.         {' ]+ a4 \* i; [! A" P- n
  182.                 uint8_t band_config_type;
    8 P" H" V' J5 ]) B6 U2 n* t  A
  183.                 uint8_t chan_number;
    9 c, H% [7 X7 G( |& \$ Q: A
  184.         } channels[1];% |& f+ I. K# v* j& |0 }( M) N
  185. } MrvlIETypes_ChanBandList_t;*/
    0 y+ ~0 n' j4 z( U
  186.   [$ }7 R4 `9 E# R8 e9 E
  187. typedef __packed struct
    + r! U% C2 B/ j& e
  188. {+ I/ z" P/ j" |* ?
  189.         MrvlIEHeader header;, H; }6 m. m7 E# X/ D
  190.         __packed struct
    : }: a5 D0 l8 k( {4 y( |
  191.         {  i( R$ g. M- z  h7 k; F1 p4 \
  192.                 uint8_t band_config_type;
      w1 f! @; k/ J% E* k
  193.                 uint8_t chan_number;
    / _+ @+ m& [, R# ~( x
  194.                 uint8_t scan_type;
    ' ?0 n4 n5 ~- ^' w$ V0 A. h" `- n
  195.                 uint16_t min_scan_time;: l" L, h( X# a0 Z9 m# e
  196.                 uint16_t max_scan_time;
    3 ^% y* s9 c( S* ]" Z& l0 F
  197.         } channels[1];
    0 N' X. a8 t) p3 }$ y* w
  198. } MrvlIETypes_ChanListParamSet_t;
    4 ?8 d, R1 k9 R: {8 \' d
  199. ' H5 [# J3 y& L
  200. typedef __packed struct2 ]' I4 U6 M5 v% B
  201. {6 y4 \2 Q1 v/ Z# A  J1 p
  202.         MrvlIEHeader header;# o8 q( v, `; w
  203.         uint8_t channel;
    : z; Y* s( ~' ~- S: w
  204. } MrvlIETypes_DsParamSet_t;
    ; {) A9 J/ _( [2 ]' q) m

  205. - V2 N" T' v6 H6 h* ^* x  ~
  206. typedef MrvlIETypes_DsParamSet_t MrvlIETypes_PhyParamDSSet_t;
    * ^1 X6 _* c0 L& v2 `

  207. / ^9 n/ `& o: u$ g( t) q
  208. typedef __packed struct' p# |# T4 C7 V$ f/ H$ Z* ~
  209. {
    7 a: ~7 h! F; L" }: k, u7 g
  210.         MrvlIEHeader header;
    / f: @8 e# Z5 D" q
  211.         uint16_t atim_window;# e# [5 c9 k, h! h8 n1 s( ~! r/ R- ^
  212. } MrvlIETypes_IbssParamSet_t;: R( I6 P: j1 r9 G
  213. / N2 |! N6 k# y8 q" A0 ^, y
  214. typedef __packed struct
    ( {4 D& Z( I/ Q$ L4 y
  215. {. G4 ?- N2 v) h( y: B: Q  R. R/ e
  216.         MrvlIEHeader header;" x/ b) `+ u2 K. r
  217.         uint16_t key_type_id;* }, ]- p3 w" i$ |5 J: J. n, O
  218.         uint16_t key_info;
    $ W8 S* _: n8 ^% k! q$ P9 J
  219.         uint16_t key_len;" L6 z* k8 f8 M. E
  220.         uint8_t key[32];* R+ O) t( T3 N+ f9 Z" ?% C2 {
  221. } MrvlIETypes_KeyParamSet_t;
    * }9 y5 x% B' M8 u1 d+ Q4 O: `3 Q3 b
  222. 4 s& X9 \- u0 A5 k' Q# E
  223. typedef __packed struct! M6 B5 p: q* Y8 J# ?$ @
  224. {
    : V- I% E& A! o$ E8 m
  225.         MrvlIEHeader header;* \: @2 H, X& W( f! x
  226.         uint8_t rates[14];
    9 r: {$ i0 s2 t+ m
  227. } MrvlIETypes_RatesParamSet_t;
    " m3 r" ]/ K+ _6 g! ~2 `1 X! Q
  228. , `8 w( {- n$ K: [' K% G
  229. typedef __packed struct2 B$ J5 E  R1 H" V+ z$ Y  g
  230. {+ @) X) V4 o' l9 R: p' T& K9 v
  231.         MrvlIEHeader header;
    , T" u+ E4 F8 t, ?$ f6 O. C
  232.         uint8_t rsn[64];- f4 o' w9 \8 i3 |  [; Y
  233. } MrvlIETypes_RsnParamSet_t;- Q. g% K) L1 N: m9 R
  234. - h0 ]- s+ Z) B4 @
  235. typedef __packed struct; O; e, }% ]8 v" t! f  {# z
  236. {) z/ m. b$ v$ T; j+ o6 a& |: u7 S
  237.         MrvlIEHeader header;$ T3 Y5 O5 p+ q( c) Z" j
  238.         uint8_t ssid[32];
    ; r9 Q1 @9 {/ G5 `1 {6 Y
  239. } MrvlIETypes_SSIDParamSet_t;
    0 C5 o: r, ^* e' q7 H8 o5 M0 A: h

  240. & }* o: G; L9 }' B" k* X9 K9 }
  241. typedef __packed struct4 S, p! V$ Q7 x5 i6 g  w( `/ d
  242. {; J4 H0 M; o* X8 P4 f  x
  243.         MrvlIEHeader header;- m+ h' C1 ^9 E  c' [1 h' i
  244.         uint64_t tsf_table[1];
    : g0 I2 }) E# h3 y5 Z, N# R
  245. } MrvlIETypes_TsfTimestamp_t;
    1 v* m" y' u' H& s: p

  246. ; b& }  p, v7 i7 p" l  H' L3 j. k
  247. // 整个结构体的最大大小为256字节! [: H& j5 O: @( n$ S' l
  248. typedef __packed struct
    3 s" ^9 b5 \1 |* B
  249. {# @3 P/ E3 ~; B! T6 K6 T; P& }8 ]
  250.         MrvlIEHeader header;" U3 @( e$ u+ }/ c6 d
  251.         uint8_t vendor[64]; // 通常情况下64字节已足够
    + a1 X6 e5 X% l
  252. } MrvlIETypes_VendorParamSet_t;& j. i/ z- F5 X, E

  253.   l  t' L/ J" t- R1 L) J, F
  254. typedef __packed struct
    0 `) T: Q* S7 N$ k
  255. {
    & ~9 V% N, E# ]( m7 @7 Q% o+ P
  256.         uint16_t length;+ n+ Z+ m9 }( m: ?4 i
  257.         uint16_t type;' B, H4 V+ D/ v; `# ~/ S
  258. } WiFi_SDIOFrameHeader;
    8 c# k# B+ l3 j& H; l
  259. . n2 R/ k2 B# A
  260. typedef __packed struct
    $ g% V, |( A1 r$ y; S
  261. {
    " Z8 T6 Q9 Y( ~
  262.         WiFi_SDIOFrameHeader frame_header; ) D7 {: M/ b1 {) X6 v/ V3 h
  263.         uint16_t cmd_code;# A/ G& ?$ s5 H; X( D
  264.         uint16_t size;( e7 N9 q- \: d7 k" V, d. R
  265.         uint16_t seq_num;  S0 x; P. g- _- b" H+ U% j
  266.         uint16_t result;
    / W5 W( g2 r$ B, H3 J. c  Z* \
  267. } WiFi_CommandHeader;6 W" \9 M$ ^# x% r0 M/ O
  268. & m* W- y0 c1 f" }9 F) P$ ?
  269. /* Table 2: Fields in Receive Packet Descriptor */
    ; s! v& C5 \# Y8 K& @- a1 J# X1 L
  270. typedef __packed struct
    # v" {  Y  U. z, B- D2 Z: j5 m
  271. {, L9 p  H8 a1 T
  272.         WiFi_SDIOFrameHeader header;; h: x' F7 G) x* `+ D7 z
  273.         uint16_t reserved1;5 B* `  ^  v3 E4 W5 N
  274.         uint8_t snr; // Signal to noise ratio for this packet (dB)
    4 R7 z3 Q$ ~  P5 p
  275.         uint8_t reserved2;
    6 j, B+ E/ x/ j# a  I: W8 d
  276.         uint16_t rx_packet_length; // Number of bytes in the payload
    # ?9 r* X1 N: |( `- J. e1 D" q
  277.         uint8_t nf; // Noise floor for this packet (dBm). Noise floor is always negative. The absolute value is passed.
    2 K4 Q! u& x. o+ ~, Y
  278.         uint8_t rx_rate; // Rate at which this packet is received1 H* t& E7 U2 e
  279.         uint32_t rx_packet_offset; // Offset from the start of the packet to the beginning of the payload data packet7 n2 R" H9 d# u  @  g1 d; M8 q+ H& L
  280.         uint32_t reserved3;  s& y, L& m1 c! p
  281.         uint8_t priority; // Specifies the user priority of received packet
    ) C" D0 y: a- Y" t* e
  282.         uint8_t reserved4[3];0 V+ i9 R9 \1 N3 [) @* j
  283.         uint8_t payload[1]; // 数据链路层上的帧# O2 m& [* J5 U! L$ O1 ]
  284. } WiFi_DataRx;0 x1 Q" y7 ]4 z4 F: K/ M. g
  285. ( _7 T( m3 f+ x. ~0 I" [0 J
  286. /* Table 3: Fields in Transmit Packet Descriptor */: `* D0 }6 ]( o) j( J& L
  287. typedef __packed struct
    - u, ]) p% S8 I* F5 X* r
  288. {
    - J, p; V& U2 C+ E9 ^
  289.         WiFi_SDIOFrameHeader header;
    6 |1 V5 c  Q% {( p+ s. Q
  290.         uint32_t reserved1;4 _- r( v' W; O- {$ _- U
  291.         uint32_t tx_control; // See 3.2.1 Per-Packet Settings
    " _1 K0 {5 o9 l4 I. |# X  T/ M0 }
  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)+ F6 ^9 E2 ^  E/ c, U/ v; e
  293.         uint16_t tx_packet_length; // Number of bytes in the payload data frame( e; Y& E% I: j( D* b. P1 z2 p, T$ }3 L
  294.         uint16_t tx_dest_addr_high; // Destination MAC address bytes 4 to 5
    ( z. D% I: ]8 B& V1 k/ F( ^# ^+ I
  295.         uint32_t tx_dest_addr_low; // Destination MAC address bytes 0 to 3/ K( @: ~* `5 U
  296.         uint8_t priority; // Specifies the user priority of transmit packet
    5 \9 Y8 t  ?5 y9 z! a+ p' ]/ W+ k5 o
  297.         uint8_t flags;  m$ m: e4 k+ {
  298.         uint8_t pkt_delay_2ms; // Amount of time the packet has been queued in the driver layer for WMM implementations# H% \' q) m/ ^, @  Z; `
  299.         uint8_t reserved2;
    1 [3 ?; W6 k1 U+ n7 W& u
  300.         uint8_t payload[1]; // 数据链路层上的帧
    4 T1 M# ]! _0 ]0 i
  301. } WiFi_DataTx;
    6 ~3 k9 d6 q! f& t: [9 H4 g

  302. $ C/ j' j. B7 N; d7 u
  303. typedef __packed struct
    + f# E1 i% s/ H; a; F
  304. {
    . W! k! F7 Z% A! H
  305.         WiFi_CommandHeader header;2 F, K( n+ @/ e, B" j( p
  306.         uint16_t action;
    4 k! y, l! W$ e/ ?& N  c& a* h
  307. } WiFi_Cmd_KeyMaterial;
    , ?6 X9 K% I  I* P9 Q, R1 l% Q% l. R: O

  308. / E' f7 j0 d5 P5 t- @7 I
  309. typedef __packed struct* {8 Z$ m/ s6 f
  310. {+ p# B% T$ Q" c% Q, {1 _; n' P
  311.         WiFi_CommandHeader header;
    4 h6 W  {+ E# H" K  @' `
  312.         uint16_t action;, L" u/ L, F" M7 ]  F# M0 E
  313.         uint8_t mac_addr[6];
    8 o$ A; g2 _' L( X! z/ P2 ?
  314. } WiFi_Cmd_MACAddr;
    + U8 [) q% a1 Q4 N3 \- j" e) }

  315. 0 c. h- X4 v, u. N# k: K3 J/ J. F
  316. typedef __packed struct5 B9 F$ L- ~. c7 @- x( [
  317. {
    + z, H! c' y: |$ {3 c; E9 h* I
  318.         WiFi_CommandHeader header;
    8 K; {% a% U  e* \
  319.         uint16_t action;
    3 c" H, z+ t0 _
  320.         uint16_t reserved;
    3 y; ^& H* u( d) h
  321. } WiFi_Cmd_MACCtrl;5 g) L; k) H. k+ Q! ^. s: m! s

  322. : U) o" t3 k& X
  323. typedef __packed struct
    4 a0 a% \% l) a- ^$ O, Q
  324. {) n7 i. w  b- H& \- Y' x
  325.         WiFi_CommandHeader header;& L) G# J) Z' V' h. r( ?( f* v
  326.         uint8_t ssid[32];
    3 D( p6 d; l9 r
  327.         uint8_t bss_type;. u3 U, V0 f2 r% y. A- E9 R
  328.         uint16_t bcn_period;
    4 L5 J% e! a+ B& L) W
  329.         uint8_t reserved1;: }+ d( Q# ]0 b& c2 W6 ]" T
  330.         MrvlIETypes_IbssParamSet_t ibss_param_set; // ATIM window length in TU/ K6 \9 J8 o6 y3 b) o5 L* d
  331.         uint32_t reserved2;
    7 K' N" i% @3 m- o
  332.         MrvlIETypes_DsParamSet_t ds_param_set; // The channel for ad-hoc network; _( z3 l& Y2 B( z
  333.         uint16_t reserved3[3];- G. b7 E6 o1 E
  334.         MrvlIETypes_CapInfo_t cap_info; // Capability information+ j# e; _6 r2 \& c! m+ B
  335.         uint8_t data_rate[14];: o5 B& T! f% d* H5 W& v7 ?# Q! h
  336. } WiFi_CmdRequest_ADHOCStart;/ I3 \/ d1 i0 c0 x* ?7 s
  337. : I' ]# F  ]: b' V9 Z
  338. typedef __packed struct8 _* p& t, a: o% Z
  339. {/ {# d5 P7 A' D' }8 L$ h& N# t' I7 F- U
  340.         WiFi_CommandHeader header;
    1 g$ h7 D( y+ D9 t  z
  341.         uint8_t peer_sta_addr[6]; // Peer MAC address
    6 P( q# Y9 b' U! F6 `6 q3 S! v
  342.         MrvlIETypes_CapInfo_t cap_info; // Capability information
    4 q3 _# \6 D4 V
  343.         uint16_t listen_interval; // Listen interval3 d2 P% B; l) K; a5 z
  344.         uint16_t bcn_period; // Beacon period( j& H, w1 X+ k# e! `" G1 D
  345.         uint8_t dtim_period; // DTIM period3 q& y8 o# a6 y0 C4 T& ?
  346. } WiFi_CmdRequest_Associate;
    + l0 q3 d' {. X6 ^3 \& a- n

  347. 6 e6 p8 R1 a( b7 q
  348. typedef __packed struct/ M+ ?, t2 i, D0 U
  349. {! J1 i: s8 n% T  B  W
  350.         WiFi_CommandHeader header;
    8 D' }* E5 B1 Y& `6 R
  351.         uint8_t bss_type;2 q4 i3 l+ L- D# F+ ~
  352.         uint8_t bss_id[6];
    # i" O4 s1 K0 t1 x0 _( U8 g
  353. } WiFi_CmdRequest_Scan;
    # z9 \- Y( D- q5 U* M

  354. ; U) ^! D- z6 }/ }& ]9 s2 @
  355. typedef __packed struct& ], O3 P. F, K+ K, |  g+ W
  356. {7 `* I& _% V/ q) e, Z& P
  357.         WiFi_CommandHeader header;4 ]8 K3 L* g- M" O; X
  358.         uint16_t capability;
    9 u; S9 k/ D6 w% h2 k
  359.         uint16_t status_code;2 b5 j, \; q- U. i* N. N
  360.         uint16_t association_id;, l) {* y7 c5 I. T9 v
  361.         IEEEType ie_buffer;
    ) u% i* V" G" q% @. ^1 c
  362. } WiFi_CmdResponse_Associate;5 N. Y5 u# d0 g) G4 U4 n

  363. $ }8 n/ `- h7 t) n% v/ e
  364. typedef __packed struct
    ; z5 F6 y9 P7 u0 Z# _3 h
  365. {
      Y" n# ~% l6 j4 ^5 ~
  366.         WiFi_CommandHeader header;
    2 `; `! m$ l9 g6 ~0 {0 ^
  367.         uint16_t buf_size;* }, V7 D/ K" s5 I
  368.         uint8_t num_of_set;
    " n; T+ m/ V- p7 C
  369. } WiFi_CmdResponse_Scan;
    * B5 U$ k& U, y# \5 ]
  370.   G, z) Y' a9 u' r
  371. typedef __packed struct$ h0 H( s) n! M# ^4 {7 u
  372. {$ z- c7 {6 `1 a0 q0 R. S
  373.         MrvlIETypes_SSIDParamSet_t ssid;
    ( X" H! ~2 `+ X  s
  374.         uint8_t mac_addr[6];
    ; O1 U/ }! V4 {3 _- c- r! |
  375.         MrvlIETypes_CapInfo_t cap_info;
    : w0 u6 M5 B  R7 Z
  376.         uint16_t bcn_period;3 b2 C; Q9 @& U6 w- I  T( U
  377.         uint8_t channel;
    2 X  K' Y2 L7 c- k+ n
  378.         MrvlIETypes_RatesParamSet_t rates;
    & |7 ]# ^. G8 ~) p
  379.         MrvlIETypes_RsnParamSet_t rsn;; _. v/ B6 _7 Y5 t9 S% v) q
  380.         MrvlIETypes_VendorParamSet_t wpa;/ W8 O2 G' t1 Z9 r  _& F
  381.         MrvlIETypes_VendorParamSet_t wwm;
    % n0 ]9 |' `+ |" H2 i) b$ O+ V; v
  382.         MrvlIETypes_VendorParamSet_t wps;; n( ^5 {7 F# L7 n% b8 |
  383. } WiFi_SSIDInfo;
    * q9 A( A+ ?  R1 b% ^) y

  384. ! h, M, P( S- ?4 T: j! O& y0 @1 m" b
  385. #define WiFi_DropPacket() WiFi_ReceivePacket(0, 0), G" T  v. v. z. S& `  G
  386. #define WiFi_GetBlockSize() _BV((SDIO->DCTRL & SDIO_DCTRL_DBLOCKSIZE) >> 4)% i* g: t4 i1 I0 ]
  387. #define WiFi_GetMACAddr(addr) WiFi_MACAddr((addr), WIFI_ACT_GET)& M, w% g3 `2 U" X! I
  388. #define WiFi_PacketArrived() (WiFi_Read(1, WIFI_CARDSTATUS) & WIFI_CARDSTATUS_UPLDCARDRDY)! l2 l: R7 S& H( w
  389. #define WiFi_ResendCommand(cmd) WiFi_SendCommand(0, (cmd), 0)4 A& v8 j7 [8 ^0 h
  390. #define WiFi_SetMACAddr(addr) WiFi_MACAddr((uint8_t *)(addr), WIFI_ACT_SET)$ E$ F: G# I! ]$ n
  391. #define WiFi_ShowShortResponse() printf("Command response received: CMD%d, RESP_%08x\n", SDIO->RESPCMD, SDIO->RESP1)
    % K% h1 ]& ?' J5 w2 ^# [
  392. . c2 q, k0 m  }; ^/ A1 h5 A
  393. uint16_t WiFi_Associate(const char *ssid);8 R/ W" S! {# l' a% P
  394. void WiFi_CheckCmdTimeout(void);
    7 ]  _1 S( R/ E9 r( Q
  395. uint16_t WiFi_Connect(const char *ssid, const char *password);
    . X; v* j: x6 }% B8 f% N
  396. uint8_t WiFi_DownloadFirmware(void);
      F6 a0 q: C4 \& e
  397. uint16_t WiFi_GetPacketLength(void);; g# e9 L3 B- e( a
  398. void WiFi_Init(void);
    1 v2 X) K8 M: |+ }1 M* N3 ~6 f
  399. uint16_t WiFi_KeyMaterial(MrvlIETypes_KeyParamSet_t *keys, uint16_t size, uint8_t action);, \; c2 f+ z. e
  400. void WiFi_MACAddr(uint8_t addr[6], uint8_t action);
    # g5 O  M/ \. r0 ^# _- W% y
  401. void WiFi_MACControl(uint16_t action);. J6 h( C' u4 n. B1 ~: x# R
  402. uint16_t WiFi_PacketPending(void);4 A5 h0 X# h4 X! I- L" v3 ?# q( ~& o
  403. void WiFi_PrepareTimer(uint16_t nms);, n. ^% |, e# t2 P6 |
  404. uint8_t WiFi_Read(uint8_t func, uint32_t addr);4 W& R: g+ K. \( I2 Z; G
  405. void WiFi_ReadData(uint8_t func, uint32_t addr, uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags);
    # B3 _1 I5 @, y+ w0 q( P6 r
  406. uint16_t WiFi_ReadPort(void *buf, uint16_t size, uint16_t bufsize);
    # a  I, B- K) m  `! L
  407. uint16_t WiFi_ReceivePacket(void *buf, uint16_t bufsize);
    ) O4 F( w3 D8 s
  408. uint16_t WiFi_ReceiveResponse(void *buf, uint16_t bufsize);
    6 w+ P' @% x9 Y! b, A9 t, J" l6 W
  409. void WiFi_Scan(void);3 `" i0 q2 I+ `6 j( y
  410. uint8_t WiFi_ScanSSID(const char *ssid, WiFi_SSIDInfo *info, uint8_t *buffer, uint16_t bufsize);& p* Y& c5 y5 u, P" O0 ~1 ]
  411. void WiFi_SendCMD52(uint8_t func, uint32_t addr, uint8_t data, uint32_t flags);
    ( A' o. G9 q. r. H( S7 L! i4 h
  412. void WiFi_SendCMD53(uint8_t func, uint32_t addr, uint16_t count, uint32_t flags);
    5 K6 A. ?) `9 G  b/ ~$ y" V9 b# i
  413. void WiFi_SendCommand(uint16_t com_code, void *data, uint16_t size);
    & C7 G4 m' E( J& O4 ?+ g, _+ r
  414. uint8_t WiFi_SendPacket(WiFi_DataTx *packet, uint16_t packet_len);
    ; l( t' @) q# o! a8 L- Q# _  x, ?
  415. void WiFi_SetBlockSize(uint8_t func);- Z) C3 _. b& l! c
  416. uint8_t WiFi_SetKeyMaterial(uint16_t type, uint16_t info, const uint8_t *key, uint16_t len);; O9 o: N+ i( T4 y8 K
  417. void WiFi_ShowCIS(uint8_t func);
    $ V. Z' ]; R) I5 j6 o  o; k6 E
  418. void WiFi_ShowKeyMaterials(void);+ X& g: E' C* E4 K  ^# v7 l
  419. uint8_t WiFi_StartADHOC(const char *ssid);' O( ~9 T8 N6 ^& d8 @
  420. uint8_t WiFi_Wait(uint8_t status);3 C. U" T' S) |" k# O3 R
  421. uint8_t WiFi_Write(uint8_t func, uint32_t addr, uint8_t value);
    ; v/ R" j5 b+ @5 Z" ]
  422. void WiFi_WriteData(uint8_t func, uint32_t addr, const uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags);
    , d* X  ]1 a4 E" s, f- q- M
  423. uint8_t WiFi_WritePort(const void *data, uint16_t size);! i) @! h; C" V9 K! Y: d- z7 @
复制代码
【WiFi.c】1 ?  _7 U/ _! b# |- r0 e' U% p
  1. #include <stdio.h>( _. B1 v7 w. u, m7 M; \
  2. #include <stm32f10x.h>* z1 W5 }# V: z8 e
  3. #include <string.h>
    ) L% R+ |% `" [
  4. #include "WiFi.h". U7 `4 {/ z. F- X5 r2 B2 z# N, a
  5. & }% r4 l8 o7 A) Q
  6. extern const unsigned char firmware_helper_sd[2516];" S5 @6 o* o, P! n0 K, h! M, E' }
  7. extern const unsigned char firmware_sd8686[122916];# ~0 v6 J  ^7 d" J. r7 |5 K
  8. 3 i. o2 Y, X6 r$ h; z) F
  9. //const uint8_t wifi_mac_addr[] = {0x62, 0x1d, 0x2f, 0x00, 0x4e, 0x2d}; // MAC地址的第一个字节必须为偶数! 否则为多播地址
    0 H0 H8 `9 ^& g7 I
  10. ( j4 m) A" c; c4 d8 `' T
  11. static uint16_t rca;* J7 {' C4 N. D# w
  12. static uint16_t wifi_timeout = WIFI_DEFAULTTIMEOUT;# p0 U2 Y: b# A; C
  13. static uint32_t io_addr;8 p2 I! [9 ]1 u) l: P
  14. static uint16_t wifi_pending_size = 0; // 未读的数据包大小* n* }3 E2 f" e' v8 l8 {4 @, h
  15. # j& ]4 a4 x( u- F
  16. void delay(uint16_t n);
    0 p7 S3 ^' L7 p5 g
  17. void dump_data(uint8_t *data, uint16_t len);
    2 ]% S2 q- L' v
  18. . P. T2 c$ h& X5 q4 t6 t
  19. /* 关联一个热点 */
    0 t0 j! S5 k7 R6 ^  i, f* _6 O
  20. uint16_t WiFi_Associate(const char *ssid)$ D, t' W. }  C. {! m$ g4 m/ m9 ]
  21. {
    ; `6 U8 ~* R7 U  E, ?5 k
  22.         uint8_t buffer[2048];
    $ p# J- Y% S4 G
  23.         WiFi_SSIDInfo info;
    7 z, }8 v+ m2 v6 I5 N
  24.         WiFi_CmdRequest_Associate *cmd = (WiFi_CmdRequest_Associate *)buffer;/ T9 O5 M+ }3 m5 \5 i
  25.         WiFi_CmdResponse_Associate *resp = (WiFi_CmdResponse_Associate *)buffer;
    5 M8 @' n  C3 e+ D7 g
  26.         MrvlIETypes_DsParamSet_t *ds;
    ' d+ g2 l4 G0 ^6 `  B  Z& r
  27.         MrvlIETypes_CfParamSet_t *cf;6 }+ f  d& @8 R& Q- N) A) Q& d
  28.         MrvlIETypes_AuthType_t *auth;
    ( y: ^# G! ?# \
  29.         MrvlIETypes_RsnParamSet_t *rsn;0 p# K1 ]+ R8 w- S. B; V
  30. / f* p& E0 ?: k/ i, \# L
  31.         if (!WiFi_ScanSSID(ssid, &info, buffer, sizeof(buffer)))( t1 Y6 ?5 v. t6 m. M: P4 i
  32.         {
    , ~1 D1 U; a  R
  33.                 printf("Cannot find AP: %s!\n", ssid);
    9 W; |1 W) t1 }, G/ Z0 z$ w( |
  34.                 return WIFI_ASSOCIATION_NOTFOUND;
    4 v) ?% `1 W7 u$ I0 x; p8 r
  35.         }
    ( _* F3 }* X/ G0 z5 E
  36.         
    4 U9 @0 o( j2 U$ Q* c" r/ u7 A4 s
  37.         memcpy(cmd->peer_sta_addr, info.mac_addr, sizeof(info.mac_addr));1 E3 \# o2 L. x/ r
  38.         cmd->cap_info = info.cap_info;
    ! m4 g4 M0 X" N& F6 h& t% v
  39.         cmd->listen_interval = 10;9 K3 x7 o5 J" X7 [" K! e
  40.         cmd->bcn_period = info.bcn_period;+ g, S9 {* n) n  a6 R" b; }' p
  41.         cmd->dtim_period = 0;
    " R3 J" w% _( I9 N) n4 V
  42.         memcpy(cmd + 1, &info.ssid, MRVLIE_STRUCTLEN(info.ssid));1 C( M# e2 x! e6 X. _1 q
  43.         ( d- Y$ a. y5 g. [/ a. R* v
  44.         ds = (MrvlIETypes_DsParamSet_t *)((uint8_t *)(cmd + 1) + MRVLIE_STRUCTLEN(info.ssid));7 C- ~0 E6 ~9 N& e
  45.         ds->header.type = MRVLIETYPES_DSPARAMSET;" Z/ N/ r. D& G
  46.         ds->header.length = 1;  a" s$ M5 i' P+ M
  47.         ds->channel = info.channel;
    ! P' |6 a' p% W" s5 L* G  W
  48.         * z- T5 [9 h' e: [+ x; W, ?1 ]8 [: R
  49.         cf = (MrvlIETypes_CfParamSet_t *)(ds + 1);
    3 a; k: D% `7 T" r# E
  50.         memset(cf, 0, sizeof(MrvlIETypes_CfParamSet_t));
    6 _- |3 A; ]$ k* p( r
  51.         cf->header.type = MRVLIETYPES_CFPARAMSET;
    3 z; h" T. A+ {" W. n9 v" ?  f0 g* V
  52.         cf->header.length = MRVLIE_PAYLOADLEN(*cf);; w% ~4 n3 M  {5 H' A1 V
  53.         
    : O. N0 i& {3 S+ ]/ {0 h& Z
  54.         memcpy(cf + 1, &info.rates, MRVLIE_STRUCTLEN(info.rates));: O+ ^  C1 {* C
  55.         auth = (MrvlIETypes_AuthType_t *)((uint8_t *)(cf + 1) + MRVLIE_STRUCTLEN(info.rates));
    % ~0 Q; I1 T/ G
  56.         auth->header.type = MRVLIETYPES_AUTHTYPE;8 C3 S2 g# L  Z2 ?" A
  57.         auth->header.length = MRVLIE_PAYLOADLEN(*auth);/ K0 J5 U3 O8 @9 O( X; m% q
  58.         auth->auth_type = AUTH_MODE_OPEN;% W# B- n9 _0 N
  59.         0 m. n/ ?3 w+ Z, E3 e* r/ e3 n
  60.         rsn = (MrvlIETypes_RsnParamSet_t *)(auth + 1);8 q+ P; Y" i8 G8 _6 g6 s2 O4 M
  61.         if (info.rsn.header.type)
    : u! K/ O) ]: \  `. Q( w4 [) W
  62.         {0 u( l& l" r% ]
  63.                 // WPA2网络必须在命令中加入RSN参数才能成功连接) g: u# J" X& R9 Y( i- J
  64.                 memcpy(rsn, &info.rsn, MRVLIE_STRUCTLEN(info.rsn));
    , I, ^- e9 p* A7 t# J
  65.                 WiFi_SendCommand(CMD_802_11_ASSOCIATE, buffer, (uint8_t *)rsn - buffer + MRVLIE_STRUCTLEN(info.rsn));3 Z1 e/ N6 {9 G! w2 C0 k
  66.         }1 T( i0 _$ @3 k" U1 a. f$ F4 ^/ N
  67.         else
    / a# }3 K# ?; u5 D8 W' z  j
  68.                 WiFi_SendCommand(CMD_802_11_ASSOCIATE, buffer, (uint8_t *)rsn - buffer); // 其余网络不需要RSN参数
    0 G" I6 h" K# l/ Y/ \
  69.         , I0 \! [; `; ?
  70.         if (!WiFi_ReceiveResponse(buffer, sizeof(buffer)))( c9 x! P9 X$ C8 Z+ ~
  71.         {
    3 b7 [' m4 b3 t  Z0 t
  72.                 printf("Association with %s failed!\n", ssid);
    " Y" m$ V0 d6 S" d* q6 o# Y
  73.                 return WIFI_ASSOCIATION_ERROR;- s% F0 W+ e: P$ x7 B' D
  74.         }
    1 P3 q0 Q3 E! D' t; u
  75.         5 z( a' Q: V/ c1 U- J( z
  76.         //printf("capability=0x%04x, status_code=0x%04x, aid=0x%04x\n", resp->capability, resp->status_code, resp->association_id);. d" ]* ~& i& y9 T
  77.         if (resp->association_id == 0xffff)9 n" T" }/ c  A
  78.                 return ((-resp->capability) << 8) | resp->status_code;0 Y# g( Z. q- u8 H5 v
  79.         return WIFI_ASSOCIATION_SUCCESS;
    + n3 j5 M7 a; f2 X1 D7 `
  80. }/ _$ H4 b- O# d, J* f

  81. * [* i% L  B, ]/ H, O& B
  82. /* 检查命令是否收到了回应, 若没收到则重发命令 */
    & P2 Y3 o$ g0 Z) ~
  83. void WiFi_CheckCmdTimeout(void)( i3 o. v; u3 U
  84. {
    7 H8 Z, |% w6 G; w- D+ r! X$ O) I
  85.         while (SDIO->STA & SDIO_STA_CTIMEOUT)0 g# C/ [  H( J5 q- M+ v5 b
  86.         {
    8 \; B& x( ~8 K0 N, Z
  87.                 SDIO->ICR = SDIO_ICR_CTIMEOUTC; // 清除标志
    & ?* L  x3 c+ D9 q5 [, n
  88.                 SDIO->CMD = SDIO->CMD; // 重发6 ]. `( K/ S8 ?; ?" d
  89.                 printf("Timeout! Resend CMD%d\n", SDIO->CMD & SDIO_CMD_CMDINDEX);, G+ ]: _) X) A' D1 i% ^6 q* W7 T, N
  90.                 while (SDIO->STA & SDIO_STA_CMDACT);8 D2 T& {/ c: D; }1 G: X; [
  91.         }
    $ r6 b3 d: Y9 }* w
  92. }
    ' @' S! q7 w( M  a* O: {5 G
  93. 8 M# K& x' J" `
  94. /* 连接WiFi热点, 并输入密码 */
    : @1 j2 I( h  ?: k- I0 B
  95. uint16_t WiFi_Connect(const char *ssid, const char *password)
    6 V* g9 l+ }) u. T( B" w
  96. {' S1 V" Z& I& [5 B- f6 S( @9 }
  97.         uint16_t ret;
    / K) r: i; N8 G8 |5 q
  98.         do
    / t( _/ u& v+ L
  99.         {- h) @5 e* K3 t8 C" d
  100.                 ret = WiFi_Associate(ssid);
    : M' Y% g% D" m9 _
  101.                 if (ret != WIFI_ASSOCIATION_SUCCESS)' c7 ]! q  i- }4 x& M$ ~
  102.                 {& R& J+ S/ e( `! z8 k7 q/ F
  103.                         printf("WiFi_Associate returned 0x%04x\n", ret);6 x* E- J. p3 k* ^# ]
  104.                         delay(2000); // 等待一段时间后重连( d# K- X2 a$ N, R$ S$ S1 R# g
  105.                 }# h. r9 k, A5 s2 K8 V* d; ]) H
  106.         } while (WIFI_ASSOCIATION_TIMEOUT(ret) || ret == WIFI_ASSOCIATION_NOTFOUND); // 若连接超时, 或未扫描到热点, 则重连. U  U0 f" _6 ?
  107.         + Y% p8 _* H, {5 h
  108.         if (ret != WIFI_ASSOCIATION_SUCCESS)
    $ n+ l: \6 p. u* a! s
  109.                 return ret;
    ! I* g8 S8 o3 x5 t1 S1 |' o, e
  110.         ; O2 z. J9 q$ _! C3 _9 h0 K* }
  111.         printf("Connected to %s!\n", ssid);5 U& |5 J) v) p8 A) w
  112.         return ret;
    4 d  R" ], y. C
  113. }: x0 k( @8 k* @( A3 ~8 G% D
  114. 4 K% K/ d# c' U2 H
  115. /* 下载固件 */
    7 H4 X# w( F( C8 }
  116. // 参考文档: marvell-88w8686-固件下载程序说明.doc: K4 B7 {8 e; R& w
  117. uint8_t WiFi_DownloadFirmware(void)* Q( ?( `8 \. C
  118. {
    ! _& m* T4 q1 U3 s7 a
  119.         uint8_t helper_buf[64];
    8 o' ~% x1 v/ `/ s- Z
  120.         const uint8_t *data;
    3 i* @( e% c; r# |  R& u/ Y
  121.         uint16_t size;- `5 I: V7 Q. X$ v/ K4 p. W+ D
  122.         uint32_t len;
    ( ~1 O2 n. }6 {+ {- T
  123.         6 {& z0 D  i* o4 e) R. F% g9 c# |3 X
  124.         // 块大小设为32
    % G" C/ Q7 G/ ?; v$ A# E0 C, z
  125.         SDIO->DCTRL = (SDIO->DCTRL & ~SDIO_DCTRL_DBLOCKSIZE) | SDIO_DCTRL_DBLOCKSIZE_2 | SDIO_DCTRL_DBLOCKSIZE_0;. y( {" f- Z) u4 [
  126.         WiFi_SetBlockSize(1); // 应用到Function 15 [' A0 z: o- q4 y4 G0 @6 p
  127.         
    ! {* `4 L" c( Q1 @( T6 F' r
  128.         // 下载helper
    . a! k8 `- Q/ L: r8 K5 J
  129.         io_addr = WiFi_Read(1, 0x00) | (WiFi_Read(1, 0x01) << 8) | (WiFi_Read(1, 0x02) << 16);$ T- D! R; V4 q4 Y8 [
  130.         data = firmware_helper_sd;6 `0 }+ A$ G" _4 a% P8 E
  131.         len = sizeof(firmware_helper_sd);
    * k. b- p1 O: v' K* d& r: ~+ ~
  132.         while (len)
    4 ~; ]( h2 J; P5 Z; e! M( O' D3 P
  133.         {$ h  P- x$ _" H! k1 P; ], N. M
  134.                 // 每次下载64字节, 其中前4字节为本次下载的数据量
    ; g3 p" A0 P8 \2 Z$ L! `% V
  135.                 size = (len > 60) ? 60 : len;
    1 z: o) @! ^# _/ z
  136.                 *(uint32_t *)helper_buf = size;
    + }; }9 l9 N( b/ O6 F' ?& m; J
  137.                 memcpy(helper_buf + 4, data, size);
    % u- Y" d% @+ O, K# L# y( N4 O8 j/ @
  138.                
    - r3 B5 V! j6 T: J# w# j
  139.                 WiFi_Wait(WIFI_CARDSTATUS_DNLDCARDRDY);( `+ f. |2 M% u/ a
  140.                 WiFi_WritePort(helper_buf, sizeof(helper_buf));
    4 J4 x/ Z. T- i* ?/ f5 `* P
  141.                 len -= size;1 L1 W( ]; k& g1 h. G! \, Z
  142.                 data += size;
    % ^! O* Z6 P9 F
  143.         }
    / ?: x# {  b; a1 O5 ?$ X
  144.         *(uint32_t *)helper_buf = 0;+ ?/ T9 h! l. }* ~# Y
  145.         WiFi_WritePort(helper_buf, sizeof(helper_buf)); // 以空数据包结束
    & P9 G! G6 a8 F% A7 e8 Z
  146.         9 p7 x3 G8 a" A
  147.         // 下载固件  r) }8 U: J5 b3 B) A# s2 X
  148.         data = firmware_sd8686;! j, X8 @* p9 F3 {
  149.         len = sizeof(firmware_sd8686);8 ^& b$ d/ d! R' ~" K  {
  150.         while (len)" i+ Q# c# q: {+ W' q6 E
  151.         {
    + r- H3 i8 C; L& o
  152.                 WiFi_Wait(WIFI_CARDSTATUS_DNLDCARDRDY);
    $ P1 O. a! q: i' r; a. ^+ B; X/ ?# Q
  153.                 while ((size = WiFi_Read(1, WIFI_SQREADBASEADDR0) | (WiFi_Read(1, WIFI_SQREADBASEADDR1) << 8)) == 0); // 获取本次下载的字节数
    ) p' b4 Q- |2 @" ]$ B# [5 a5 K0 X
  154.                 //printf("Required: %d bytes, Remaining: %d bytes\n", size, len);' ?! x6 D2 |7 o( J
  155.                
    ' |. x. ^; w: c3 D7 A# `
  156.                 if (size & 1)" x8 z; Q& J  l- o( {+ P' y3 {
  157.                 {
    . z5 z7 o8 J, H+ {, m0 \% r  d
  158.                         // 若size为奇数(如17), 则说明接收端有CRC校验错误, 应重新传送上一次的内容(这部分代码省略)7 t' {& b3 Q/ d% @0 G3 A
  159.                         printf("Error: an odd size is invalid!\n");2 H' }- f4 B( N" J# u: z3 E3 }  v; i
  160.                         return 0;7 X( ]9 a' a  ?4 h% G$ }* x% z
  161.                 }3 x1 K2 g9 f9 q
  162.                 if (size > len)
    ' _+ i# B! E$ `* O8 L7 Q9 z% _4 ^: F
  163.                         size = len;' F/ ~0 x! X4 e0 L! X3 }5 S
  164.                
    - @; |# W+ Z! S$ v; E
  165.                 if (!WiFi_WritePort(data, size))  B: a0 a7 m  A2 g+ t! ?, G8 v
  166.                 {1 G- d9 H# ]; O7 b! c: A: b4 s: _
  167.                         printf("Data transfer error! SDIO->STA=0x%08x\n", SDIO->STA);2 @: K7 M* W# w( p$ w: p& A
  168.                         return 0;
    ! A4 @1 q  l' t: p9 H8 Z! m* E
  169.                 }
    ' C# s: n% ~; ~
  170.                
    ! e8 V3 f# X; C9 Y0 C+ D2 r
  171.                 len -= size;) Z& Q" }& t) \+ y
  172.                 data += size;" _8 E8 P. f& |/ ]2 @% S
  173.         }
    1 D1 ?6 i0 C- a8 F# x- F9 r4 a' O
  174.         9 y( ~8 w! K8 r3 p6 ]$ s
  175.         // 等待Firmware启动
    4 t( M# G- _& z& K
  176.         while (WiFi_GetPacketLength() == 0xfedc);
    7 p  x0 v# ^0 [9 W
  177.         printf("Firmware is successfully downloaded!\n");
    ' O- c$ e" `; x( T
  178.         return 1;6 E) j$ z$ C& ?  J, |1 o5 i
  179. }6 Y) S! ]4 N/ k+ n
  180. 8 f9 V( S( u# Z; i6 u( S0 s
  181. /* 获取数据帧大小 */
    8 Q# m- D4 \; ~- Y  w0 Y
  182. uint16_t WiFi_GetPacketLength(void)
    * Q8 `) w# G+ j
  183. {+ _9 ^- ~6 c; u0 n1 L) q
  184.         return WiFi_Read(1, 0x34) | (WiFi_Read(1, 0x35) << 8);
    ; h  H- Y8 `5 O$ n
  185. }5 g- L& M* S/ b) O2 b8 K
  186. / h, l, @4 `5 b5 {
  187. /* 初始化WiFi模块 */$ k) t  ?9 u3 q: W
  188. // SDIO Simplified Specification Version 3.00: 3. SDIO Card Initialization7 [7 p& I3 ^* |, ~
  189. void WiFi_Init(void)& d) H2 F/ ^) j% p7 S, m  O' D: F
  190. {! _8 V  L; i. @$ o6 {2 C+ N
  191.         printf("Initialization begins...\n");
    / O8 a" t  q# k6 p3 D& @
  192.         SDIO->POWER = SDIO_POWER_PWRCTRL;
    7 A' e) u7 o8 o: F
  193.         SDIO->CLKCR = SDIO_CLKCR_CLKEN | 178; // 初始化时最高允许的频率: 72MHz/(178+2)=400kHz
    " N8 S- Y# d: A% d# C6 g: f( H2 a
  194.         delay(5); // 延时可防止CMD5重发
    4 h$ p" F' Q5 _7 S  u/ s
  195.           u4 D) ]; G. Y5 K( s! t
  196.         // 不需要发送CMD0, 因为SD I/O card的初始化命令是CMD52
    0 W0 P- Q% J3 N* T& C1 s  n# K
  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)! M2 K8 {0 y* G3 `
  198.         
    * T3 V( n9 x6 @! b3 g( k9 H
  199.         /* 发送CMD5: IO_SEND_OP_COND */6 s% _2 ]9 S8 c. p
  200.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 5;" b% y& A, G5 R0 b0 u& m2 T
  201.         while (SDIO->STA & SDIO_STA_CMDACT);
    ) G1 i9 M& M. R2 X* E1 y0 F$ G; X
  202.         WiFi_CheckCmdTimeout(); // 为了保险起见还是要检查一下是否要重发命令
    + c8 h2 y8 H, ^( m
  203.         if (SDIO->STA & SDIO_STA_CMDREND)( U8 d) G, n3 J9 e& y! a& C
  204.         {
    % h( L! X# f5 |4 G1 b* e
  205.                 SDIO->ICR = SDIO_ICR_CMDRENDC;' ^' W8 k0 E# G2 @4 O% `
  206.                 WiFi_ShowShortResponse();
    0 ~, G+ T' @2 j( U1 X- p1 _3 c
  207.         }4 g. F6 U! p0 m
  208.         
    ( P& o3 z: L0 g, J
  209.         /* 设置参数VDD Voltage Window: 3.2~3.4V, 并再次发送CMD5 */7 l6 E5 E( \' X3 K( T, f
  210.         SDIO->ARG = 0x300000;
    7 @9 n5 R% o  Y& n
  211.         SDIO->CMD = SDIO->CMD;
    8 N& }1 }4 `/ w9 H* Z) p5 d
  212.         while (SDIO->STA & SDIO_STA_CMDACT);: H' e+ i* Y# }. m
  213.         if (SDIO->STA & SDIO_STA_CMDREND)' K  m- _3 n- T' U
  214.         {$ M+ |! q) ~  x4 c% C$ r
  215.                 SDIO->ICR = SDIO_ICR_CMDRENDC;* d% [. B1 m2 b
  216.                 WiFi_ShowShortResponse();
    * J/ ~! n  q! k) x' \& T9 z2 E7 I7 `
  217.                 if (SDIO->RESP1 & _BV(31))  ^5 d. ]; c1 m
  218.                 {
    8 B) j7 J: X1 S' N
  219.                         // Card is ready to operate after initialization& S5 Q3 D1 U3 a/ \0 U& ~
  220.                         printf("Number of I/O Functions: %d\n", (SDIO->RESP1 >> 28) & 7);
    * n, ?; y/ [$ L# I1 ?; x
  221.                         printf("Memory Present: %d\n", (SDIO->RESP1 & _BV(27)) != 0);! U  [/ L1 R  ^; Y- ~
  222.                 }/ ~) c1 A  D& p- B
  223.         }
    " V  a  g8 w( l8 {+ v$ U% Y( P$ G) S! ?
  224.         
    : z1 P7 h$ p/ z+ G1 B' @
  225.         /* 获取WiFi模块地址 (CMD3: SEND_RELATIVE_ADDR, Ask the card to publish a new relative address (RCA)) */4 @% {- Q& Y0 J6 Q
  226.         SDIO->ARG = 0;
    5 U$ U) A7 J" M; |4 T
  227.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 3;
    ! O& g2 B6 m! x
  228.         while (SDIO->STA & SDIO_STA_CMDACT);
    $ k5 p3 T5 `$ y) w
  229.         if (SDIO->STA & SDIO_STA_CMDREND)3 O) \2 k7 ~. v$ z! {* ~
  230.         {
    6 b2 I% l5 c% X$ Q
  231.                 SDIO->ICR = SDIO_ICR_CMDRENDC;% l$ Q7 |: V  R" Q. y& k
  232.                 rca = SDIO->RESP1 >> 16;1 f1 l" g' e* E1 @1 r9 c: K2 W! l
  233.                 printf("Relative card address: 0x%04x\n", rca);
    4 S$ N0 ]' V" B3 k% g
  234.         }8 D1 s- z; _- T/ A/ y
  235.         
    , l( Y3 X$ r" E  d
  236.         /* 选中WiFi模块 (CMD7: SELECT/DESELECT_CARD) */1 X+ I: g- u7 ^
  237.         SDIO->ARG = rca << 16;& V9 F4 J+ c+ O
  238.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 7;
    + {4 q$ p* `: O. a& ?# y1 M) `! U6 O
  239.         while (SDIO->STA & SDIO_STA_CMDACT);( Z. M0 @& _, @& @
  240.         if (SDIO->STA & SDIO_STA_CMDREND)
    % }3 r; w2 z: S: r# n/ _
  241.         {, X: }! E7 i8 A! u8 W( I  d
  242.                 SDIO->ICR = SDIO_ICR_CMDRENDC;/ O" C) A8 T9 e* G, f& W: u
  243.                 printf("Card selected! status=0x%08x\n", SDIO->RESP1);
    " A; y9 g3 j/ S$ |; p% x9 v- |! Z
  244.         }" L# ^5 V" M' H, T# ~4 X+ x
  245.         . j* t( _$ D. e" U; A
  246.         // 提高时钟频率
    $ I+ w0 v& b! M: E
  247.         SDIO->CLKCR = (SDIO->CLKCR & ~SDIO_CLKCR_CLKDIV) | 70; // 72MHz/(70+2)=1MHz
    - E  J: v: A/ M0 o+ l4 F! X9 o8 w
  248.         SDIO->DTIMER = 1000000; // 当频率为1MHz时, 超时时间为1秒
    " `; e/ {0 l9 F' u7 u
  249.         //SDIO->CLKCR = (SDIO->CLKCR & ~SDIO_CLKCR_CLKDIV) | 1; // 72MHz/(1+2)=24MHz
    5 O) k7 j+ R: j/ Q% ^
  250.         
    " F4 G9 h- Q9 x5 B
  251.         /* 选择总线宽度 (Wide Bus Selection) */8 }/ ^6 {" T2 i; S9 n: ~6 Q9 V
  252.         // For an SDIO card a write to the CCCR using CMD52 is used to select bus width. (See 4.5 Bus Width)! q' F$ l5 A  M6 @
  253.         // CMD52: IO_RW_DIRECT, CCCR: Card Common Control Registers
    , l2 R* P4 W* V0 M
  254.         WiFi_Write(0, 0x07, WiFi_Read(0, 0x07) | 0x02); // Bus Width: 4-bit bus5 h/ e& `7 i9 N; o6 n
  255.         SDIO->CLKCR |= SDIO_CLKCR_WIDBUS_0;
    4 q! S1 |) \# ]1 O  W( e& p
  256.         # r2 `; H& M- e# I* G6 q
  257.         // 初始化Function 1
    ! U* e9 ?% v1 o! C" j
  258.         WiFi_Write(0, 0x02, 0x02); // IOE1=1 (Enable Function)
    0 @) }2 s/ g# M! n+ i- Q- I
  259.         while ((WiFi_Read(0, 3) & 0x02) == 0); // 等到IOR1=1 (I/O Function Ready)
    5 j) e) p9 O1 J( w' F
  260.         
    ; C8 s) M2 P- t4 m
  261.         // 显示CIS信息" X7 ~) O! w; H7 N: @
  262.         //WiFi_ShowCIS(0);
    9 T' Q6 d* E4 K+ j8 I& U
  263.         //WiFi_ShowCIS(1);( p* _! W+ ~. P( q
  264.         ' w6 f1 g. l: p! K( h
  265.         // 下载固件
    3 `" f7 T- l! d7 D4 F
  266.         WiFi_DownloadFirmware();( D( l$ Z; Y% V" }" l" E( b
  267.         2 q6 V0 W- v2 x' j
  268.         // 设置数据块大小为256字节
    9 b+ j* I; V) ?' K9 ?- Y/ d* b$ N
  269.         SDIO->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3;
    9 w4 v, E# V1 U6 x: |3 K
  270.         WiFi_SetBlockSize(0);- I6 g; d" R- V8 ~- s5 M
  271.         WiFi_SetBlockSize(1);( m" ^) m$ t! [
  272.         
    1 l2 x4 J' A, }( H( `* o8 z( H+ C: r) u
  273.         // 允许发送和接收
    + p. w/ q$ e; h8 X7 L
  274.         // 不使用带有LLC子层的802.2SNAP帧格式, 这样LLC和SNAP这8个字节的内容就不会夹在数据链路层的源地址字段与数据字段之间2 J7 d. m8 c3 D" V4 z
  275.         WiFi_MACControl(WIFI_MACCTRL_ETHERNET2 | WIFI_MACCTRL_TX | WIFI_MACCTRL_RX);$ a8 |: `+ r- N5 g% D2 ?
  276. }" b0 C' ]; p9 {, s) e' d8 D5 m) o
  277. 9 F2 q& R& D( M  k
  278. /* 获取或设置密钥 */7 e" f6 ]7 a, O6 l- L; O9 c
  279. uint16_t WiFi_KeyMaterial(MrvlIETypes_KeyParamSet_t *keys, uint16_t size, uint8_t action)
    7 p. c$ l. d3 F7 ?1 }; \* Z
  280. {
    # [  F  s* [0 l6 x) X5 U* o0 a
  281.         uint8_t buffer[256];7 X' j7 O$ }; @) A, t2 D/ X* a0 Y; [
  282.         uint8_t ret_size;
    * r9 R7 x% s5 B7 ~8 R
  283.         WiFi_Cmd_KeyMaterial *cmd = (WiFi_Cmd_KeyMaterial *)buffer;
    9 ]+ K$ K" v5 D2 C$ J4 @0 z, x% `3 C
  284.         cmd->action = action;
    & g* v/ |& `4 l  U9 k5 o& L
  285.         if (action == WIFI_ACT_SET)
    3 P/ O3 q& b9 t" g
  286.         {6 T. C5 l- n2 @/ i' z; o
  287.                 memcpy(cmd + 1, keys, size);
    2 w0 v: X* G  ^6 o
  288.                 WiFi_SendCommand(CMD_802_11_KEY_MATERIAL, buffer, sizeof(WiFi_Cmd_KeyMaterial) + size);& g5 P/ [% F  M/ C+ y; n
  289.         }- v- w+ a0 H, \
  290.         else5 g5 ?0 k* E4 A. Q" y. Y4 W! q: w0 S
  291.                 WiFi_SendCommand(CMD_802_11_KEY_MATERIAL, buffer, sizeof(WiFi_Cmd_KeyMaterial));# Q' B5 r. O: E5 v/ @2 m
  292.         WiFi_ReceiveResponse(buffer, sizeof(buffer));! I- s: X1 D" ^8 u
  293.         3 \" M$ j" [  Q; |, t0 U1 }% k
  294.         if (action == WIFI_ACT_GET)
    2 ?8 N/ H" p, X7 r
  295.         {# B9 b, Q1 P3 E; b  `  I) N9 |
  296.                 ret_size = cmd->header.size - sizeof(cmd->header) - sizeof(cmd->action);" F0 W; Y- C0 I* m: m* @; W
  297.                 if (ret_size <= size)
    4 r3 D, m, c9 o% w
  298.                         memcpy(keys, cmd + 1, ret_size);' r* Y+ E) L7 r: x" z
  299.                 else
    + V6 m' c. T! d0 [1 v9 ~
  300.                         printf("WiFi_KeyMaterial: Buffer size is too small! %d bytes required!\n", ret_size);
    5 S3 y1 M9 q/ W- U
  301.                 return ret_size; // action=get时返回读取的数据大小
    ( H0 p, B3 L6 q
  302.         }/ |. Z. z  c" d9 f+ F( \
  303.         else
    / G! }, [; F) w* y+ v
  304.                 return cmd->header.result; // action=set时返回命令执行结果值( O' ^( _% t0 ?7 b4 M
  305. }- J4 @6 d. z+ S% f1 j
  306. # b3 ?2 P8 S" L$ Q7 A
  307. /* 获取或设置MAC地址 */
    . W( D$ y: b. \+ v$ O7 J
  308. void WiFi_MACAddr(uint8_t addr[6], uint8_t action)
    1 e5 Q, c% P- ?* e
  309. {6 F1 v) t0 T: ~. P) @; @
  310.         WiFi_Cmd_MACAddr cmd;
    - N2 B" a% W8 s* k1 P
  311.         cmd.action = action;5 S4 F7 a, l4 N% S; @
  312.         if (action == WIFI_ACT_SET)
    ! Z" K5 c) _: |  v4 H
  313.                 memcpy(cmd.mac_addr, addr, 6);
    & \+ ~) i- l! r7 X
  314.         
    0 m- [& v, f: i( J/ e0 x
  315.         WiFi_SendCommand(CMD_802_11_MAC_ADDR, &cmd, sizeof(cmd));
    , @. x: {# G8 S" W  a4 S: [
  316.         WiFi_ReceiveResponse(&cmd, sizeof(cmd));6 \+ i3 w+ y7 m- @' i6 w
  317.         if (action == WIFI_ACT_GET)* U+ a) A0 T$ {$ m  S- X
  318.                 memcpy(addr, cmd.mac_addr, 6);, x( \) p6 u0 Q7 b% O
  319. }
    4 c( m" \& [  X5 ?, x8 ?' o

  320. - B* V+ H" ~3 R! o- ]0 c7 r
  321. /* 配置MAC */
    # v9 s/ e8 E8 p) S
  322. void WiFi_MACControl(uint16_t action)$ T- Y$ I1 h: e5 G, w8 F7 R: t
  323. {, c* @4 w/ Y/ _/ y
  324.         WiFi_Cmd_MACCtrl cmd;
    - N+ [2 l, V" s. U
  325.         cmd.action = action;, [4 n( _5 L$ y( ]$ w( Q1 u
  326.         cmd.reserved = 0;; ]4 P$ Z$ T' J( O
  327.         WiFi_SendCommand(CMD_MAC_CONTROL, &cmd, sizeof(cmd));, n4 M3 A# J8 |
  328.         WiFi_ReceiveResponse(&cmd, sizeof(cmd));- V6 L5 Q( J( \3 g
  329. }8 O0 p1 m; U  `1 g
  330. 4 s+ o0 W5 @3 c; X
  331. /* 获取滞留的数据包大小 */
    7 n. P5 v/ I, H+ o, z: P
  332. uint16_t WiFi_PacketPending(void)4 r/ p; h# I  w, @, [: u
  333. {1 u8 l# D9 O0 e! c5 ?4 A$ \
  334.         return wifi_pending_size;
    & w6 s# H/ Q( x) \
  335. }
    4 J1 W$ w& B1 s& T  x0 K' B2 k5 A& d/ I; ?

  336. $ r6 K9 Y7 Z1 K+ ~
  337. /* 准备好超时计时器 */: U7 w. d, N+ }. k, v/ J' i
  338. void WiFi_PrepareTimer(uint16_t nms)7 i! g* P9 A% ^) G! u$ x: k
  339. {( l/ O0 b3 w# K
  340.         TIM6->ARR = 10 * nms - 1;1 R; S4 {: `) i" K6 j
  341.         TIM6->PSC = 7199; // 72MHz/7200=10kHz
    % M( T' ?0 |% g# B) |) B! @5 o
  342.         TIM6->EGR = TIM_EGR_UG; // 保存设置
    1 j6 T) H! ?0 p$ A8 S' ?
  343.         TIM6->SR &= ~TIM_SR_UIF; // 清除溢出标志位! A( J0 q) ]! [) s/ F- x: T* K0 |
  344.         TIM6->CR1 = TIM_CR1_OPM | TIM_CR1_CEN; // 开始计时, 模式为非循环模式) ~' S2 `0 i0 }: Q( ?
  345. }
    3 C5 b0 @; x$ J( o1 A0 U3 Y

  346. 5 y* h" J3 [" O6 o5 {
  347. /* 读寄存器 */8 F2 ^, T5 [- O& J. }! p! O" [
  348. uint8_t WiFi_Read(uint8_t func, uint32_t addr)
    9 Q" Q6 {3 a/ v2 `, z, [
  349. {. @; l7 \9 ^* P0 p: [! J- L
  350.         WiFi_SendCMD52(func, addr, NULL, NULL);
    % s4 h" c6 ]/ E3 z  W5 [
  351.         if (SDIO->STA & SDIO_STA_CMDREND)  m! p, K$ o7 C) d$ W
  352.         {% e% j! P) P' a, K
  353.                 SDIO->ICR = SDIO_ICR_CMDRENDC;- B7 t, D0 g9 U5 q
  354.                 return SDIO->RESP1 & 0xff;, l* G! h  Q# x# b. n
  355.         }
    $ d6 E) A; h' G/ E/ ~
  356.         else% B: E9 O3 H# e; {, d' J. e( {
  357.         {8 M$ L' P) o2 U
  358.                 printf("WiFi_Read failed, SDIO->STA=0x%08x!\n", SDIO->STA);9 M: k- `7 Q+ k1 X/ U0 Z
  359.                 return 0;8 K6 Q: L$ u- {5 T( h1 L1 |, ~! y
  360.         }8 Z3 \0 T% }2 g7 O8 m" p/ [' P
  361. }1 F! h- Q+ I" l/ B6 I: @

  362. 0 ^% Q7 I: [* e8 ?
  363. /* 读数据 */: G% p; q' A: u' a7 @+ i" m$ c1 N' }
  364. // count为要发送的字节数或块数, bufsize为data缓冲区的大小
    1 \4 X- A7 G3 w9 [- M
  365. // bufsize=0时, 只读取数据不存入缓冲区, K+ ^" D& S/ s9 t$ ?% q! V$ @6 c
  366. void WiFi_ReadData(uint8_t func, uint32_t addr, uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags)
    ! R. O! ~2 _4 X+ z& M  U' E% `
  367. {5 _6 r. ^5 ~! T) f
  368.         uint32_t len, temp;  D* z# w1 @# [* f
  369.         if (flags & CMD53_BLOCKMODE)  {0 q5 |9 G) U8 N* R9 ]- H$ w
  370.         {0 _! x) c& I; h2 {- R2 K
  371.                 len = count * WiFi_GetBlockSize(); // count表示数据块数$ W; K( U8 k; Q# U2 x
  372.                 SDIO->DCTRL &= ~SDIO_DCTRL_DTMODE; // Block模式
    $ E+ [6 ~, R( m) W
  373.         }, [, P/ v/ Q2 _8 J  ]2 T
  374.         else
    6 y9 o" z; L( ~/ q1 B
  375.         {3 `. Q9 f; O. o& X  ?& C9 c
  376.                 len = count; // count表示字节数
    , G5 Z/ C4 l. A3 P' |
  377.                 if (len % 4 != 0)
    * E$ ?3 z5 t" ?
  378.                 {9 D& A) w' g4 E! Y  P1 S# U
  379.                         len += 4 - len % 4; // WiFi模块要求写入的字节数必须为4的整数倍' S; o& P1 o6 `/ h
  380.                         count = len;' T9 J/ ^" n6 e2 C6 h1 N! w: B
  381.                 }
    ' `" K; h) Q% X: B5 i' g! k
  382.                 SDIO->DCTRL |= SDIO_DCTRL_DTMODE; // Multibyte模式! I) X4 r  ]2 Q8 n- z0 j/ p
  383.         }" ?2 ?% V5 }- `+ \
  384.         SDIO->DLEN = len;
    # k( F  v' i3 w7 P7 S, Z6 S
  385.         SDIO->DCTRL |= SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTEN; // 设置传输方向为从模块到主机7 {$ ^, Y. N' K: J& _. ]+ l
  386.         8 l5 A- w. v. H
  387.         WiFi_SendCMD53(func, addr, count, flags);: m* r" O, i0 Y! m+ C6 A; f: R1 {
  388.         while (len)( t# s- R" \; F$ X  s( c3 H* b
  389.         {
    * |0 _8 z" p( l1 r8 u+ ~1 c
  390.                 if (SDIO->STA & SDIO_STA_RXDAVL)
    ! Y4 {- q# h+ t* k3 o; ^
  391.                 {
    ; p9 p; x. f" {3 y
  392.                         // 若有数据到来就读取数据
    ' U" r! v) X7 m9 J
  393.                         len -= 4;
    4 X* v4 x* B) y; x
  394.                         if (bufsize >= 4)
    ) F: P. V& p( ?2 \
  395.                         {
    ' M4 n3 J, j  N" g3 e4 m
  396.                                 *(uint32_t *)data = SDIO->FIFO;! S7 d2 }' s, K) b3 j' ]$ z0 {# h
  397.                                 data += 4;
    , V( u6 l; z. |  q
  398.                         }9 d% W5 _9 F1 I1 e' ^* t
  399.                         else
    , X2 M: w% ^" f/ z
  400.                         {
    : t* h2 R8 |" L! j
  401.                                 temp = SDIO->FIFO;- T2 |3 A7 r* g' F$ ^' b
  402.                                 if (bufsize > 0)
    ' ?+ E* E. p7 {0 w+ J# v5 L' w
  403.                                 {
    2 o( W' j5 [9 A0 B8 v: ~
  404.                                         // 写入缓冲区最后1~3字节
    : T, k$ d8 @9 g% A: i# T5 l: J
  405.                                         memcpy(data, &temp, bufsize);
    1 i3 m% ]9 Q9 ]# U, u
  406.                                         bufsize = 0;: y& q* ~# B% V, M: i9 B0 w
  407.                                 }
    & c, ^1 n; o+ e, f! r
  408.                         }
    ; p  ^# {* O% B" d. G+ S
  409.                 }
    9 D, o) r( E! P# i* ~9 B
  410.                 4 U- B8 Y$ t- x: [3 v0 _
  411.                 if (SDIO->STA & SDIO_STA_DTIMEOUT)( u- r0 j  _, T8 C
  412.                 {7 G. g5 a5 ^, A! e; [$ f' ~
  413.                         printf("Data Timeout!\n");) p- w# q7 r1 n5 O# c
  414.                         break;; S  v* G+ u; s. S
  415.                 }1 C7 a5 G0 I) ?, m; d
  416.                 else if (SDIO->STA & SDIO_STA_DCRCFAIL)
    1 A# X! D5 F5 Y6 o$ n9 |
  417.                 {
    + f7 B5 Q0 L7 [: E8 C  n' }
  418.                         printf("Data CRC check failed! %d bytes are lost\n", len);
    # ~7 W- t  z$ e4 M1 C% F, R
  419.                         break;
    , `/ d- d5 D" i# K
  420.                 }% O% f$ U; G1 f. Z/ e
  421.         }: `8 Z, G: Q+ `5 e, t8 f
  422.         " u  u+ [: O8 ?/ W" H, X/ Z. E
  423.         while (SDIO->STA & (SDIO_STA_CMDACT | SDIO_STA_RXACT));
    6 d, j$ g8 t" i* X+ e$ s
  424.         SDIO->DCTRL &= ~SDIO_DCTRL_DTEN;
    2 p8 V3 ^, t( i8 D
  425.         5 {- W* r. Y0 q1 m9 B/ P* E
  426.         SDIO->ICR = SDIO_STA_DATAEND | SDIO_ICR_CMDRENDC;2 [3 }; R7 T. @% t
  427.         if (flags & CMD53_BLOCKMODE)7 l0 F, c: Q; C% L# j6 f- t
  428.                 SDIO->ICR = SDIO_ICR_DBCKENDC;
    / V3 ]) T1 Z1 x4 f& r
  429.         9 N! ]; e0 C. j: i# {
  430.         // 通过判断SDIO->STA是否等于0可知传输是否成功+ b/ P! B5 s! c! @) r/ ~
  431. }
    : I) n8 i! }: [0 X" M" j4 r5 {* s

  432. . v* Z- \9 K2 A2 P( X  M1 X& Q
  433. uint16_t WiFi_ReadPort(void *buf, uint16_t size, uint16_t bufsize)
    " A4 k4 K* A7 T- z
  434. {
    2 K+ B$ o) Z$ D# S. y
  435.         uint16_t block_num, block_size;
    ' s* k$ |# }7 y  f1 a: L
  436.         block_size = WiFi_GetBlockSize();, U% m& u! ^' L3 ], \
  437.         
    : M" b$ N) S8 F
  438.         // 读取数据
    % Q; o+ b+ i9 b# m
  439.         WiFi_Wait(0); // 发送CMD53前必须IOReady=14 u8 @7 U( T1 C# k8 ?0 g6 D
  440.         if (size >= 512 || size % block_size == 0)  l3 ]3 f3 h4 L. ^/ P6 G: y+ E2 X$ D
  441.         {- k' y! J" _! \7 g
  442.                 // 采用Block模式传输& S# ~. r* _6 r
  443.                 block_num = size / block_size;) h) g5 m3 M* `9 M8 P1 K- Z7 e
  444.                 if (size % block_size != 0)
    + h* [; v0 ]& J. ~: U6 J. k: I$ F
  445.                         block_num++;
      X  `$ S: u4 d% M
  446.                 7 ^7 y6 J5 [/ q" |7 l/ J4 R
  447.                 WiFi_ReadData(1, io_addr, buf, block_num, bufsize, CMD53_BLOCKMODE);
    % J8 I- X$ `7 W
  448.         }3 b2 p& \- G/ }4 Y, r& P
  449.         else* {' g, A* }$ ?' T& ^  ~  z( `2 ^
  450.                 WiFi_ReadData(1, io_addr, buf, size, bufsize, 0);
    % t" @2 ~6 {4 k3 E5 P: ^2 k
  451.         0 E% c3 I2 A, D! l/ N7 u* w
  452.         return SDIO->STA == 0;
    $ X. N9 ]/ s& ~+ ], Z
  453. }7 U4 V- s/ g. x# H8 {, b/ L
  454. : z& f1 w6 ]# O2 J
  455. /* 接收数据帧 */. R2 C5 k* X8 K# y4 V) X0 W
  456. uint16_t WiFi_ReceivePacket(void *buf, uint16_t bufsize)2 D- p) d) u8 T3 t0 s6 Q
  457. {
    . {2 k7 J3 E! L! z( [: I; U
  458.         uint16_t size;4 {! T1 L. P4 \" K& k
  459.         if (wifi_pending_size)
    / m7 {! @# [+ |+ u
  460.         {5 b9 ?9 P9 ~* J3 A; d$ D8 ^
  461.                 size = wifi_pending_size; // 先读取滞留的数据包
      M5 ~9 {- S& c' R3 n1 _  U
  462.                 wifi_pending_size = 0;
    2 {, Z) s+ i4 g+ Z0 X
  463.         }6 a& m9 r% Y1 U# v3 b0 f4 M8 r$ s9 f
  464.         else
    1 Y; l0 |3 \" c; a( J% E
  465.                 size = WiFi_GetPacketLength();" [' _- m3 }2 y, B
  466.         return WiFi_ReadPort(buf, size, bufsize);
    ; B) x* k, W7 ]/ V. g
  467. }
    1 l+ |8 o* |2 c3 o

  468. ' q; ^2 V# {# y) T* j# O
  469. /* 接收WiFi命令的回应 */
    , G9 b. b1 e4 G2 p7 N) {
  470. uint16_t WiFi_ReceiveResponse(void *buf, uint16_t bufsize)
    2 |9 c- W7 h( p& }' Q( A6 L8 P
  471. {  E% S: a" U* M( N
  472.         uint8_t retry_cnt = 0; // 重试次数
    - r: w( O0 X0 |6 i$ p
  473.         uint8_t wait_status, resend;
    6 s+ `. X; G& x& ~& K9 p5 n$ r7 P
  474.         uint16_t size;
    ' b2 v, m  G; D
  475.         WiFi_CommandHeader *cmd = (WiFi_CommandHeader *)buf;6 u! d! U! [* _4 `
  476.         WiFi_SDIOFrameHeader temp;8 e# E) w" X: h
  477.         1 }2 a, U9 v+ F5 s
  478.         // 等待数据准备好
    & p5 U, A7 E$ X
  479.         do
    $ I" Z1 i9 k+ m' r( g' i, x5 r. {
  480.         {$ o( n- W; u0 j: W. h' Z0 v0 p
  481.                 wait_status = WiFi_Wait(WIFI_CARDSTATUS_UPLDCARDRDY);2 F/ D5 s2 C, [0 r  J, T/ m. G3 q1 f
  482.                 3 w9 P; [: ^* T. R
  483.                 WiFi_ReadPort(&temp, sizeof(temp), sizeof(temp)); // 试着读取头部信息
    5 M; V! R3 h# q/ |* X1 B0 R: d/ v. \
  484.                 if (temp.type == WIFI_SDIOFRAME_DATA && temp.length > 0) // 若读取到一个数据帧的头部
    ; e' i$ I  \! G) `& `5 a0 u
  485.                 {
    2 M% c. t3 e' Q5 x% G
  486.                         // 若读到的是一个数据帧, 不是命令回应- e9 x7 {. b2 m. p/ |/ j
  487.                         // 则直接丢掉该数据帧, 然后重发命令, 保证命令执行成功
    & }. u' W  V5 N6 V7 s4 ]
  488.                         printf("A packet of %d byte(s) preempted the command!\n", temp.length);$ v( F. m/ u7 j9 q3 l% o" {& j+ m. q
  489.                         wifi_pending_size = temp.length;
    # `+ Y, H9 K/ ~$ v* |& s3 _+ C5 P
  490.                         WiFi_DropPacket(); // 必须读取完整个数据包, 只读完头部不算
    7 H( X1 d. a# s! i5 q: I
  491.                         resend = 1;
    # Q: t( c+ }4 U8 e
  492.                 }5 m7 ?5 G) P! l; o+ e, w
  493.                 else if (wait_status == 0)
    4 T+ u; p0 `8 s. t
  494.                 {2 B1 s  v# ?( M2 r5 B2 V% z4 h
  495.                         // 若WiFi_Wait返回0, 则说明超时 (状态位在规定的时间内未置位)
    ! w+ ^6 }3 P; I( B
  496.                         resend = 1;
    : Y- y6 o. s' E" ]
  497.                         retry_cnt++;* v2 R9 @3 X2 |
  498.                         if (retry_cnt >= 5)
    6 ?6 m4 P6 x# I: H
  499.                         {$ b0 b* t/ g6 v. K4 s0 f
  500.                                 printf("No response!\n");/ r, s6 h; @6 z3 Z. X/ {
  501.                                 return 0;) B+ |  R# e6 O6 f  G; Y
  502.                         }
    " Z+ x% u$ Q$ a: y! }, H8 y: Q
  503.                 }9 X1 ^+ _: ~, S9 J( c) s
  504.                 else
    1 P' X  u% _% a9 q1 S
  505.                         resend = 0;, _" y# m# @: i: u' N
  506.                 3 z* @8 \0 D% d1 n% ~  H3 \4 s
  507.                 if (resend)
    ( N3 O! U: T! e4 c5 v
  508.                 {
    % Z- I) o* B% k! z
  509.                         if (cmd->frame_header.type == WIFI_SDIOFRAME_COMMAND)
    9 B# I. W. f8 g- ?
  510.                         {
    5 P' P, H2 }3 @" U9 P8 z$ U
  511.                                 // 若超时后还没收到数据, 则重发命令, 然后再次执行WiFi_Wait6 i( b( F: ]8 v
  512.                                 printf("Resend WiFi command 0x%04x! size=%d\n", cmd->cmd_code, cmd->frame_header.length);: o# c, ~2 W8 y2 h  |) @
  513.                                 WiFi_ResendCommand(buf);
    % l) }0 U2 }! q' n! n
  514.                         }
    0 k0 q* x( k9 t! ?5 ^  S
  515.                         else" W6 {6 i9 J+ Y7 _( S' m/ `
  516.                                 return 0; // 若buf中的内容不是命令, 则直接退出
    % j* o2 S2 D' N3 ?$ t5 M2 i
  517.                 }
    1 T5 V9 i* z9 ~; x8 A3 o3 `
  518.         } while (resend);
    4 v. O3 }3 b7 y- c1 @5 X
  519.         + \9 Y9 z- x! Y: B2 b$ g
  520.         size = WiFi_GetPacketLength();
    ! Z3 k5 E, K* W' u; q, T3 X6 a
  521.         if (size > bufsize)
    # ], \2 x. ^) V( H9 x; F: B2 ~; ~: W% s
  522.                 printf("WiFi_ReceiveResponse: Buffer size is too small! %d bytes required!\n", size);
    $ o+ o8 z  ~/ K- I3 {' s
  523.         return WiFi_ReadPort(buf, size, bufsize);5 p* A2 v" I9 G; B
  524. }
    0 i, I. a9 ]& n0 Q1 U$ @' u; p% {
  525. & e8 {! b: H( c4 U- w) i
  526. /* 扫描全部热点 (仅显示) */6 U) D2 I7 g1 h7 k- @# L
  527. void WiFi_Scan(void)
    * H2 y" Y/ b6 X
  528. {
    8 K6 E9 h; h3 S& S3 q) i0 X
  529.         // 必须把STM32启动文件*.s中的Stack_Size改大, 否则函数中无法创建大数组
    - u2 I1 O2 A5 [7 L( y" F
  530.         // Stack_Size=0x00000c00
    0 q' U- l) w5 t  ~( C& b2 o; ?
  531.         uint8_t buffer[2048]; // 用于接收返回的WiFi接入点信息, 需要较大的内存空间来存放- C6 x8 z+ v/ _1 z8 m' m
  532.         uint8_t i, j, n;
    # N( B2 @1 T: V$ ^5 }! _
  533.         uint8_t ssid[33], channel, wpa;* m. l- ]/ }' s! x  @! O
  534.         uint16_t ie_size;9 e0 [, I7 ^- C& C" D4 d
  535.         
    + s! |. {' ^' ^# Z$ z" @& `
  536.         WiFi_CmdRequest_Scan *cmd = (WiFi_CmdRequest_Scan *)buffer; // 用buffer空间来存放要发送的命令
    " i& K; U/ H! `
  537.         MrvlIETypes_ChanListParamSet_t *chanlist = (MrvlIETypes_ChanListParamSet_t *)(buffer + sizeof(WiFi_CmdRequest_Scan));3 K' J: B7 e4 D4 T
  538.         
      A" T" f4 y5 k6 G* q4 G
  539.         WiFi_CmdResponse_Scan *resp = (WiFi_CmdResponse_Scan *)buffer;4 X3 q) H" J0 N' ^' V% m
  540.         WiFi_BssDescSet *bss_desc_set;
    ! P) o- y0 u- }. ^! R* V4 B
  541.         WiFi_VendorHeader *vendor;4 E3 i& j* J2 B+ ^; ^  `# L4 U
  542.         IEEEType *ie_params;( n1 X  K9 h" }( ?
  543.         //MrvlIETypes_TsfTimestamp_t *tft_table;1 r2 R' I; m" U. b8 R
  544.         ! T  d5 k" d. e- u* u
  545.         // 分4次扫描14个通道; V7 \/ ~9 M- ?; H
  546.         for (i = 0; i < 4; i++)
    ; P! Q  L7 ~- k% \$ F2 O
  547.         {
    * S' R5 ^% v7 ~# k7 B
  548.                 cmd->bss_type = BSS_ANY;
    + Q: f8 F1 r% s  j: e
  549.                 memset(cmd->bss_id, 0, sizeof(cmd->bss_id));/ q, q# G" }2 Z1 y  _
  550.                
    2 t9 F" d6 H  U
  551.                 // 通道的基本参数
    + ]  n4 O( Y# Z9 y5 l+ v
  552.                 n = (i == 3) ? 2 : 4; // 本次要扫描的通道数
    + B7 M# i& w' o9 A6 b# {$ K
  553.                 chanlist->header.type = MRVLIETYPES_CHANLISTPARAMSET;
    9 U7 q  i. Z& n5 I* ?7 `$ L; \  v1 m% |
  554.                 chanlist->header.length = n * sizeof(chanlist->channels);
    + b) U+ ^& s  H
  555.                 for (j = 0; j < n; j++)
    * v2 K* b5 D9 }
  556.                 {
    1 u5 Y& s' R6 z3 Q/ s2 w7 I' c
  557.                         chanlist->channels[j].band_config_type = 0;
    6 Y& q/ w# v% ^0 {7 R
  558.                         chanlist->channels[j].chan_number = 4 * i + j + 1; // 通道号
    ' a2 V4 K% |- ~5 r6 H+ P
  559.                         chanlist->channels[j].scan_type = 0;$ z9 ~1 E% W" O
  560.                         chanlist->channels[j].min_scan_time = 0;
    6 N, R7 u+ A8 E; ]6 `/ H% Q2 A) _
  561.                         chanlist->channels[j].max_scan_time = 100;% E) i1 T) _; w1 C# N$ V5 O
  562.                 }% s  ?9 i, S4 V2 {) k& }& h4 l
  563.                
    $ j# L6 J& b1 r2 Y, S8 V
  564.                 // 发送命令并接收数据
    ) x0 O7 }* ]  k( N: r
  565.                 WiFi_SendCommand(CMD_802_11_SCAN, buffer, sizeof(WiFi_CmdRequest_Scan) + sizeof(chanlist->header) + chanlist->header.length);
    8 {4 B0 J2 L1 V9 ^: e; \: Q
  566.                 WiFi_ReceiveResponse(buffer, sizeof(buffer)); // 接收的数据会将cmd和chanlist中的内容覆盖掉: i* [+ q& W/ r
  567.                
    , q% Q0 B4 M1 D- m# u* c
  568.                 // 显示热点信息, num_of_set为热点数
    1 j7 a# l( T, D# a; S
  569.                 if (resp->num_of_set > 0)
    0 A' c% q, _5 r& V
  570.                 {- `( j$ }- ]& J* l- j
  571.                         bss_desc_set = (WiFi_BssDescSet *)(buffer + sizeof(WiFi_CmdResponse_Scan));# `' e0 a1 {  o& L2 h/ T
  572.                         for (j = 0; j < resp->num_of_set; j++), [  r0 ~9 B, s6 ~
  573.                         {% r0 ^9 l9 K8 r" x# p7 m* l
  574.                                 wpa = 0;" Z' Z# k6 i6 g+ _/ P
  575.                                 ie_params = &bss_desc_set->ie_parameters;
    3 ~. p+ C* e3 i" F! |* Z" w/ u6 F
  576.                                 ie_size = bss_desc_set->ie_length - (sizeof(WiFi_BssDescSet) - sizeof(bss_desc_set->ie_length) - sizeof(bss_desc_set->ie_parameters));4 I+ G: h! ?( q- b7 \- `
  577.                                 while (ie_size > 0)/ p. A, m' O# C7 `
  578.                                 {
    8 _% X' I9 c  e3 \
  579.                                         switch (ie_params->type)
    - E' `3 L+ P- e5 \* Y1 `
  580.                                         {
    : J' L3 P7 B5 d! k( ?0 l
  581.                                         case MRVLIETYPES_SSIDPARAMSET:
    ! ^! w+ V, N% \" \* X: k" n8 E$ I
  582.                                                 // SSID名称
    * t5 l# J  V4 z5 q& |8 `( @+ o
  583.                                                 memcpy(ssid, ie_params->data, ie_params->length);9 K1 L4 F% l" p8 a( Z  A
  584.                                                 ssid[ie_params->length] = '\0';
    5 c* K! S, a, w: f. w7 J
  585.                                                 break;  z0 _* V$ k9 O+ v
  586.                                         case MRVLIETYPES_DSPARAMSET:! k. @/ C" |+ P: x" g
  587.                                                 // 通道号, }' R+ |( M# A% _% ~+ a% X
  588.                                                 channel = ie_params->data[0];) n/ @5 ^& k& f6 ?' f# I
  589.                                                 break;3 Y% u$ U$ B& ^. j. X* i" {
  590.                                         case MRVLIETYPES_RSNPARAMSET:: C2 i, J3 I. q
  591.                                                 wpa = 2;2 N1 D1 n& ~3 b& F, p
  592.                                                 break;6 Y/ ~. s9 _' T7 [/ `& k
  593.                                         case MRVLIETYPES_VENDORPARAMSET:
    ! d' j' b& F- ~+ U, \
  594.                                                 if (wpa == 0)
    5 K% l. r& ]1 [2 n* H
  595.                                                 {
    % z5 z1 {  H) {
  596.                                                         vendor = (WiFi_VendorHeader *)ie_params->data;2 D4 [$ ?: h' O2 G+ m9 _0 O/ p! b
  597.                                                         if (vendor->oui[0] == 0x00 && vendor->oui[1] == 0x50 && vendor->oui[2] == 0xf2 && vendor->oui_type == 0x01)
    & p! L. L: M+ y1 [+ i) @! `/ u
  598.                                                                 wpa = 1;
    4 y& I) |0 m) k
  599.                                                 }& l* E* p' k# e0 T
  600.                                                 break;
    - l# h! _: o+ m+ @9 Q
  601.                                         }! R+ u: o2 L: y. J9 {) C
  602.                                         ie_size -= ie_params->length + 2;
    2 j+ d" ?+ g/ u
  603.                                         ie_params = (IEEEType *)((uint8_t *)ie_params + ie_params->length + 2);
    0 _) e- \2 d4 z+ `7 K
  604.                                 }
    ! h# _3 W+ \/ a) ?& R
  605.                                 if (ie_size != 0)
    $ |3 a& n1 ]* b. {* h8 {! b
  606.                                         printf("ie_parameters error!\n");
    & ^5 x8 z: Y  e7 Z
  607.                                 
    6 `. @) _! i3 L& ~* Y
  608.                                 printf("SSID '%s', ", ssid); // 热点名称) q6 W1 P$ }( s  r* g4 h5 N
  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地址
    ) [$ Q( ?7 w$ p0 L* _/ B! r
  610.                                 printf("RSSI %d, Channel %d\n", bss_desc_set->rssi, channel); // 信号强度和通道号
    # s! m5 G& Y3 I7 Y1 r  b+ p3 p
  611.                                 //printf("  Timestamp %lld, Beacon interval %d\n", bss_desc_set->pkt_time_stamp, bss_desc_set->bcn_interval);% [6 K. E7 w3 P! }7 C
  612.                                 : `8 G7 r" V( U- D* `! b. `4 X
  613.                                 printf("  Capability: 0x%04x", bss_desc_set->cap_info);
    / ]0 ~* L, b4 l) j4 ?/ n
  614.                                 if (bss_desc_set->cap_info & WIFI_CAPABILITY_PRIVACY)) I( f. ]3 _: q# t
  615.                                 {
    6 z" U0 }0 |& \4 Z& |
  616.                                         if (wpa == 1)
    " x5 j, d/ k- o) s3 V# p
  617.                                                 printf("(WPA: ON, ");+ n7 x2 I( e7 B+ C, ~" S' u2 m
  618.                                         else if (wpa == 2)! U) ~3 E$ z! K; l( n9 Q" A
  619.                                                 printf("(WPA2: ON, ");. K6 f" D2 u  j- w  c9 r5 t3 q
  620.                                         else
    . j1 q$ Q: d( O) I+ h2 d: e, ^4 M4 r
  621.                                                 printf("(WEP: ON, ");  A. p7 l" z5 e: f0 J2 [  \$ z- |
  622.                                 }
    0 Z6 _- g9 T- @7 o; i  v, Z
  623.                                 else
    ! b9 I$ i' V/ T$ y; w. _; m0 g& M  Y
  624.                                         printf("(WEP: OFF, ");
    - u+ J1 N" v3 Q9 s
  625.                                 2 E  L, V; G# b! n: V
  626.                                 if (bss_desc_set->cap_info & WIFI_CAPABILITY_IBSS), l" A, C, v5 `  n) b& m7 b
  627.                                         printf("mode: Ad-Hoc)\n");$ Q" E. \9 h$ _8 l
  628.                                 else# e5 f/ h! e7 E! [
  629.                                         printf("mode: Infrastructure)\n");0 F/ W! W  O, M# B$ S2 L9 f" U$ w7 b
  630.                                 & j" f4 s- m: H4 K  g: K7 i* b
  631.                                 // 转向下一个热点信息
    4 E6 l% V# {- x) D$ b0 z  L
  632.                                 bss_desc_set = (WiFi_BssDescSet *)((uint8_t *)bss_desc_set + sizeof(bss_desc_set->ie_length) + bss_desc_set->ie_length);/ t7 b- O4 Q# b9 U- [; |
  633.                         }0 W% }- Y. X4 i  t$ j# t
  634.                         
    7 D" x  l' I! n% i# B+ M- E% h, V
  635.                         // resp->buf_size就是bss_desc_set的总大小
    ; G+ F# _+ d6 O, n
  636.                         // 因此tft_table == buffer + sizeof(WiFi_CmdResponse_Scan) + resp->buf_size
    ) R+ F2 I% i; V
  637.                         /*tft_table = (MrvlIETypes_TsfTimestamp_t *)bss_desc_set;: Y$ |2 W  q$ R3 D* G  N% p
  638.                         if (tft_table->header.type == MRVLIETYPES_TSFTIMESTAMP && tft_table->header.length == resp->num_of_set * sizeof(uint64_t))
    8 E+ Q, p; P/ v) c* @5 o4 E- H
  639.                         {# W5 L, M# a' P; M
  640.                                 printf("Timestamps: ");
    . `) L2 a  R0 J1 C2 i5 c) @
  641.                                 for (j = 0; j < resp->num_of_set; j++)# w# U; _2 A3 U4 ~+ S9 Q9 y
  642.                                         printf("%lld ", tft_table->tsf_table[j]);1 I* i0 T/ Y) Z
  643.                                 printf("\n");. T" @/ j, c( r
  644.                         }*/
    # t7 I: F- x; x  \; B
  645.                         
    ; K- ~6 y& [) k& U4 r1 T$ e' n0 W
  646.                         // TSF timestamp table是整个数据的末尾, 后面没有Channel/band table
    & x/ P: Y5 Y; t$ Z1 m8 a
  647.                         //if (((uint8_t *)tft_table - buffer) + sizeof(tft_table->header) + resp->num_of_set * sizeof(uint64_t) == cmd->header.frame_header.length)
    1 }1 N9 [, Y3 i  H2 q  i
  648.                         //        printf("data end!\n");
    % E+ m- s6 I" M# {4 b
  649.                 }. Q9 Q" Q8 T: g6 {
  650.         }
    ; j( Y3 T0 Q  P' W, R
  651. }
    & Q7 A5 B; z' m

  652. 8 R: G3 I9 f7 W4 \8 F
  653. /* 扫描指定名称的热点 */+ M4 ^' a% Q5 l! Z/ D& q7 |
  654. // buffer用来存放返回的全部结果, 因此bufsize应该足够大& u/ s' a6 F7 C/ H) `) \: w1 W
  655. // info用来存放从buffer中提取出来的一些常用信息
    + |* k" M& L, f1 S0 A# e' b: d
  656. uint8_t WiFi_ScanSSID(const char *ssid, WiFi_SSIDInfo *info, uint8_t *buffer, uint16_t bufsize)( K; p! U( [8 ~8 L8 r2 Z* ~( Q
  657. {5 @: V& S' [+ @0 L+ i1 j
  658.         uint8_t i;
    8 b1 Q' p3 |4 F, z9 N# ]
  659.         uint16_t ie_size;( ^7 ?3 L5 [3 o/ ?: j
  660.         WiFi_CmdRequest_Scan *cmd = (WiFi_CmdRequest_Scan *)buffer;
    # n  O( g9 z6 c( I8 g. p
  661.         WiFi_CmdResponse_Scan *resp = (WiFi_CmdResponse_Scan *)buffer;; `4 G) T0 [' y3 p- ^0 O
  662.         WiFi_BssDescSet *bss_desc_set = (WiFi_BssDescSet *)(resp + 1);. o$ W$ e3 O5 d4 I& g- t
  663.         MrvlIETypes_ChanListParamSet_t *chan_list;
    & L9 \6 e/ C; U. ]# |
  664.         IEEEType *ie_params;
    0 R" I& X+ F: M( ?  X' k+ H* Q
  665.         WiFi_VendorHeader *vendor;
    9 D4 s, r/ n8 |% M: p# G
  666.         # X! d3 O; b. n* E# ^: a
  667.         cmd->bss_type = BSS_ANY;
    & c* k! u! |# Y5 _
  668.         memset(cmd->bss_id, 0, sizeof(cmd->bss_id));
    $ |' G! {9 T' M6 `
  669.         
    5 n- I8 ~0 o8 S' g2 u* Z& K
  670.         // 添加ssid参数# E% @; M6 _5 Y1 F
  671.         info->ssid.header.type = MRVLIETYPES_SSIDPARAMSET;* f' x1 A4 W- @& U+ L) T6 P/ B- r
  672.         info->ssid.header.length = strlen(ssid);
    & _% [2 w) W. B9 r
  673.         memcpy(info->ssid.ssid, ssid, info->ssid.header.length);
    5 S: b8 E; w! M* \* }- t- |: j. X
  674.         memcpy(cmd + 1, &info->ssid, MRVLIE_STRUCTLEN(info->ssid));
    2 O- @4 q9 _: c! `0 Q; g
  675.         6 O( {' ]1 w5 m' _( g! ]2 R/ k
  676.         chan_list = (MrvlIETypes_ChanListParamSet_t *)((uint8_t *)(cmd + 1) + MRVLIE_STRUCTLEN(info->ssid));
    2 _" h6 B3 n, J
  677.         chan_list->header.type = MRVLIETYPES_CHANLISTPARAMSET;3 |* P$ p( l5 {- ^2 O
  678.         chan_list->header.length = 14 * sizeof(chan_list->channels); // 一次性扫描14个通道6 g) U! Y6 p! a6 Z  @
  679.         for (i = 0; i < 14; i++)3 O9 f  c1 h) c' g( P: N) k& R
  680.         {
    ( w9 g. J5 ^# h6 g  [
  681.                 chan_list->channels[i].band_config_type = 0;
    8 P1 ?0 c( `) Z4 S, W
  682.                 chan_list->channels[i].chan_number = i + 1;
    6 k' L: ~9 U8 ^1 i* V3 t1 y
  683.                 chan_list->channels[i].scan_type = 0;. I9 B7 L8 F/ f# C" r" J# s0 q( z
  684.                 chan_list->channels[i].min_scan_time = 0;! `! ~' @4 ]/ y+ b; ^3 d
  685.                 chan_list->channels[i].max_scan_time = 100;: _1 r- z; [4 h& ~6 Y
  686.         }
    ! \6 |" l7 {# B5 P7 ^
  687.         & l3 f7 K2 F9 C* W) r* M
  688.         WiFi_SendCommand(CMD_802_11_SCAN, buffer, ((uint8_t *)chan_list - buffer) + MRVLIE_STRUCTLEN(*chan_list));/ z& s# u; l1 u6 M8 S
  689.         wifi_timeout = 3000; // 延长超时时间6 _: E7 _( J& r2 S  N! L  }8 j
  690.         WiFi_ReceiveResponse(buffer, bufsize);
    ) t3 N- F" ^* [3 \( N
  691.         wifi_timeout = WIFI_DEFAULTTIMEOUT;
    " z8 l3 T$ ^7 G8 g/ i
  692.         - ]% E( O7 p  f' v+ b
  693.         if (resp->num_of_set == 0)+ P+ ^& A8 ~4 h, s' W
  694.                 return 0; // 失败
    5 \0 S& F1 p  t. @; b& ~
  695.         
    $ ?+ u, _7 K! Y3 f- |) A- b" H8 b
  696.         // bss_desc_set以扫描到的第一个信息项为准
    7 E8 g. K& h* c3 R
  697.         memcpy(info->mac_addr, bss_desc_set->bssid, sizeof(info->mac_addr));
    * a& a3 O( T5 t
  698.         info->cap_info = bss_desc_set->cap_info;
    & e8 P1 F9 q# P: h) Z- X. \
  699.         info->bcn_period = bss_desc_set->bcn_interval;( E  |6 }! y5 D
  700.         
    / i# N8 S% d! z# p+ `4 P2 e
  701.         // 若type=0, 则表明没有该项的信息 (除SSID结构体外, 因为SSID的type=MRVLIETYPES_SSIDPARAMSET=0)" `9 P) o5 A( \, `
  702.         info->rates.header.type = 0;$ i( C" o! K; X- L4 Q
  703.         info->rsn.header.type = 0;
    8 I2 Y. Q8 G- N/ Y' q8 t  h
  704.         info->wpa.header.type = 0;: t, E  G" V: \( v
  705.         info->wwm.header.type = 0;. q0 X: W; W1 B" u8 G- A6 {/ n! m
  706.         info->wps.header.type = 0;
    . b# G' w$ \  ^
  707.         * B7 M% H% E- y
  708.         ie_params = &bss_desc_set->ie_parameters;
    + m7 G2 [% D8 n+ j+ u
  709.         ie_size = bss_desc_set->ie_length - (sizeof(WiFi_BssDescSet) - sizeof(bss_desc_set->ie_length) - sizeof(bss_desc_set->ie_parameters));! m! d8 q. f* b$ O0 l/ {
  710.         while (ie_size > 0)+ Q% ]+ l7 a  F* Z4 z3 y% ]
  711.         {& `8 A; w9 H; X9 [% V, o5 ^  a) k6 p
  712.                 switch (ie_params->type)
    - ?0 \, Y; C0 J8 X1 U/ n
  713.                 {
    & K. Q- G0 l/ \, H
  714.                 case MRVLIETYPES_RATESPARAMSET:& X: V1 ^, u  a: {
  715.                         // 速率( a1 G; E- w. \
  716.                         info->rates.header.type = MRVLIETYPES_RATESPARAMSET;) L6 Q$ a' {) B' L! Y1 x* }' a( q
  717.                         info->rates.header.length = ie_params->length;
    9 y! ~5 q7 I1 I
  718.                         if (info->rates.header.length > sizeof(info->rates.rates))
    5 W1 z1 C4 _% M1 T- {5 T
  719.                                 info->rates.header.length = sizeof(info->rates.rates);
    2 [% v) j: l/ P3 y: M3 ]  }
  720.                         memcpy(info->rates.rates, ie_params->data, ie_params->length);
    % f: x6 p- q6 D
  721.                         break;
    3 H( @+ f2 M' c8 O% N) W
  722.                 case MRVLIETYPES_DSPARAMSET:8 Y8 `% }  _) B8 o, W* e
  723.                         // 通道号
    ( k1 d  o# U6 }* r6 g" S
  724.                         info->channel = ie_params->data[0];
    ( P( S7 |0 k: X  V
  725.                         break;2 c& U/ q7 F1 _# f2 n
  726.                 case MRVLIETYPES_RSNPARAMSET:
    3 @; q" t2 r) b( }! f; t7 c0 {
  727.                         // 通常只有一个RSN信息 (与WPA2相关)' S7 J+ ^" e5 I  u  z( @( r
  728.                         // printf("RSN len=%d\n", ie_params->length);
    ! i! {$ I' m6 Q4 r4 M4 S
  729.                         info->rsn.header.type = MRVLIETYPES_RSNPARAMSET;6 g8 p+ n% C% w/ Z4 V
  730.                         info->rsn.header.length = ie_params->length;( {8 H& \- F  `0 T( ?& i, z9 ^
  731.                         if (info->rsn.header.length > sizeof(info->rsn.rsn))
    " Z: e* ?( u; s8 X/ n) b
  732.                                 info->rsn.header.length = sizeof(info->rsn.rsn);
    + p# z! C1 G/ y' u8 O5 i
  733.                         memcpy(info->rsn.rsn, ie_params->data, info->rsn.header.length);
    # f/ ], ^6 j  Q$ F% I
  734.                         break;
    , U% Q8 n' U5 B) ^& N  W  k' E: _8 u
  735.                 case MRVLIETYPES_VENDORPARAMSET:
    * F6 |+ s+ ~  w3 T6 X$ |4 z
  736.                         // 通常会有多项VENDOR信息 (与WPA相关)
    # v  e; I) v" p6 M6 `! X2 {
  737.                         vendor = (WiFi_VendorHeader *)ie_params->data;
    - m- W2 R& l+ W  `- P  R6 U
  738.                         if (vendor->oui[0] == 0x00 && vendor->oui[1] == 0x50 && vendor->oui[2] == 0xf2)9 |3 l% y& J9 Q% N$ h5 E! W
  739.                         {3 C% i8 n: a$ d
  740.                                 switch (vendor->oui_type)
    , l8 W: S  @. E) Y
  741.                                 {+ P) @9 t. N: {. w! T3 ]
  742.                                 case 0x01:
    + y4 }* J6 c: [5 Z/ s
  743.                                         // wpa_oui8 c# s6 k! f2 a
  744.                                         info->wpa.header.type = MRVLIETYPES_VENDORPARAMSET;& k3 `/ ?/ u, P
  745.                                         info->wpa.header.length = ie_params->length;
    4 O- \  r5 a. k
  746.                                         if (info->wpa.header.length > sizeof(info->wpa.vendor))
      r3 V) P; I0 ^1 S
  747.                                                 info->wpa.header.length = sizeof(info->wpa.vendor);
    ; r; c* @+ ?7 m" F6 b- u7 ~
  748.                                         memcpy(info->wpa.vendor, ie_params->data, info->wpa.header.length);/ j+ F2 M) K4 e
  749.                                         break;3 D7 n9 p8 e1 x* g! u
  750.                                 case 0x02:
    9 N! d" E. k3 N: l7 _3 ^
  751.                                         // wmm_oui$ i4 |8 r! L: `8 P/ E
  752.                                         if (ie_params->length == 24) // 合法大小
    8 j% q, m( s) a- b5 G, _+ |% g  I( G
  753.                                         {; j8 L, c9 r+ r; B# [; }) x& U
  754.                                                 info->wwm.header.type = MRVLIETYPES_VENDORPARAMSET;
    9 Y" R' X9 q6 l
  755.                                                 info->wwm.header.length = ie_params->length;
    2 U1 X$ S" M- U& l( S
  756.                                                 memcpy(info->wwm.vendor, ie_params->data, ie_params->length);' s% A/ ~. B' n  d9 k
  757.                                         }( o$ j# x' e& O% y" q' O0 m2 T, w
  758.                                         break;( d! m# ]! u4 d
  759.                                 case 0x04:" T. ?* t; e! z0 p2 {8 ?6 ?. z' @
  760.                                         // wps_oui
    1 Z) s: ]* ?5 j4 M4 j# k, w( c
  761.                                         info->wps.header.type = MRVLIETYPES_VENDORPARAMSET;
    / R; |) e, z. \
  762.                                         info->wps.header.length = ie_params->length;, o, ~+ |/ c' i+ |$ A
  763.                                         if (info->wps.header.length > sizeof(info->wps.vendor))/ M2 p( p- t8 e! A: K& q$ ]
  764.                                                 info->wps.header.length = sizeof(info->wps.vendor);
    ) N7 Q/ S( i  P, [6 U6 e' T* P
  765.                                         memcpy(info->wps.vendor, ie_params->data, info->wps.header.length);# w4 z9 ^, _. U/ S1 W
  766.                                         break;! ^7 q7 R6 G$ G  i! c! ^
  767.                                 }
    ( p  c3 G% P  K8 B  K
  768.                         }  t3 X5 I, i( y3 w
  769.                         break;6 o4 P8 y: i7 s( A9 L
  770.                 }
    9 s; E; u1 Q. H2 z/ H* W
  771.                 ie_size -= ie_params->length + 2;; r8 w& D( Y) G0 M, R) T- H
  772.                 ie_params = (IEEEType *)((uint8_t *)ie_params + ie_params->length + 2);) `0 H( H8 d2 f; h) l" ~
  773.         }3 b. }. G+ H7 x  w* Y* X; j# n( r
  774.         8 b. H( Q! \) o& C, a6 Y+ b
  775.         return 1; // 成功+ y! s6 S2 J% }: D
  776. }" w7 `& m  Z/ N8 E* s5 [

  777. $ f. B" _) V; f$ ~0 z* s
  778. void WiFi_SendCMD52(uint8_t func, uint32_t addr, uint8_t data, uint32_t flags)
    2 [/ l/ @3 j8 q) H
  779. {/ ]1 N2 s: d' {$ g* v$ \: Y: S
  780.         SDIO->ARG = (func << 28) | (addr << 9) | data | flags;
    7 z$ |/ K; q/ \
  781.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 52;
    : u! h" R$ ?/ U9 D4 F
  782.         while (SDIO->STA & SDIO_STA_CMDACT);: c$ F, l% P4 b
  783. }
    - r) u+ z! l5 m( A/ i
  784. : w' A& p1 J  u5 i1 ]/ g/ @* L
  785. void WiFi_SendCMD53(uint8_t func, uint32_t addr, uint16_t count, uint32_t flags)& r( V4 I* t9 F7 v. a) Q
  786. {* W" A- ~7 l; \+ u0 J" N- Z& V" x  j
  787.         // 当count=512时, 和0x1ff相与后为0, 符合要求, e. A7 l! K: y' |
  788.         SDIO->ARG = (func << 28) | (addr << 9) | (count & 0x1ff) | flags;: i( n1 o  _/ [7 m4 ^  \. B
  789.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 53;
    4 Z/ N" P) K2 H5 y
  790. }
    0 y6 w4 x5 F( [9 X, @7 R4 B
  791. 0 Y9 k# ]7 R. O( k& ~: U4 B
  792. /* 发送WiFi命令 */& h7 c: a8 k% I* [  b) i
  793. void WiFi_SendCommand(uint16_t com_code, void *data, uint16_t size)
    5 l! J+ D$ f8 i. I6 C+ K
  794. {7 j1 b  m0 s0 h1 p( Y
  795.         static uint16_t seq_num = 0;/ R/ s. N' _) L) n' I
  796.         WiFi_CommandHeader *cmdhdr = (WiFi_CommandHeader *)data;) I# t' i7 k" O4 O, }
  797.         $ N% ]' ^) W; G0 @
  798.         if (size != 0)
    ( O* b& b" H! t+ M. B0 f
  799.         {
    8 n6 _6 |; O1 e
  800.                 cmdhdr->frame_header.length = size;3 z, ]8 ^: s4 {
  801.                 cmdhdr->frame_header.type = WIFI_SDIOFRAME_COMMAND;
    ' w; c2 K" i0 K  r
  802.                 cmdhdr->cmd_code = com_code;
    ) v3 \" G3 \! H/ x
  803.                 cmdhdr->size = size - sizeof(WiFi_SDIOFrameHeader); // 命令大小包括命令头部, 但不包括SDIO帧头部
    2 z$ D0 \" r0 V' z, v# I
  804.                 cmdhdr->seq_num = seq_num++;' o: Z7 ]5 g) E& y- O4 J) P6 J
  805.                 cmdhdr->result = 0;1 `9 ?! h3 x; P  ]( W) \  W* A
  806.         }# V/ Q  C* r5 I. W. p
  807.         else
    0 D: b2 p& ~* ]* c
  808.                 size = cmdhdr->frame_header.length; // 重发命令时不填写cmdhdr
    ( F) c* @1 \/ ?) J8 y# B& C
  809.         
    ) t, b# |/ y  C
  810.         // 发送命令前若恰好有数据帧到来, 则直接丢弃% Q, J! W: k1 B3 ?/ M" ?9 S5 Y
  811.         if (WiFi_PacketPending() || WiFi_PacketArrived())
    ( ^; \3 U; K7 g, @, Y  p0 p, k
  812.         {
    1 Q! N# R+ b0 M8 D- E; J* \% V+ H5 `- _
  813.                 printf("A new packet happends to arrive when sending command! Drop it!\n");
    6 q  `5 o2 X$ z! t
  814.                 WiFi_DropPacket();
    - V# q6 k- h, y7 o5 [) c0 }$ x
  815.         }
    : M& D2 c. `/ d- `
  816.           T3 n3 R3 }% j% p. P- @& M. r9 b0 C
  817.         WiFi_WritePort(data, size);
    $ E) A" G( m1 S$ p) h5 G
  818. }
    ; _- v7 f$ U/ K2 H; `) V4 a. j
  819. : p2 Z% z0 p' t# i' T8 L
  820. /* 发送数据帧 */4 c. j* H. M4 t$ d) p/ K6 c+ J6 I
  821. uint8_t WiFi_SendPacket(WiFi_DataTx *packet, uint16_t packet_len)8 q6 s3 M4 L) l' o  I. Q4 x# P; n; z
  822. {. D( u  h  b+ }9 A2 k
  823.         uint8_t ret;
    % m% j+ ^0 [& I7 L% R7 r
  824.         
      ]: x' ~+ m1 |) z/ ?$ z
  825.         // 有关发送数据包的细节, 请参考Firmware Specification PDF的Chapter 3: Data Path
    6 \8 l) Y4 D$ [# a9 {# U& @. P3 v$ j
  826.         packet->header.length = sizeof(WiFi_DataTx) - sizeof(packet->payload) + packet_len;
    * s5 C. h( A5 N4 T0 d6 ~
  827.         packet->header.type = WIFI_SDIOFRAME_DATA;1 O, A, U0 @, g& j
  828.         
    / P) X+ S$ Z# I
  829.         packet->reserved1 = 0;& d  p, ~- |& t9 {0 i- \
  830.         packet->tx_control = 0; // 控制信息的格式请参考3.2.1 Per-Packet Settings
    8 }* v0 Z9 E6 W* f
  831.         packet->tx_packet_offset = sizeof(WiFi_DataTx) - sizeof(packet->payload) - sizeof(packet->header); // 不包括SDIOFrameHeader
    ; G7 V! R: f. y' C1 r6 x8 W
  832.         packet->tx_packet_length = packet_len;
    . P/ l* _7 m) C& h* K$ n
  833.         memcpy((void *)&packet->tx_dest_addr_high, packet->payload, 6);
    5 Y  m9 J( @8 L% L% Y4 ?' D
  834.         packet->priority = 0;/ K: T/ K6 y% d/ S* P% h
  835.         packet->flags = 0;
    + P3 x/ i& n, G* X# t' W, j+ o
  836.         packet->pkt_delay_2ms = 0;0 o3 d+ `0 Q5 x4 g3 x' [6 I
  837.         packet->reserved2 = 0;% j! ?0 @- `3 N2 @
  838.         
    & W& b6 q8 ?- r/ }( r
  839.         // 若现在有新收到的数据帧, 则暂存数据包大小% ?8 Q7 D9 [: m0 B
  840.         // 未读取之前不会收到新的数据帧1 a& ^5 z! y/ C5 y
  841.         if (WiFi_PacketArrived())
    $ ^  q/ M3 r" v0 t5 }
  842.                 wifi_pending_size = WiFi_GetPacketLength();
    8 U/ D* K4 {+ A; G+ n' m, z
  843.         
    * J) q5 a6 ^% w7 C8 m
  844.         ret = WiFi_WritePort(packet, packet->header.length);
    9 Q6 n3 U8 {: X$ E3 i/ V5 ^
  845.         WiFi_Wait(WIFI_CARDSTATUS_DNLDCARDRDY); // WiFi模块收到数据后, 会将该位置1
    7 t, I( [! B& o" ^) E- s
  846.         return ret;
    ) f, @* [7 s8 Y4 m2 g. h
  847. }8 c; V" v* v3 s6 I! ?
  848. - ?0 y0 W6 E* _9 R: _5 ]/ z, B
  849. /* 将SDIO->DCTRL中的块大小信息应用到WiFi模块指定的功能区上 */
    " n) x7 Q* m5 R- M- p
  850. void WiFi_SetBlockSize(uint8_t func)
    ! N& ^$ [! \3 h% ?1 i" ]
  851. {
      G/ w5 G* P9 m$ T7 f+ _9 F; R
  852.         // Part E1: 6.9 Card Common Control Registers (CCCR), 6.10 Function Basic Registers (FBR)* T- }/ b+ s2 P
  853.         uint16_t size = WiFi_GetBlockSize();
    5 |" s1 X0 Z: u& H' s
  854.         WiFi_Write(0, (func << 8) | 0x10, size & 0xff);# m3 x1 f2 X# k& v& j2 p; F
  855.         WiFi_Write(0, (func << 8) | 0x11, size >> 8);
    0 M+ T6 Q" I- x& h, b. d) e
  856. }
    . [; T' n- W* m
  857. ) l3 `2 h! A4 d
  858. /* 设置密钥 */
    2 S9 ~3 t: b- i/ V  }- @' N; N& z
  859. uint8_t WiFi_SetKeyMaterial(uint16_t type, uint16_t info, const uint8_t *key, uint16_t len)( u# Z( V. Q. u
  860. {
    " Z" m2 M" N& t* `$ Y5 ~
  861.         MrvlIETypes_KeyParamSet_t key_param;
    5 s. Q( E* O% t# }7 a
  862.         if (len > sizeof(key_param.key))  G2 F' U" Q& f% r2 k! ?" Q* f
  863.                 return CMD_STATUS_ERROR;4 R- L. l/ x; d8 l4 B
  864.         key_param.header.type = MRVLIETYPES_KEYPARAMSET;, \- W( r/ _! E$ S/ d1 {: ?
  865.         key_param.header.length = (key_param.key - (uint8_t *)&key_param) - sizeof(key_param.header) + len;( K! Q" b: P# f2 ~1 p
  866.         key_param.key_type_id = type;
    ! g% B6 E5 D/ |, b+ A& L
  867.         key_param.key_info = info;+ P6 R# L6 x; M4 `6 W
  868.         key_param.key_len = len; // 当len=0时可保留key的值, 只更新key_info
    ( o# W8 d8 }5 w  k6 z+ J" V' x
  869.         if (len)$ v( D  e* l! A+ H. w# m1 |* ^
  870.                 memcpy(key_param.key, key, len);5 Q& `: V$ d) @, q# q: Z
  871.         return WiFi_KeyMaterial(&key_param, MRVLIE_STRUCTLEN(key_param), WIFI_ACT_SET);
    % N/ `# |- G7 |5 R
  872. }
    6 F* b, L' c% i) E* T) c

  873. ( {) F3 Y% [  F- \" @. Q3 G
  874. /* 显示WiFi模块信息 */$ I2 @/ R! ^7 f% P% _  |# R9 {; t
  875. void WiFi_ShowCIS(uint8_t func)
    3 Q0 b. Z! @( I% M
  876. {+ F1 S: S& K2 s7 U' N
  877.         uint8_t data[255];
    ) C/ c: ?# ]) b7 j
  878.         uint8_t i, len;8 ^% I7 R9 u" [8 l, H7 L
  879.         uint8_t tpl_code, tpl_link; // 16.2 Basic Tuple Format and Tuple Chain Structure/ N6 D: t* B0 T) t+ E
  880.         uint32_t cis_ptr;
    + J, I, O% l. g! \9 @
  881.         , B& h3 G. ?) g3 A+ d) C# h8 T& X
  882.         // 获取CIS的地址
    * ?" f1 b# k4 q# g
  883.         cis_ptr = (func << 8) | 0x9;
    : g. w4 V( A( Y& y5 w
  884.         cis_ptr        = WiFi_Read(0, cis_ptr) | (WiFi_Read(0, cis_ptr + 1) << 8) | (WiFi_Read(0, cis_ptr + 2) << 16);0 s( V5 M1 {2 s0 E& X( p
  885.         printf("Pointer to Function %d Card Information Structure (CIS): 0x%08x\n", func, cis_ptr);% _) |+ C8 B9 q
  886.         , x6 v: y' K0 o; C( y! \9 c. P
  887.         // 遍历CIS, 直到尾节点4 E* i& E" a# q; B! ~) ~) i
  888.         while ((tpl_code = WiFi_Read(0, cis_ptr++)) != CISTPL_END)
    2 ^2 \6 a6 n8 t( a) a- ]0 S
  889.         {
    ; m! Y& C8 z3 J& i
  890.                 if (tpl_code == CISTPL_NULL)
    / T, q+ W- h, ~& K( J2 V
  891.                         continue;. d! `  U; v+ R5 Y9 e
  892.                 4 X, z+ Q: E+ y0 w- [3 \2 }1 W
  893.                 tpl_link = WiFi_Read(0, cis_ptr++); // 本结点数据的大小0 j9 v; J& y2 a5 @' c" ^7 |/ c
  894.                 for (i = 0; i < tpl_link; i++)! s; b2 _% T8 k6 `( F6 L
  895.                         data[i] = WiFi_Read(0, cis_ptr + i);
    6 r. j" m& n* Y6 K1 z- z" u
  896.                
    . e, V) d* h: o6 @; w- S- N
  897.                 printf("[CIS Tuple 0x%02x] addr=0x%08x size=%d\n", tpl_code, cis_ptr - 2, tpl_link);1 N3 p, V. o1 N5 e, ~
  898.                 dump_data(data, tpl_link);
    * M0 _6 Z! o8 A
  899.                 switch (tpl_code): Y+ e0 H( N: S) X" ]. e1 t2 H
  900.                 {: B1 S7 f& Z! i, Q0 ^
  901.                 case CISTPL_VERS_1:
    & ]- u7 d' n5 ^# W- C
  902.                         i = 2;
    3 Q1 b7 L4 C& `6 g0 r6 d( b. J: M
  903.                         while (data[i] != 0xff)+ _3 l4 J- Q) [4 z
  904.                         {; f! \; \; N' r4 Y
  905.                                 len = strlen((char *)&data[i]);
    2 |6 X" Z; _4 ], J
  906.                                 if (len != 0); }+ y$ Q: N/ p
  907.                                         printf("%s\n", data + i);
    / w: U! v( W* o
  908.                                 i += len + 1;+ E6 l( k# ?: O* f2 H; i; s8 g
  909.                         }
    " @3 }6 m) @" V) `# s" ?
  910.                         break;
    " a" ?, P/ j- L0 ]+ x5 Q) T
  911.                 case CISTPL_MANFID:
    8 X! v# V; L! j5 G
  912.                         // 16.6 CISTPL_MANFID: Manufacturer Identification String Tuple
    ( s  I" P8 f; H/ {$ l. x
  913.                         printf("SDIO Card manufacturer code: 0x%04x\n", *(uint16_t *)data); // TPLMID_MANF
    1 g6 Q: A8 R- ^' [- a7 C! b
  914.                         printf("manufacturer information (Part Number and/or Revision): 0x%04x\n", *(uint16_t *)(data + 2)); // TPLMID_CARD$ k' ^& h* ?3 O! g5 }2 Y! V/ I9 }
  915.                         break;
    ; n, F; z3 F3 i) y6 J! [
  916.                 case CISTPL_FUNCID:
    9 b4 {) K! b& z7 f* m+ H, n% T
  917.                         // 16.7.1 CISTPL_FUNCID: Function Identification Tuple
    , }$ w2 F. P4 D) e; ^) e  p
  918.                         printf("Card function code: 0x%02x\n", data[0]); // TPLFID_FUNCTION
    4 m0 ?4 R0 z5 P! `
  919.                         printf("System initialization bit mask: 0x%02x\n", data[1]); // TPLFID_SYSINIT* c$ l! K% {6 m9 u" K
  920.                         break;/ M+ [: E3 M, Q  B3 t9 _& \, z: D& O2 g
  921.                 case CISTPL_FUNCE:( Q* D1 I; L1 P- E. x6 {
  922.                         // 16.7.2 CISTPL_FUNCE: Function Extension Tuple* c/ H& q' X' A3 r' N
  923.                         if (data[0] == 0)
    - g. |2 F/ p4 ~4 {: n
  924.                         {
    ( J" x  Q( e; d& k; I
  925.                                 // 16.7.3 CISTPL_FUNCE Tuple for Function 0 (Extended Data 00h), J1 U4 P: S# b! [% `( R( A
  926.                                 printf("maximum block size: %d\n", *(uint16_t *)(data + 1));
    ' H  A7 v  p4 |% T" T; i, Y
  927.                                 printf("maximum transfer rate code: 0x%02x\n", data[3]);
    $ L' e# J, p# @& h, J# @9 _
  928.                         }
    0 i/ w# @) J  H5 C8 G" R- F
  929.                         else
    1 v0 Q1 T; p  V# ~$ Z
  930.                         {/ u' {* j1 P9 O! w' l6 b
  931.                                 // 16.7.4 CISTPL_FUNCE Tuple for Function 1-7 (Extended Data 01h)
    . c# a) j' l8 p$ U* X# U
  932.                                 printf("maximum block size: %d\n", *(uint16_t *)(data + 0x0c)); // TPLFE_MAX_BLK_SIZE9 x' l0 ?( T4 x
  933.                         }
    1 v, t, e7 p4 t" }1 h* {' ~8 ?
  934.                 }
    , V5 ~' c9 \% H/ N5 ^0 _8 |
  935.                 # g- \+ Y4 y1 t- T* u7 K
  936.                 cis_ptr += tpl_link;- ]8 w$ f, ?  J  b0 Q
  937.                 if (tpl_link == 0xff)2 d6 ~+ g7 P" j7 I9 }$ }
  938.                         break; // 当TPL_LINK为0xff时说明当前结点为尾节点
    $ H3 k1 v/ o3 C% Y3 P9 D
  939.         }* X" y# T7 p" N2 L
  940. }. }0 Y! G0 b$ Z5 h; |
  941. . T8 M- v9 c) g  s
  942. /* 显示所有密钥 */8 z( @; Z1 Z: k7 ?
  943. void WiFi_ShowKeyMaterials(void)
    - V. ?: e$ e  j- e4 d
  944. {$ E2 Z6 y$ r& q; R5 q# u% x
  945.         uint8_t buffer[256];
    : P* M) l+ V; `# e: L! Z" e; K& V
  946.         uint16_t size;1 _) G1 l) d# y! `
  947.         MrvlIETypes_KeyParamSet_t *key = (MrvlIETypes_KeyParamSet_t *)buffer;) ~% n. E4 b$ H7 J( W4 C4 I$ D
  948.         ( L  t6 P7 p& r% y0 P
  949.         size = WiFi_KeyMaterial(key, sizeof(buffer), WIFI_ACT_GET);: S. B. `" X5 d# F: O3 h9 @; a5 w$ E2 }
  950.         while (size)
    . b; |9 [. T6 P% r1 J2 q
  951.         {3 D' h( d2 l1 p% N' G8 P3 l
  952.                 printf("Type %d, Info 0x%04x, Len %d\n", key->key_type_id, key->key_info, key->key_len);
    2 n8 ?( ]6 K7 C. P
  953.                 dump_data(key->key, key->key_len);
    . x7 k- j! K7 h% F
  954.                 size -= MRVLIE_STRUCTLEN(*key);! ]- S+ [: b' l- v
  955.                 key = (MrvlIETypes_KeyParamSet_t *)((uint8_t *)key + MRVLIE_STRUCTLEN(*key));
    5 D4 v' g: r8 Q& C
  956.         }$ G. l: |& i" D) N& f$ t
  957.         if (size == 0)
    4 x" w% @' r4 @" F
  958.                 printf("data end!\n");2 C5 F: W0 [0 E4 N/ N
  959. }
    ; l8 ^3 v4 e1 g& j7 I  K

  960. 1 d6 d; W0 z3 E$ O! {% G! ^
  961. /* 创建一个Ad-Hoc型的WiFi热点 */2 n9 r, t# k* M' S$ b0 x8 t
  962. uint8_t WiFi_StartADHOC(const char *ssid): u: q! U( C9 c4 ?$ M- I
  963. {
    % s6 n0 j2 [- \
  964.         WiFi_CmdRequest_ADHOCStart cmd;; F  M2 S6 M1 U9 q5 D
  965.         memset(&cmd, 0, sizeof(cmd)); // 由于命令中含有Reserved区域, 所以必须先清零
    + v  S) ~1 _  C7 M2 W! J
  966.         
    # o2 X4 l  ?& F0 w0 }0 ~- ]5 o
  967.         strncpy((char *)cmd.ssid, ssid, sizeof(cmd.ssid));
    - K& Q% x- {4 W9 w, a
  968.         cmd.bss_type = BSS_INDEPENDENT;
    8 u1 ^. v8 \! `$ q1 v; g. L
  969.         cmd.bcn_period = 100;
    / m5 K' a& g1 W$ v" \
  970.         cmd.ibss_param_set.header.type = MRVLIETYPES_IBSSPARAMSET;5 [: ?3 {2 j) N- M: R* y
  971.         cmd.ibss_param_set.header.length = MRVLIE_PAYLOADLEN(cmd.ibss_param_set);
    0 E) s& g, }! _  ]
  972.         cmd.ibss_param_set.atim_window = 0;% x2 X/ t) q! J  H6 `
  973.         cmd.ds_param_set.header.type = MRVLIETYPES_DSPARAMSET;
    . y" z7 }2 V* L5 |
  974.         cmd.ds_param_set.header.length = MRVLIE_PAYLOADLEN(cmd.ds_param_set);
    & ^1 L5 ~8 d% }+ Q+ u) e0 k
  975.         cmd.ds_param_set.channel = 1;
    ' l/ a9 S% i* F- R  }% I  L
  976.         cmd.cap_info = WIFI_CAPABILITY_IBSS/* | WIFI_CAPABILITY_PRIVACY*/;
    3 x% t2 u* x" s! c+ w7 Q+ e
  977.         *(uint32_t *)cmd.data_rate = 0x968b8482;
    1 R2 F4 g* {2 t2 l6 l- N) R$ H
  978.         & Y& v2 ?, E) @/ B$ y. Q3 b4 J
  979.         WiFi_SendCommand(CMD_802_11_AD_HOC_START, &cmd, sizeof(cmd));, x' F/ c: c5 `' I5 t) }
  980.         WiFi_ReceiveResponse(&cmd, sizeof(cmd));
      A3 [+ C- `: H  Z2 P) b
  981.         return cmd.header.result;! F. f8 r. f/ Q4 E$ \8 j  E
  982. }0 `% b3 U& Z0 E

  983.   ]9 C" n0 _% E6 S
  984. /* 在规定的超时时间内, 等待指定的卡状态位置位(自动包括IO Ready位), 若成功则返回1 */4 Z% v6 \* y# T# F, p+ N
  985. uint8_t WiFi_Wait(uint8_t status)6 D6 n/ F' J3 C* k
  986. {
    4 J1 f# [6 o. R4 P, B
  987.         status |= WIFI_CARDSTATUS_IOREADY;
    7 g9 r* F2 A  h
  988.         WiFi_PrepareTimer(wifi_timeout);" n; b# F% N- v) J
  989.         while ((WiFi_Read(1, WIFI_CARDSTATUS) & status) != status)* E" ^9 t6 q# m1 w3 J8 a5 E
  990.         {& v" j; `  o$ Y
  991.                 if (TIM6->SR & TIM_SR_UIF)
    ! i* A6 K! G5 P) Z
  992.                 {& n$ u+ E; n' d. j1 ]6 u" \
  993.                         // 若超时时间已到
    - w1 k+ e& |7 u! O
  994.                         TIM6->SR &= ~TIM_SR_UIF;) m9 @- i3 ?* `) D3 R2 {
  995.                         printf("WiFi_Wait(0x%02x): timeout!\n", status);1 Z: R- t) Z5 \% E
  996.                         return 0;: s) W9 F$ ]+ e
  997.                 }
    7 ^+ U1 f5 D7 T9 z4 y
  998.         }
    * S4 @, @3 K8 V) o% }
  999.         TIM6->CR1 &=~ TIM_CR1_CEN; // 关闭定时器
    * N' ]9 p! d. g+ E! N1 {) _0 |
  1000.         return 1;" r6 k! p/ e' M) S
  1001. }+ g+ [* D: B8 d* w% Y

  1002. 4 [5 k  x2 S+ p( F( k7 e; K
  1003. /* 写寄存器, 返回写入后寄存器的实际内容 */
    / z7 }- ?4 x1 G' D, H0 J$ K
  1004. uint8_t WiFi_Write(uint8_t func, uint32_t addr, uint8_t value)
    3 ~8 ?, f7 ^' P2 X3 p2 z" p# H
  1005. {6 C+ y, O% I4 Q- g$ x. C
  1006.         WiFi_SendCMD52(func, addr, value, CMD52_WRITE | CMD52_READAFTERWRITE);
    ; V8 x- V& G+ p; G0 @
  1007.         if (SDIO->STA & SDIO_STA_CMDREND)
    ( Y$ x' j; C' Q/ d" V! K
  1008.         {
    # z  |& R( U3 O# w. k; z) L$ s3 X7 U
  1009.                 SDIO->ICR = SDIO_ICR_CMDRENDC;
    4 _: R( n" V9 N+ g2 k; e
  1010.                 return SDIO->RESP1 & 0xff;& d' l. m/ s/ o- c
  1011.         }: F; [0 T+ {( ~, T
  1012.         else# m( B% k" x' m
  1013.         {( U6 G- R3 j4 A* {% d1 G! ~
  1014.                 printf("WiFi_Write failed, SDIO->STA=0x%08x!\n", SDIO->STA);
    9 `$ o% v/ p* `% F
  1015.                 return 0;! H' v+ c: _9 s8 c7 x; D. d
  1016.         }% ^& F! O" y# e9 l, h! H5 k4 Y) P
  1017. }8 s+ B- |9 q/ n! U' U

  1018. $ K' O3 U0 t8 l) U$ u
  1019. /* 写数据 */
    * C  F3 }* n( X% r1 m& K
  1020. // count为要发送的字节数或块数, bufsize为data缓冲区的大小
    # n, Z( T4 A$ O  u& q5 o* J% X
  1021. void WiFi_WriteData(uint8_t func, uint32_t addr, const uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags)
    ; h5 _  `, C6 H0 M/ B( I$ D6 e
  1022. {
    + l4 O' G+ _8 J/ o0 D: _$ F
  1023.         uint32_t len, temp;! s5 T$ x& f$ z1 Y
  1024.         if (flags & CMD53_BLOCKMODE)- o( o; U. g: {7 \# [! M0 c
  1025.         {
    5 P5 f. Q/ v& B5 _3 T8 |+ J. r3 N3 S
  1026.                 len = count * WiFi_GetBlockSize();, ~5 [  P$ J0 ?5 ~
  1027.                 SDIO->DCTRL &= ~SDIO_DCTRL_DTMODE;
    - b1 |2 I. c% \) @: ^0 H3 K: X
  1028.         }  D$ W' h+ K+ i- m5 _% B, \
  1029.         else
    / P0 h8 s; p. o0 i, ?: @1 g1 E. m6 P
  1030.         {
    ( f5 L9 D+ R( u0 q8 _  T1 u
  1031.                 len = count;# _$ F" X, b. W
  1032.                 if (len % 4 != 0)
    6 M8 w4 }* T4 n! i% c3 M7 h' J
  1033.                 {
    ' T* z, ?, i" j8 B  Z: z; `0 K8 D
  1034.                         len += 4 - len % 4; // WiFi模块要求写入的字节数必须为4的整数倍
    : B0 i  d! c8 V! d$ [$ J% S8 G
  1035.                         count = len;
    6 z$ L0 ]; Y0 E* t
  1036.                 }
    / O! A0 I  V: A
  1037.                 SDIO->DCTRL |= SDIO_DCTRL_DTMODE;
    % ~0 D" D# L( @+ S
  1038.         }' x( x7 F2 c4 g$ U, z. u9 @. _
  1039.         SDIO->DLEN = len;
    # f) y5 O) B. v1 W8 p# [
  1040.         SDIO->DCTRL &= ~SDIO_DCTRL_DTDIR; // 设置传输方向: 从主机到模块
    8 X- w) b7 I- b  B9 i* l
  1041.         - _# g1 R( ~0 y) T% c# l* v
  1042.         WiFi_SendCMD53(func, addr, count, flags | CMD53_WRITE);
    5 H# V0 ?$ }' B' [/ g+ a
  1043.         while (SDIO->STA & SDIO_STA_CMDACT);
    1 p( n9 x3 T) D; N5 z( U! m
  1044.         if ((SDIO->STA & SDIO_STA_CMDREND) == 0)
    - |" @! {. z, U- K
  1045.         {: }+ K5 ^$ e( j. q6 l
  1046.                 printf("WiFi_WriteData: CMD53 no response!\n");! @+ k3 o( x) H/ E* f& B) ?
  1047.                 return;0 y1 V/ z2 }( k. V+ _6 W8 m; a
  1048.         }1 b2 k; ]8 @2 {1 D
  1049.         SDIO->ICR = SDIO_ICR_CMDRENDC;
    . M/ [) p4 ?; `  k4 N
  1050.         ) Z! T3 X3 I8 P2 ]( g) p; k
  1051.         SDIO->DCTRL |= SDIO_DCTRL_DTEN; // 开始发送数据+ Z7 }& A7 N3 L) Z
  1052.         while (len)
    8 f& v3 Z. l, X
  1053.         {( k' p. A' y. U9 O7 B
  1054.                 len -= 4;  n& e4 C6 L- k& B( J
  1055.                 if (bufsize >= 4)
    * o( [! c1 l) Y, s* b+ q6 T
  1056.                 {
    4 n, T$ P5 t! l$ v! L7 f3 r: y/ s
  1057.                         SDIO->FIFO = *(uint32_t *)data;
    0 R* O2 a+ F/ ~; g+ s
  1058.                         data += 4;
    / H* a, b0 Z" p* ^
  1059.                         bufsize -= 4;
    * b# J/ h8 v3 G- G
  1060.                 }7 F' \$ F% F8 K) z
  1061.                 else if (bufsize > 0)
    ( G, _+ E% S4 [& c# S) j" y
  1062.                 {: r4 M" k0 O8 G1 q# y
  1063.                         // 发送缓冲区最后1~3字节
    5 E4 p) L( L9 f4 E) P$ C( u4 s1 d
  1064.                         temp = 0; // 不足的位用0填充& V% l! j. O9 X( s) x3 ]7 T" V
  1065.                         memcpy(&temp, data, bufsize);
    ( _  V5 \" m$ x4 N- f$ N
  1066.                         SDIO->FIFO = temp;
    4 d4 j3 Y4 X. j4 p
  1067.                         bufsize = 0;
    4 V$ Z9 L* v4 w( p2 W% \! i
  1068.                 }
    ) B! Z+ m9 |% _
  1069.                 else- S! `8 [/ F( k, D( Q# `4 T
  1070.                         SDIO->FIFO = 0; // 缓冲区已用完, 因此发送0$ U2 h+ ^( x! k# a
  1071.                 while (SDIO->STA & SDIO_STA_TXFIFOF); // 如果FIFO已满则等待
    ) s! t+ c( J7 t+ o- i( Y
  1072.         }; c) ~3 e2 F4 M
  1073.         
    ( ~: I0 @7 c) _  w7 }1 v  Q
  1074.         while (SDIO->STA & SDIO_STA_TXACT); // 等待发送完毕+ K) f8 \1 j$ [. m( S
  1075.         SDIO->DCTRL &= ~SDIO_DCTRL_DTEN; // 数据传输完毕后DTEN应及时清零, 防止后续对DCTRL寄存器操作后误启动数据传输导致超时或CRC校验错误
    : ]- _; z" ]0 c" p& v  D: m3 V
  1076.         + M- L% O8 R, w, B/ [
  1077.         // 清除相关标志位
    ' e3 q4 v( I* \# o/ m% N, L
  1078.         SDIO->ICR = SDIO_ICR_DATAENDC;/ G: s; a  K* R: L- k7 u
  1079.         if (flags & CMD53_BLOCKMODE)
    : T5 x. |( s; G1 _" J  q( \# i
  1080.                 SDIO->ICR = SDIO_ICR_DBCKENDC;
    ) i, P  l' b' Z1 J
  1081. }( N7 y& q2 K$ J

  1082. - f' l2 Z1 j' y9 i+ h: F1 E: d; M% w
  1083. uint8_t WiFi_WritePort(const void *data, uint16_t size)
    , a1 o) q5 p( @2 ^
  1084. {/ E' u1 i6 ]$ i, a- U" X
  1085.         uint16_t block_num, block_size;: y) h' s. x5 p9 F. [
  1086.         block_size = WiFi_GetBlockSize();' C/ T) ~( P2 h- t5 X7 ^; ]
  1087.         ' @: M- }$ v% F! M! d
  1088.         WiFi_Wait(0); // 发送CMD53前必须IOReady=1
    . k4 O" P5 a3 [- R: j; I/ }9 I; c
  1089.         if (size >= 512 || size % block_size == 0). T& ]2 {/ R  x( e6 C- ?0 ^
  1090.         {' ^3 e! v$ Q# n0 g, B- D* @
  1091.                 // 采用Block模式传输
    ' a" Q" n. j: }
  1092.                 block_num = size / block_size;# [2 ~& K' ~+ c: x
  1093.                 if (size % block_size != 0)
    ) O3 y! S0 y/ z: U$ l6 s: a% Z
  1094.                         block_num++;
    ' @1 @# L1 b% N( m6 b3 E
  1095.                 3 P1 _) v5 h( I2 z/ B
  1096.                 WiFi_WriteData(1, io_addr, data, block_num, size, CMD53_BLOCKMODE);( G& b# y4 H5 I; j
  1097.         }  C# |% a  F. ^
  1098.         else
    8 A: f, \- |3 s! R9 R5 g
  1099.                 WiFi_WriteData(1, io_addr, data, size, size, 0);
    # _+ C* h0 f$ d4 G8 S, D
  1100.         return SDIO->STA == 0;; a7 Y* {6 B6 ?; P# [: d& f
  1101. }
    5 u. Y/ V$ i8 B# w( I6 w0 a
复制代码
$ V$ W0 O+ E+ m: U' y! L9 ?

, \3 r  Y* f. E: x  a# T! E在工程的所在文件夹创建一个lwip文件夹。! j( P+ R) L+ @# t/ a8 ^+ q
然后在lwip的官方网站下载lwip-2.0.2.zip,打开压缩包中的lwip-2.0.2/src文件夹,解压以下文件夹到工程的lwip目录下。# I1 i  E% ]8 ?3 A5 f3 V5 R0 }
! Y; ~# S* |. E7 k+ A
core/* l0 u" p* C8 j! D
core/ipv4& Y3 A5 p3 }/ p. a+ u" M: {8 d
include/lwip8 T' f0 x8 v+ T! P. ?
include/netif7 x2 b6 {" t! T; S' o4 X
netif/ethernet.c
- U) B8 L* x8 d* V0 _netif/ethernetif.c7 f/ x# o' b5 {/ G

- f7 o$ G: ^& [5 {解压后,将里面的c文件都添加到工程的lwip分组下。
4 u' G- n  o% s' x具体添加的文件请看下图:
; u& O) D" f3 P2 Y* _3 U( [) ^6 [6 h# X! G8 b# `6 w

) E7 R* q# _1 A5 _- j- ~6 x7 i" m/ ^接下来,创建lwip/include/arch/cc.h文件,内容如下:  J! j3 Y* I) M/ ~- Y2 Y! ^
  1.     #define PACK_STRUCT_BEGIN __packed // struct前的__packed  
复制代码
创建lwip/include/lwipopts.h文件,内容如下:( a5 U! D) I* S. E
  1.     #define NO_SYS 1 // 无操作系统  8 ?1 E9 i  ]/ g3 t) n
  2.       
    2 N! w! Y1 d6 V5 l  U
  3.     #define LWIP_NETCONN 0  3 i$ T; U# w2 @8 \8 A9 v; z
  4.     #define LWIP_SOCKET 0  6 B/ P1 q9 A4 W4 N: s; C& A6 r$ x. R
  5.     #define LWIP_STATS 0  1 g. Q8 {/ ~. e8 q
  6.       ; d; T, s: ~- ]$ }* r! w# c+ I
  7.     #define MEM_ALIGNMENT 4 // STM32单片机是32位的单片机, 因此是4字节对齐的  
    . @( v( k, G: W/ y( ^+ c
  8.       
    3 A7 _# y8 D2 v+ m* Q7 s
  9.     #define SYS_LIGHTWEIGHT_PROT 0 // 不进行临界区保护 (在中断中调用lwip函数时要小心)  
复制代码
打开lwip/netif/ethernetif.c文件,按照下面的中文提示修改代码:( L+ U1 {; V% u+ P" T
  1. /**
    4 z; f  v1 b: t/ ^6 d
  2. * @file0 g9 P6 u9 P& V3 `: _+ h1 a  M
  3. * Ethernet Interface Skeleton7 H! Y, J4 P# s2 a, q0 T) M7 J# q
  4. *# h# E) u( X( c# K
  5. */
    6 V7 ~1 l  c- N9 v( s

  6. $ v7 u  T  B0 x
  7. /*
    - ]7 ^  a, p  T0 e7 k
  8. * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
    1 a  i+ S: I* X. e$ j
  9. * All rights reserved.3 O% Y" D/ e1 g) U( C) A1 p
  10. *9 H' `: q. [& R' H
  11. * Redistribution and use in source and binary forms, with or without modification,5 H1 G. b/ s* |, Z. b
  12. * are permitted provided that the following conditions are met:$ X, L* Q+ n  E: H! }
  13. *
    7 k  b# i9 B. C4 M. ?7 A
  14. * 1. Redistributions of source code must retain the above copyright notice,
    / B7 m' k# y) f, _' o7 A7 \
  15. *    this list of conditions and the following disclaimer.
    4 Y0 a" Q: P- s' Y3 h! [2 e$ z
  16. * 2. Redistributions in binary form must reproduce the above copyright notice,; U6 _) C$ w+ H1 h" Q% V0 ^
  17. *    this list of conditions and the following disclaimer in the documentation( I- T( V' T. M* l- d2 H
  18. *    and/or other materials provided with the distribution.
    * ]& E4 I$ M5 _4 w4 @& F
  19. * 3. The name of the author may not be used to endorse or promote products. e/ Q. f1 e. w3 d, W6 Q. k0 m
  20. *    derived from this software without specific prior written permission.* @5 j# d9 J$ b+ J+ y; \# I
  21. *
    ' N9 E  ~9 y! g: n8 ^# _
  22. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED7 @, q' \& Y9 I5 r
  23. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    # b4 ~" Y2 S" T3 C! i
  24. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
      w. ~1 ^) a  B( ~! w; e. [( K
  25. * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,: g) s" `1 G0 z. i( O
  26. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
    2 u" ^; v8 L0 {/ i/ R9 t, Z
  27. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  w% K* R/ f9 {# q) O
  28. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    % H8 [% ?2 w! T+ X  ?: K# J
  29. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    9 c, J0 g! e4 T& B& Z2 \6 J: y
  30. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY, o- b: ^  X  |; g3 A
  31. * OF SUCH DAMAGE.. v( Q- p3 C5 e! u2 x7 \2 j
  32. *
    ' c! H5 U/ L9 C0 }/ c
  33. * This file is part of the lwIP TCP/IP stack.
    . h  W4 ^. _" k- e: c! q3 U2 I
  34. *
    " \4 m. s. [6 Q7 m- x
  35. * Author: Adam Dunkels <adam@sics.se>& }- Z1 I; [2 K" s; \- _( @7 y
  36. *
      v& y* `. c& ~9 ]
  37. */4 M  D" l/ S) r( k- B4 J& U

  38. ; q7 O! K* s) ~8 t
  39. /*3 X- G& w+ w, H* d8 x
  40. * This file is a skeleton for developing Ethernet network interface
    4 t* h9 T) l* W) E2 I5 ^
  41. * drivers for lwIP. Add code to the low_level functions and do a
    1 N* j) H! x1 m: z0 B4 P" [( L! ]
  42. * search-and-replace for the word "ethernetif" to replace it with
    0 V. A9 c+ I' I
  43. * something that better describes your network interface.4 W0 x+ ^" M: o7 u/ R
  44. */% ^# Y1 @& W+ W) @, {
  45. 8 t( J9 y. \7 T) u
  46. #include "lwip/opt.h"
    * E% E" C! z; O  n9 r0 ^
  47. # M- G5 J/ u+ V) e# \
  48. #if 1 // 允许编译器编译该文件* q) F3 z: R. d, |  s

  49. * t. y7 u' R; E( [
  50. #include "lwip/def.h"/ n, r; F% A9 c: V8 x- G
  51. #include "lwip/mem.h"
    ' j* E; ~! n/ k6 I! ?+ L# M
  52. #include "lwip/pbuf.h"
    # Y( e: |: k# K! {+ `9 u
  53. #include "lwip/stats.h"9 f/ L+ A& I: j) H# H
  54. #include "lwip/snmp.h"
    ) U0 @3 a0 N+ \( b6 [5 ?
  55. #include "lwip/ethip6.h"
    ) K" E/ `( c# H8 J
  56. #include "lwip/etharp.h"& x$ r) V) p. p* n( R8 f; Y/ {7 V
  57. #include "netif/ppp/pppoe.h"
    7 K( d4 x) J) c4 J

  58. 5 l. x8 ^- X+ [: t4 l
  59. /* Define those to better describe your network interface. */
    1 e& H( d1 u, J$ e; u' S
  60. #define IFNAME0 'e'! a' H* d% C4 f+ M' B4 p, O9 Z
  61. #define IFNAME1 'n'
    ) A7 C4 F* F" I0 F/ A) [$ ^. v

  62. 2 D: u2 C3 Y* B& O0 I: k
  63. #include <string.h> // memcpy函数所在的头文件' n: q' l& }1 Z9 B7 U6 P7 q
  64. #include "WiFi.h" // WiFi模块驱动程序头文件& f8 {8 b# B4 z$ L* u
  65. 0 P9 T! Y5 M% \3 Y% P7 {: A
  66. void dump_data(uint8_t *data, uint16_t len);8 W* ^) h: }( ]9 E5 @  [
  67. ) Q& B7 n" S) X
  68. /**
    ' k7 O: W* h3 D3 l0 z; ~0 E
  69. * Helper struct to hold private data used to operate your ethernet interface.
    4 F, o- @0 m7 M) \+ C/ d2 X3 K
  70. * Keeping the ethernet address of the MAC in this struct is not necessary
    5 [0 U( t6 C" r8 R, ^( b5 z
  71. * as it is already kept in the struct netif.* b5 H  n9 m4 q' t2 z
  72. * But this is only an example, anyway...' S, @# U. L% O* ^7 x& A
  73. */
    % y) C. F0 M7 m
  74. struct ethernetif {0 j! k' K% g) Z4 X
  75.   struct eth_addr *ethaddr;
    7 W* D  g8 F, {( w
  76.   /* Add whatever per-interface state that is needed here. */
    $ W( l! s/ M( _4 B) n- K+ P
  77. };: f8 ~# D( ?. K4 X
  78. % |8 y0 U, ^" K0 n
  79. /* Forward declarations. */
    ' ^6 ~+ G- S8 [" H. W! R
  80. // 这里必须去掉static  R$ R! C+ s* L: a
  81. /*static */void  ethernetif_input(struct netif *netif);: x5 O3 a6 f! o4 F' E" `) d" e
  82. 8 m4 D! x$ R, D6 G
  83. /**
    ) C& V: _8 E7 Y  s
  84. * In this function, the hardware should be initialized.
    8 u8 l/ f; w# N' F
  85. * Called from ethernetif_init().
    5 y" k8 o1 B: S. y
  86. *+ J5 g2 V2 o" Q1 w: x& R& q' w
  87. * @param netif the already initialized lwip network interface structure
    - @' a* p7 ^' c4 e
  88. *        for this ethernetif) g8 K1 k* y& E8 X. X
  89. */, ~) S6 \! m, [
  90. static void3 |( }' P' O9 `& j4 C% v) I* m
  91. low_level_init(struct netif *netif)$ N2 z* Y% O& J- y! ?. b/ h
  92. {
    1 _* n# n, r2 p% V. P5 R4 _
  93.   struct ethernetif *ethernetif = netif->state;
    ) k# Q7 B: k( G' W9 |/ n" ~

  94. & E6 o- a4 A7 @1 f
  95.   /* set MAC hardware address length */" t2 p4 a* d" U5 K( X; X' ^; n
  96.   netif->hwaddr_len = ETHARP_HWADDR_LEN;+ r. B2 }/ h5 K; r  z! A* R

  97. ' x- f, R; J# x
  98.   /* set MAC hardware address */
    6 B" I% R/ }" F$ r0 c/ R% f0 s
  99.   WiFi_GetMACAddr(netif->hwaddr); // 获取网卡的默认MAC地址& c5 a6 {3 N: B
  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]);
    * g% J7 j7 t# b, D" }3 b
  101. # f1 h- c# L6 ^) w- S) M
  102.   /* maximum transfer unit */
    , x; ?+ O; e. w! W5 @
  103.   netif->mtu = 1500;
    $ w, s/ b  N0 M6 L) {  Z
  104. 6 [3 k' C3 y" Z; k5 U
  105.   /* device capabilities */
    8 s6 E; z9 N4 Q+ n9 @
  106.   /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */; g* N% p9 i. P, O4 O: n* i1 C
  107.   netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;3 D- l- D  Y0 G" w* I$ i+ x

  108. 9 b* A8 K- Y, R& ]0 M+ ^
  109. #if LWIP_IPV6 && LWIP_IPV6_MLD+ q: `* Z0 M& L2 h" B& {
  110.   /*# K9 j* c4 ]' C7 |) N5 O: x
  111.    * For hardware/netifs that implement MAC filtering.0 p1 K; |& N9 E$ N: E" M
  112.    * All-nodes link-local is handled by default, so we must let the hardware know
    6 A: ^! ?) C- W' w
  113.    * to allow multicast packets in.# L" [" R5 h: F6 J
  114.    * Should set mld_mac_filter previously. */
    ' ?+ U3 e, P9 A7 O. W; U: H
  115.   if (netif->mld_mac_filter != NULL) {
    2 w# S7 o6 d1 o% @9 Y1 \: _
  116.     ip6_addr_t ip6_allnodes_ll;
    / z4 @$ U+ u& l( r0 Y
  117.     ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
    8 P" C" w. H$ D# P2 `9 c
  118.     netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER);! R# k4 _: F. i* d! e0 @! W0 v
  119.   }9 q# X/ b3 Y6 j/ D
  120. #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */" f1 ~. G3 l& i" x) @
  121. ) n1 e5 `: |5 o; V
  122.   /* Do whatever else is needed to initialize interface. */
    % o/ m. s+ w# I; s' Z0 x, C
  123. }/ L1 ]) `8 b0 b9 `3 T$ q+ a: [
  124. ) c: z  W2 g5 i6 ]: G- z: j' z
  125. /**
    5 e. ~" U+ s: N" p  h' a6 z
  126. * This function should do the actual transmission of the packet. The packet is
    8 @& [# H6 L7 Q
  127. * contained in the pbuf that is passed to the function. This pbuf2 S4 v; ?. b4 A+ g; \: S
  128. * might be chained.5 j* g/ }" d9 X5 ?, G  l
  129. *; S9 U0 ~, k5 Y! \( i
  130. * @param netif the lwip network interface structure for this ethernetif
    6 `+ S# u3 e9 z- c# P6 q1 G
  131. * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)8 P; i7 X6 Q' M* d. ]' e$ c
  132. * @return ERR_OK if the packet could be sent
    + v" s* k% ^1 x( d  H6 l( C
  133. *         an err_t value if the packet couldn't be sent
    & X4 R9 i& l* G9 U
  134. *
    0 I5 b( k* t6 U3 n6 e' \
  135. * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
    7 T: J4 K  H9 M! }4 |8 ?
  136. *       strange results. You might consider waiting for space in the DMA queue& c) a4 x6 {" b  x( c
  137. *       to become available since the stack doesn't retry to send a packet
    / I" O/ a5 a. |1 B; y8 r
  138. *       dropped because of memory failure (except for the TCP timers).
    0 Z+ W7 q4 |0 h0 ^
  139. */
    5 X* o; v) O/ `, L# }" I

  140. 7 W0 ?8 q/ w5 i: Y
  141. static err_t
    3 O4 n& z2 \- Q' S' b
  142. low_level_output(struct netif *netif, struct pbuf *p)' T. w; L+ ~+ B3 S1 C
  143. {
    2 t2 F  ^& f. W* N6 z, A, t
  144.   struct ethernetif *ethernetif = netif->state;
    0 G! Q' {. s+ u5 `7 k7 j
  145.   struct pbuf *q;
    5 d6 d! W# H6 Y# |( Z" n
  146.         6 c. E2 [) z* Z- d9 R
  147.   // 添加的变量
    6 j. N+ O2 C6 m( x7 V, ^% i( r
  148.   uint8_t buffer[1792];
      r* F" p+ t  s: g  z6 m6 N
  149.   WiFi_DataTx *packet = (WiFi_DataTx *)buffer;; A& h% E! v1 \; O1 v$ z+ g
  150.   uint8_t *bufptr = packet->payload;0 T; p1 K6 _( e
  151. 9 t1 Z1 C. @' i1 Y# J
  152.   //initiate transfer();, W) q# {9 a1 D1 u

  153. ' J- ], @' h9 L- A1 S$ `- o- R
  154. #if ETH_PAD_SIZE
    1 T- z" `6 }6 w  e! X3 S" K
  155.   pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
    . H% k  r* f( g3 S- x
  156. #endif! N9 h* g) @; h1 d  i+ M. D
  157. " A- H3 \2 w. o, D
  158.   for (q = p; q != NULL; q = q->next) {; b  y% t- m; t  T6 x5 v' h
  159.     /* Send the data from the pbuf to the interface, one pbuf at a
    + W, \' g# G* J
  160.        time. The size of the data in each pbuf is kept in the ->len
    4 H4 N" z% I. Y4 Q7 i; F9 W. F
  161.        variable. */
    ! v( d+ M6 y* C4 ]
  162.     //send data from(q->payload, q->len);0 e( d3 C& I. R
  163.         memcpy(bufptr, q->payload, q->len); // 复制数据包内容
    ! ]1 w  t1 U3 r, `, _# Z4 ~7 D2 Q
  164.         bufptr += q->len; // 指针前移
    - o1 T( o8 }% W" b
  165.   }
    6 o) x# ?' U1 o. M3 V
  166. , i% B8 w6 O2 U6 m+ l2 v! w! ]4 H
  167.   //signal that packet should be sent();  V8 F9 ^9 d0 v# [6 h3 a
  168.   WiFi_SendPacket(packet, bufptr - packet->payload); // 发送数据包2 X7 m. Z+ ~, T) {3 G. s9 r) ?
  169.   
    6 u8 x# R! F% Q/ i: ?" ~: x1 y" _
  170.   // 打印数据包内容
    + D& L- D: p% L" e$ c1 v- G% @/ y
  171.   printf("[Send] size=%d\n", packet->tx_packet_length);  o* v& n' B% S/ N! O0 |. }* C
  172.   dump_data(packet->payload, packet->tx_packet_length);0 o  m& x6 }# _

  173. 4 {2 m0 p2 F. O4 q# J: t
  174.   MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
    / \# p; _1 M6 ~1 b% s
  175.   if (((u8_t*)p->payload)[0] & 1) {
    6 U; j6 B% ]3 C8 ]2 p
  176.     /* broadcast or multicast packet*/- U4 B3 M3 f: `  f0 r* t2 @9 r
  177.     MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
    % o: \$ c' Y, y" f5 O1 `! {
  178.   } else {
    / h6 c8 F- Y" `- Q
  179.     /* unicast packet */
    5 O: Q  q3 a) |! X% P
  180.     MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);- f/ U9 h0 a2 q& ?5 e$ Q4 s
  181.   }$ m) `2 B: o: j) e  A
  182.   /* increase ifoutdiscards or ifouterrors on error */) K; ?; z2 H: Y, H- P) `" c: [
  183. & {! z  S; V: p7 w) P$ {$ u% o
  184. #if ETH_PAD_SIZE% |. ~' `& e  e7 F
  185.   pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */% Y0 x  X/ v) v& y  N9 J1 _
  186. #endif
    2 }6 |; g" n5 b6 p9 p+ [
  187. 4 A6 D3 Z: Y, _+ Y& k
  188.   LINK_STATS_INC(link.xmit);
    3 _! D9 O6 E1 A' h4 i$ q% V! s
  189. 1 ]* d# V( J  y! h4 t1 H& K$ n
  190.   return ERR_OK;$ U* _: M  _' E6 ]
  191. }, Z/ [4 N* L$ a7 U

  192. * u! I( ]2 b5 ~5 `1 y" V
  193. /**9 |- f6 j' ?2 v( b4 G) J
  194. * Should allocate a pbuf and transfer the bytes of the incoming. \2 j3 g! x$ b3 W/ ~9 v
  195. * packet from the interface into the pbuf.! s' U, f* I* i; F3 l9 S3 @
  196. *( X6 a8 h& U+ ^" W
  197. * @param netif the lwip network interface structure for this ethernetif4 Z% O4 O* m. v! X
  198. * @return a pbuf filled with the received packet (including MAC header)
    4 Q5 R+ g' g9 ~
  199. *         NULL on memory error
    ! t/ f( _. j6 z
  200. */
    ! u5 ]$ p  a- r1 w& A9 V
  201. static struct pbuf *' R6 L* h4 H9 a7 p" A% w  T( W
  202. low_level_input(struct netif *netif)
    - n% O7 G+ I" v* b  n) v. W4 C
  203. {  O$ {# m9 T- P, s
  204.   struct ethernetif *ethernetif = netif->state;
    " I3 c) v$ g$ H! w6 N; y- v' }
  205.   struct pbuf *p, *q;1 b+ u) N% l6 }: T* m* N
  206.   u16_t len;* I; x) r4 A. f& l7 h
  207.         3 `9 O2 E3 y+ f9 Q3 x+ w
  208.   // 添加的变量1 m; ]7 V8 ?4 L& ]) t7 G) l! R( X
  209.   uint8_t buffer[1792]; // 由于WiFi模块本身不支持使用多个CMD53命令读取数据包, 所以必须建立一个缓冲区, 一次性读取完% A" p# B+ N9 ^7 {9 c+ Q9 @3 u
  210.   WiFi_DataRx *packet = (WiFi_DataRx *)buffer;3 v% j- U: f& U. F7 Z0 C! i
  211.   uint8_t *bufptr = packet->payload;
    , @4 W; m6 c; W# c% p. W. N9 R/ s

  212. 2 l, p" Y% T) T  X0 \
  213.   /* Obtain the size of the packet and put it into the "len"
    4 d3 I! t% L9 g; @( V' G0 n4 z
  214.      variable. */
    : y" u: A! z8 U9 q
  215.   len = WiFi_ReceivePacket(buffer, sizeof(buffer)); // 读取整个数据包, 返回值包含头部大小
    ) y! A$ z! S# x1 Z8 v6 Z
  216.   if (len == 0)+ Y- `+ z/ I, y+ u& B, S. n
  217.   {6 c! m( c1 t: I1 e$ c
  218.           // 若读取失败, 则不分配pbuf, 退出本函数8 ^5 C- E% s/ b' d3 r
  219.           p = NULL;3 A0 b- V; G' M' S" l0 q. U+ h
  220.           goto after_alloc;
    " e2 \4 `! D* u$ [
  221.   }9 m$ D9 r) v' ~0 ~3 o0 s1 _8 b
  222.   len = packet->rx_packet_length; // 获取数据包的大小! `7 m" _7 N- @
  223.         
    & @& `+ b% @! W8 S
  224.   // 打印数据包内容
    ; A" O( ^  a% i: Q1 J" U- v! E) M
  225.   printf("[Recv] size=%d\n", len);, Q$ `" o  ~. L3 w0 l5 t
  226.   dump_data(packet->payload, len);
    ) `+ a& |% O/ I' _* l$ ?

  227. 4 {1 b( U, r0 h: q: s  ?
  228. #if ETH_PAD_SIZE0 G; l0 N+ P; Y! [
  229.   len += ETH_PAD_SIZE; /* allow room for Ethernet padding */+ U/ z6 }% T# x4 }1 `9 |
  230. #endif7 f% \2 ?# ?7 j5 n8 R" k; m) A# w
  231. 2 n' M# F" F$ T
  232.   /* We allocate a pbuf chain of pbufs from the pool. */+ o: `# G0 d& p8 {1 c
  233.   p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
    ) F1 B" N' v' t0 C4 ]
  234.   2 f( y9 ^2 H- J
  235. after_alloc: // 添加此标记6 M: G0 e2 T0 N3 [* G

  236. 8 K0 c1 B3 v0 ]% k2 H, }4 G: [  t
  237.   if (p != NULL) {, P+ z: J1 _* i8 e
  238. ! _& k9 O" E! e8 ~# z3 ^
  239. #if ETH_PAD_SIZE) K4 E% d% W4 x7 E; W( U
  240.     pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */9 u$ C9 f$ A8 R3 ?& h+ W
  241. #endif
    8 S  r" J& u7 c+ p& X4 s3 q

  242. . i. V! C' D6 }" b
  243.     /* We iterate over the pbuf chain until we have read the entire/ z& d; R0 {! o$ c/ x5 K
  244.      * packet into the pbuf. */3 m3 l2 Y8 O* U# @# ]. N) z4 a
  245.     for (q = p; q != NULL; q = q->next) {
    * w; n6 O. k! L
  246.       /* Read enough bytes to fill this pbuf in the chain. The& Q) g2 K: b& U1 [: X
  247.        * available data in the pbuf is given by the q->len
    $ D( T/ F- c  {4 J( m9 ?/ \
  248.        * variable.
      l5 Y+ w$ d( s5 d# b
  249.        * This does not necessarily have to be a memcpy, you can also preallocate, W5 _8 w. b* `- Z+ D/ J6 m
  250.        * pbufs for a DMA-enabled MAC and after receiving truncate it to the
    8 I4 f$ \9 `, W
  251.        * actually received size. In this case, ensure the tot_len member of the% U) H2 ?% M% S/ m
  252.        * pbuf is the sum of the chained pbuf len members.5 r  |% G( J+ ~; y3 D, i$ ^
  253.        */
    ( y! Q/ T  ^* H3 V6 x0 ~
  254.       //read data into(q->payload, q->len);$ }- C: q7 F) x( }! p+ x
  255.                 memcpy(q->payload, bufptr, q->len); // 复制数据包内容4 V4 l2 u! n6 a- S7 o4 q& ^- ~
  256.                 bufptr += q->len; // 指针前移6 \- l3 W  h7 L% f5 ]* }# \
  257.     }  W* U' u9 f6 _' H* r
  258.     //acknowledge that packet has been read(); // 无需确认
    " E2 v( e1 \# g
  259. 6 I$ ~, j0 a1 G0 o
  260.     MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);1 v: W, P% Q- L! C& Z1 P9 p3 \
  261.     if (((u8_t*)p->payload)[0] & 1) {" S$ ^  Z; N/ P0 l
  262.       /* broadcast or multicast packet*/* [% O# ]" Q" Q1 b. n  {
  263.       MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);( Z8 |0 h% s) t. t
  264.     } else {
    3 y0 o2 d: e" [/ s! u( S
  265.       /* unicast packet*/; L- A" S3 G5 I. e8 J$ e- R/ a
  266.       MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
    0 X4 s0 d6 u) T
  267.     }8 ]1 z( s( }/ q* p8 |
  268. #if ETH_PAD_SIZE
    9 w% J$ |/ }6 g: D: a8 b* J% e" g
  269.     pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */6 |2 G! J8 J( [; c8 |
  270. #endif/ v: y0 M  y$ k) x1 g0 r% q

  271. / z& k) e5 R  x* |# a% S! r
  272.     LINK_STATS_INC(link.recv);% ~! n9 C- c8 |* ~5 o- q
  273.   } else {1 B% V1 h: z$ Z! ^* s) g4 A  Y% b
  274.     //drop packet(); // 注释掉此行0 {3 Q6 o# B7 J9 g
  275.     LINK_STATS_INC(link.memerr);9 |4 t1 B: u( Q0 s
  276.     LINK_STATS_INC(link.drop);
    ; ?9 B8 y. j" Q% [( `4 D$ {& l* m
  277.     MIB2_STATS_NETIF_INC(netif, ifindiscards);
    - h! H3 m$ k# x( c- Y% w: f
  278.   }
    * Y/ ]6 C  Z) q$ \
  279. , N- e/ T4 ^9 \+ E5 s& a
  280.   return p;$ z0 ]: O0 I$ g* p" M, `
  281. }1 W% p2 d4 w- s! \/ P; h1 m

  282. / l$ C' ~6 d. g) N1 g* Z! [& M! V* e; V
  283. /**) I) v: J& M) g% m
  284. * This function should be called when a packet is ready to be read! p  w1 t# M9 t+ W5 |! {( T: I, l
  285. * from the interface. It uses the function low_level_input() that
    ! H$ t, E; A. @& K5 e2 r- u$ K
  286. * should handle the actual reception of bytes from the network: j" l5 D/ d& t* S1 j: X
  287. * interface. Then the type of the received packet is determined and
    * B* H, r5 T$ q4 r' L* L+ ]" A
  288. * the appropriate input function is called.
    * z- O4 O- f* G: e6 i# F$ x
  289. *8 X, ?" J' T. D6 H6 C% i
  290. * @param netif the lwip network interface structure for this ethernetif; S5 ?  ^/ i6 A$ k" {+ Q
  291. */
    4 P% w# Q+ K. [' g: v2 N
  292. // 必须去掉static9 l: c9 }9 V. K6 R  F& R
  293. /*static */void1 Q: o" o6 F6 T0 y; X
  294. ethernetif_input(struct netif *netif)- L3 c+ n8 k2 u
  295. {( k4 a3 i' n: M
  296.   struct ethernetif *ethernetif;
      |0 J, A6 e" T% |# X( Y
  297.   struct eth_hdr *ethhdr;6 o. p3 e/ p4 M; W" D
  298.   struct pbuf *p;/ J3 W* |8 |% ]& z% U0 e

  299. 6 o  ]6 ]4 B5 v0 b/ ^4 }" _
  300.   ethernetif = netif->state;
    , z. Y. S4 G+ }/ a6 {
  301. ' t. U$ D/ T! E: K1 p  l  b! t. e. E2 N
  302.   /* move received packet into a new pbuf */6 a) J# i' H0 x& N
  303.   p = low_level_input(netif);
    8 [  n: L" W3 x2 X3 e
  304.   /* if no packet could be read, silently ignore this */" q( a9 D' f3 l& g: F# T1 m
  305.   if (p != NULL) {% O# o  N* Y$ r0 ~
  306.     /* pass all packets to ethernet_input, which decides what packets it supports */
    6 b+ A9 ^  r# J8 u/ E# K
  307.     if (netif->input(p, netif) != ERR_OK) {' T7 o6 F. ^2 O# K# f, _
  308.       LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));: \8 R2 Y# v2 m6 C2 v* |( e
  309.       pbuf_free(p);
    4 P+ }. I5 m9 I$ P5 n# y8 ^
  310.       p = NULL;
    3 k! g+ \0 B! E# j
  311.     }
    9 q# ?: d- T1 B8 A! }
  312.   }
    8 P8 x: G7 q- R2 Q/ Y1 E3 H
  313. }
    , s1 ]7 F. K' A9 M% g# t

  314. ' N$ x+ [* S0 y; c" h% r0 L; [, i
  315. /**
    - r3 j1 [: L  ?9 H9 |
  316. * Should be called at the beginning of the program to set up the/ V( W# t2 a1 Y* \& M: l
  317. * network interface. It calls the function low_level_init() to do the
    - j. [- n, i" L' w* F) ?
  318. * actual setup of the hardware.
    5 [$ V; t1 B" b7 O* o
  319. *
    7 n" ?2 S2 e0 f/ H. f
  320. * This function should be passed as a parameter to netif_add().6 S( p! ^6 R8 D" W  I7 ^3 x5 S
  321. *
    & Y0 {% j+ `5 |, n, h
  322. * @param netif the lwip network interface structure for this ethernetif
    : N5 g* [% ?. g% u( Z4 q
  323. * @return ERR_OK if the loopif is initialized
    : q2 _8 z0 ?: H
  324. *         ERR_MEM if private data couldn't be allocated
    4 h% c) y6 |! @3 r( Y
  325. *         any other err_t on error/ d3 l: K' R: W9 n: e% U8 N
  326. */$ V* s, G$ k2 ?) t4 k1 [, U
  327. err_t
    . w1 P1 ]5 ~+ J2 @3 e6 ^
  328. ethernetif_init(struct netif *netif)
    3 e4 F* I8 M- c
  329. {
    5 Q# f$ S! l9 |" L3 o; ^
  330.   struct ethernetif *ethernetif;; S( d" U0 z- ^; T

  331. % w" {6 Q3 Z2 E0 I" Y
  332.   LWIP_ASSERT("netif != NULL", (netif != NULL));
    ( U' N/ E" c' I- R, B% V' s6 c5 `- p! }
  333. 7 ]/ g+ n8 s( A% x6 w3 B, @
  334.   ethernetif = mem_malloc(sizeof(struct ethernetif));/ j5 K! }3 k8 \
  335.   if (ethernetif == NULL) {
    0 E. Q" O2 W' V7 v
  336.     LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));. I9 R8 E6 T/ I( q
  337.     return ERR_MEM;
    # h7 }' p! `' g- P- A7 U" F& z
  338.   }
    / ^& W& U$ w+ r7 G0 z- g7 H
  339. + g. |/ n, B% k
  340. #if LWIP_NETIF_HOSTNAME9 d) C  S# _6 \6 F+ U6 F4 \! h
  341.   /* Initialize interface hostname */
    + ~- \/ m/ T6 V. ~. Q3 D/ T
  342.   netif->hostname = "lwip";; z# a9 s8 G& N6 e5 f/ t
  343. #endif /* LWIP_NETIF_HOSTNAME */2 P- x/ T9 X; L5 o1 V# ^& y
  344. . x, m7 _' R* M" [. b0 H
  345.   /*
    ) |- G1 W1 o' ~$ ~) c7 N2 {
  346.    * Initialize the snmp variables and counters inside the struct netif.5 p8 h% Z0 s% x* o6 Q
  347.    * The last argument should be replaced with your link speed, in units
    * r# @/ |, f- S2 O& `
  348.    * of bits per second.
    8 m! m: ~% X0 P' v$ v& d/ Q
  349.    */4 f) @/ e( q& p% G2 U7 e# L  t1 @# Q
  350.   MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);% p2 X. p7 ?0 [

  351. 1 m. j* V5 P: o; j( e
  352.   netif->state = ethernetif;! {9 u6 F4 z4 _7 M
  353.   netif->name[0] = IFNAME0;7 j! X' n  C# P# ^0 K# m, X3 |
  354.   netif->name[1] = IFNAME1;+ q% Z4 m" w8 T+ s$ y
  355.   /* We directly use etharp_output() here to save a function call.3 k1 [0 ~/ E7 i1 |+ J( Y% g
  356.    * You can instead declare your own function an call etharp_output()
    / C/ u( H/ k/ A  G: A8 [
  357.    * from it if you have to do some checks before sending (e.g. if link9 g4 x4 w3 N$ ]* {+ V  _
  358.    * is available...) */
    * u0 `* i' }+ Z- S
  359.   netif->output = etharp_output;
    # Z5 f" G/ g1 U9 O% r
  360. #if LWIP_IPV68 ?5 Q2 a4 x: X6 n. f. d" D
  361.   netif->output_ip6 = ethip6_output;8 ?0 L( D- u3 o: i. l" B5 |% ]/ ^. W5 H
  362. #endif /* LWIP_IPV6 */
    8 [2 q' N3 ^& R1 {$ \
  363.   netif->linkoutput = low_level_output;: }0 U% G0 G/ U' j
  364.   D9 S- }5 r8 {/ V/ U. N& }8 Q
  365.   ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);$ c/ ]: H, H7 H1 w9 }
  366. 6 r! Q: A5 |# X9 y5 H# Q
  367.   /* initialize the hardware *// ^8 z, d! @  X/ F% W9 C
  368.   low_level_init(netif);
    / o6 H2 I3 u# x  Q5 O7 n7 m: k* A
  369. - }" t2 p0 z1 z, z
  370.   return ERR_OK;
    7 o5 t2 n: Z( s5 ]3 d
  371. }
      d6 M1 P8 }, M5 [; y( N" Z5 f4 ]

  372.   K, F% Q$ f( S9 ]. p- Z# @8 Q8 E
  373. #endif /* 0 */( B5 W; ?9 T" j+ d' U
复制代码
3 d5 K8 s  A7 `* A: {; `' x2 X( a
在项目属性中,设置Include Paths为:.;.\lwip\include! S0 x% A& h1 u: g+ Z8 l9 a& B0 ~
其中点表示工程根目录。* J" q7 L5 N) h4 k  }

% K7 g  [  x# M& E另外,为了在程序中使用printf函数,Target选项卡下的Use MicroLIB复选框也要勾选上。3 S2 |. ]+ \' X3 u0 u4 c
3 C: f) d3 G$ \6 A3 S  c  F
编译并下载程序,电脑和WiFi模块要连同一个WiFi热点。
! C2 t) k7 g; Q0 n  ?6 Q电脑的IP地址要手动配置。IP地址为192.168.43.71(最后一个数随便),子网掩码为255.255.255.0,网关为192.168.43.1。" X$ [4 _  `( V8 E4 O' S  J
配置完成后,即可用电脑上的浏览器访问开发板上面的HTTP服务器。4 h# `* q% q" @: g7 @  N5 H$ O

评分

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

查看全部评分

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

举报

5个回答
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....+ x0 P9 C1 y, \" q

: x% S# ]. l& p/ K# e: g多谢分享
zlk1214 回答时间:2025-4-8 13:55:18
while (WiFi_GetPacketLength() == 0xfedc);
写错了,应该是
while (WiFi_GetPacketLength() != 0xfedc);
才对。
L

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版