请选择 进入手机版 | 继续访问电脑版
搜索
查看: 4378|回复: 4

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

[复制链接]

该用户从未签到

5

主题

23

帖子

0

蝴蝶豆

初级会员

最后登录
2020-8-3
发表于 2017-7-20 16:34:07 | 显示全部楼层 |阅读模式
本程序所用的单片机型号为:STM32F103RE
PB12端口为外接的WiFi模块电源开关,当PB12输出低电平时接通电源。
注意:WM-G-MR-09模块的芯片组(Chip Set)就是Marvell 88W8686。
该程序目前只能连接没有设密码的路由器,创建热点时也无法设置密码。
固件内容请参考:http://blog.csdn.net/zlk1214/article/details/74612925

注意必须把STM32启动文件*.s中的函数堆栈大小Stack_Size改大,否则函数中无法创建大数组!
  1. Stack_Size      EQU     0x00000c00  
复制代码
【main.c】
  1. #include <stdio.h>
  2. #include <stm32f10x.h>
  3. #include <string.h>
  4. #include "lwip/init.h" // lwip_init函数所在的头文件
  5. #include "lwip/timeouts.h" // sys_check_timeouts函数所在的头文件
  6. #include "netif/ethernet.h" // ethernet_input函数所在头文件
  7. #include "WiFi.h"

  8. // 这两个函数位于ethernetif.c中, 但没有头文件声明
  9. err_t ethernetif_init(struct netif *netif);
  10. void ethernetif_input(struct netif *netif);

  11. // httptest.c中的函数
  12. void init_http(void);

  13. // 延时n毫秒
  14. void delay(uint16_t n)
  15. {
  16.     WiFi_PrepareTimer(n);
  17.     while ((TIM6->SR & TIM_SR_UIF) == 0); // 等待计时完毕
  18.     TIM6->SR &= ~TIM_SR_UIF; // 清除溢出标志
  19. }

  20. void dump_data(uint8_t *data, uint16_t len)
  21. {
  22.     while (len--)
  23.         printf("%02X", *data++);
  24.     printf("\n");
  25. }

  26. int fputc(int ch, FILE *fp)
  27. {
  28.     if (fp == stdout)
  29.     {
  30.         if (ch == '\n')
  31.         {
  32.             while ((USART1->SR & USART_SR_TXE) == 0);
  33.             USART1->DR = '\r';
  34.         }
  35.         while ((USART1->SR & USART_SR_TXE) == 0);
  36.         USART1->DR = ch;
  37.     }
  38.     return ch;
  39. }

  40. // RTC时间转化为毫秒数
  41. uint32_t sys_now(void)
  42. {
  43.     uint32_t tmp = (RTC->CNTH << 16) | RTC->CNTL; // 秒
  44.     tmp = tmp * 1000 + (32767 - RTC->DIVL) * 1000 / 32768; // 毫秒
  45.     return tmp;
  46. }

  47. int main(void)
  48. {
  49.     struct ip4_addr ipaddr, netmask, gw;
  50.     struct netif wifi_88w8686;
  51.     uint32_t last_check = 0;
  52.    
  53.     RCC->AHBENR = RCC_AHBENR_SDIOEN;
  54.     RCC->APB1ENR = RCC_APB1ENR_PWREN | RCC_APB1ENR_TIM6EN;
  55.     RCC->APB2ENR = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | RCC_APB2ENR_USART1EN;
  56.    
  57.     GPIOA->CRH = 0x000004b0;
  58.     GPIOB->CRH = 0x00030000; // PB12为外接的WiFi模块电源开关, PB12=0时打开WiFi模块
  59.     GPIOC->CRH = 0x000bbbbb;
  60.     GPIOD->CRL = 0x00000b00;
  61.    
  62.     USART1->BRR = 0x271; // 波特率: 115200
  63.     USART1->CR1 = USART_CR1_UE | USART_CR1_TE;
  64.    
  65.     PWR->CR = PWR_CR_DBP; // 允许写入后备寄存器
  66.     if ((RCC->CSR & RCC_CSR_LSION) == 0)
  67.     {
  68.         RCC->CSR |= RCC_CSR_LSION; // 开内部低速晶振LSI
  69.         while ((RCC->CSR & RCC_CSR_LSIRDY) == 0);
  70.         //printf("LSI Ready!\n");
  71.     }
  72.     if ((RCC->BDCR & RCC_BDCR_RTCEN) == 0)
  73.     {
  74.         // 若RTC还没有打开, 则初始化RTC
  75.         RCC->BDCR |= RCC_BDCR_RTCEN; // 打开RTC外设, 但暂不开始走时
  76.         
  77.         RTC->CRL |= RTC_CRL_CNF; // 进入RTC配置模式
  78.         RTC->PRLH = 0;
  79.         RTC->PRLL = 39999; // 定时1s (PRLH和PRLL寄存器只能写不能读)
  80.         //RTC->CNTH = 0;
  81.         //RTC->CNTL = 50; // 初始时间
  82.         RTC->CRL &= ~RTC_CRL_CNF; // 保存设置
  83.         
  84.         RCC->BDCR |= RCC_BDCR_RTCSEL_1; // 选LSI作为RTC时钟, 准备走时
  85.         while ((RTC->CRL & RTC_CRL_RTOFF) == 0); // 等待设置生效
  86.         // RTC从此处开始走时
  87.     }
  88.    
  89.     WiFi_Init();
  90.     WiFi_Scan();
  91.    
  92.     //WiFi_StartADHOC("Marvell_88W8686"); // 创建一个热点
  93.     WiFi_Connect("vivo Y29L", NULL); // 连接一个WiFi热点 (目前还不支持设密码)
  94.    
  95.     lwip_init();
  96.     IP4_ADDR(&ipaddr, 192, 168, 43, 10); // IP地址
  97.     IP4_ADDR(&netmask, 255, 255, 255, 0); // 子网掩码
  98.     IP4_ADDR(&gw, 192, 168, 43, 1); // 网关
  99.    
  100.     netif_add(&wifi_88w8686, &ipaddr, &netmask, &gw, NULL, ethernetif_init, ethernet_input);
  101.     netif_set_default(&wifi_88w8686); // 设为默认网卡
  102.     netif_set_up(&wifi_88w8686);
  103.    
  104.     init_http();
  105.    
  106.     while (1)
  107.     {
  108.         if (WiFi_PacketPending() || WiFi_PacketArrived())
  109.             ethernetif_input(&wifi_88w8686);
  110.         
  111.         // sys_check_timeouts函数千万不能调用的太频繁, 否则会出错!(例如开机后要等1~2分钟DHCP才能分配到IP地址)
  112.         if (sys_now() - last_check > 200)
  113.         {
  114.             last_check = sys_now();
  115.             //printf("Time: %d\n", last_check);
  116.             sys_check_timeouts();
  117.         }
  118.     }
  119. }
复制代码
【httptest.c】
  1. #include <string.h>
  2. #include "lwip/tcp.h" // 一般情况下需要包含的头文件

  3. #define STR_AND_SIZE(str) (str), strlen(str)

  4. err_t http_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
  5. {
  6.         char len[10]; // 存放HTML内容的长度
  7.         char str[200]; // 存放HTML内容
  8.         
  9.         char name[100];
  10.         char *pstr;
  11.         uint8_t i = 0;
  12.         if (p != NULL)
  13.         {
  14.                 // 提取页面名称
  15.                 pstr = (char *)p->payload;
  16.                 while (*pstr++ != ' ');
  17.                 while (*pstr != ' ')
  18.                         name[i++] = *pstr++;
  19.                 name[i] = '\0'; // 不要忘了结束name字符串
  20.                 tcp_recved(tpcb, p->tot_len);
  21.                
  22.                 // 生成HTML内容
  23.                 sprintf(str, "<meta charset="gb2312"><title>获取网页名称</title><div style="font-family:Arial"><b>请求的网页文件名称是: </b>%s</div>", name);
  24.                
  25.                 sprintf(len, "%d", strlen(str)); // HTML内容的长度
  26.                 tcp_write(tpcb, STR_AND_SIZE("HTTP/1.1 200 OK\r\nContent-Length: "), TCP_WRITE_FLAG_MORE);
  27.                 tcp_write(tpcb, STR_AND_SIZE(len), TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
  28.                 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);
  29.                 tcp_write(tpcb, STR_AND_SIZE(str), TCP_WRITE_FLAG_COPY); // 发送HTML内容
  30.                 pbuf_free(p);
  31.         }
  32.         return ERR_OK;
  33. }

  34. err_t http_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
  35. {
  36.         tcp_recv(newpcb, http_recv);
  37.         return ERR_OK;
  38. }

  39. void init_http(void)
  40. {
  41.         struct tcp_pcb *tpcb = tcp_new();
  42.         tcp_bind(tpcb, IP_ADDR_ANY, 80);
  43.         tpcb = tcp_listen(tpcb);
  44.         tcp_accept(tpcb, http_accept);
  45. }
复制代码
【WiFi.h】
  1. #define _BV(n) (1u << (n))

  2. #define CMD52_WRITE _BV(31)
  3. #define CMD52_READAFTERWRITE _BV(27)

  4. #define CMD53_WRITE _BV(31)
  5. #define CMD53_BLOCKMODE _BV(27)
  6. #define CMD53_INCREMENTING _BV(26)

  7. // 16.5 SDIO Card Metaformat
  8. #define CISTPL_NULL 0x00 // Null tuple
  9. #define CISTPL_VERS_1 0x15 // Level 1 version/product-information
  10. #define CISTPL_MANFID 0x20 // Manufacturer Identification String Tuple
  11. #define CISTPL_FUNCID 0x21 // Function Identification Tuple
  12. #define CISTPL_FUNCE 0x22 // Function Extensions
  13. #define CISTPL_END 0xff // The End-of-chain Tuple

  14. #define WIFI_DEFAULTTIMEOUT 1500 // WiFi命令回应的超时时间(ms)

  15. #define WIFI_SQREADBASEADDR0 0x10
  16. #define WIFI_SQREADBASEADDR1 0x11
  17. #define WIFI_SQREADBASEADDR2 0x12
  18. #define WIFI_SQREADBASEADDR3 0x13

  19. #define WIFI_CARDSTATUS 0x20 // Card Status
  20. #define WIFI_CARDSTATUS_IOREADY _BV(3) // I/O Ready Indicator
  21. #define WIFI_CARDSTATUS_CISCARDRDY _BV(2) // Card Information Structure Card Ready
  22. #define WIFI_CARDSTATUS_UPLDCARDRDY _BV(1) // Upload Card Ready
  23. #define WIFI_CARDSTATUS_DNLDCARDRDY _BV(0) // Download Card Ready

  24. #define WIFI_CAPABILITY_BSS _BV(0)
  25. #define WIFI_CAPABILITY_IBSS _BV(1)
  26. #define WIFI_CAPABILITY_CF_POLLABLE _BV(2)
  27. #define WIFI_CAPABILITY_CF_POLL_REQUEST _BV(3)
  28. #define WIFI_CAPABILITY_PRIVACY _BV(4)
  29. #define WIFI_CAPABILITY_SHORT_PREAMBLE _BV(5)
  30. #define WIFI_CAPABILITY_PBCC _BV(6)
  31. #define WIFI_CAPABILITY_CHANNEL_AGILITY _BV(7)
  32. #define WIFI_CAPABILITY_SPECTRUM_MGMT _BV(8)
  33. #define WIFI_CAPABILITY_QOS _BV(9)
  34. #define WIFI_CAPABILITY_SHORT_SLOT _BV(10)
  35. #define WIFI_CAPABILITY_DSSS_OFDM _BV(13)

  36. #define WIFI_SDIOFRAME_DATA 0x00
  37. #define WIFI_SDIOFRAME_COMMAND 0x01
  38. #define WIFI_SDIOFRAME_EVENT 0x03

  39. /* Command List */
  40. #define CMD_802_11_SCAN 0x0006 // Starts the scan process
  41. #define CMD_802_11_ASSOCIATE 0x0012 // Initiate an association with the AP
  42. #define CMD_MAC_CONTROL 0x0028 // Controls hardware MAC
  43. #define CMD_802_11_AD_HOC_START 0x002b // Starts an Ad-Hoc network
  44. #define CMD_802_11_MAC_ADDR 0x004d // WLAN MAC address
  45. #define CMD_802_11_KEY_MATERIAL 0x005e // Gets/sets key material used to do Tx encryption or Rx decryption
  46. #define CMD_802_11_BG_SCAN_CONFIG 0x006b // Gets/sets background scan configuration
  47. #define CMD_802_11_BG_SCAN_QUERY 0x006c // Gets background scan results

  48. /* Command Result Codes */
  49. #define CMD_STATUS_SUCCESS 0x0000 // No error
  50. #define CMD_STATUS_ERROR 0x0001 // Command failed
  51. #define CMD_STATUS_UNSUPPORTED 0x0002 // Command is not supported

  52. #define WIFI_ACT_GET 0
  53. #define WIFI_ACT_SET 1

  54. /* Authentication Type to be used to authenticate with AP */
  55. #define AUTH_MODE_OPEN 0x00
  56. #define AUTH_MODE_SHARED 0x01
  57. #define AUTH_MODE_NETWORK_EAP 0x80

  58. /* WiFi_Associate return value */
  59. #define WIFI_ASSOCIATION_NOTFOUND 0xfffe
  60. #define WIFI_ASSOCIATION_ERROR 0xffff
  61. #define WIFI_ASSOCIATION_SUCCESS 0x0000 // 连接成功
  62. #define WIFI_ASSOCIATION_INTERNALERROR 0x0101
  63. #define WIFI_ASSOCIATION_AUTHUNHANDLED(ret) (((ret) & 0xff00) == 0x200) // 未处理的认证帧
  64. #define WIFI_ASSOCIATION_UNSUPPORTEDAUTHALG 0x0213
  65. #define WIFI_ASSOCIATION_INVALIDSEQUENCENUMBER 0x0214
  66. #define WIFI_ASSOCIATION_AUTHREFUSED(ret) (((ret) & 0xff00) == 0x300) // 认证失败
  67. #define WIFI_ASSOCIATION_TIMEOUT(ret) (((ret) & 0xff00) == 0x400) // 超时
  68. #define WIFI_ASSOCIATION_ASSOCTIMEOUT 0x0401 // 连接超时
  69. #define WIFI_ASSOCIATION_AUTHTIMEOUT 0x402 // 认证超时
  70. #define WIFI_ASSOCIATION_NETWORKJOINTIMEOUT 0x403 // 加入网络时超时

  71. #define WIFI_KEYTYPE_WEP 0
  72. #define WIFI_KEYTYPE_TKIP 1
  73. #define WIFI_KEYTYPE_AES 2

  74. #define WIFI_KEYINFO_KEYENABLED _BV(2)
  75. #define WIFI_KEYINFO_UNICASTKEY _BV(1)
  76. #define WIFI_KEYINFO_MULTICASTKEY _BV(0)

  77. #define WIFI_MACCTRL_RX _BV(0)
  78. #define WIFI_MACCTRL_TX _BV(1) // 此位必须要置1才能发送数据!!!
  79. #define WIFI_MACCTRL_LOOPBACK _BV(2)
  80. #define WIFI_MACCTRL_WEP _BV(3)
  81. #define WIFI_MACCTRL_ETHERNET2 _BV(4)
  82. #define WIFI_MACCTRL_PROMISCUOUS _BV(7)
  83. #define WIFI_MACCTRL_ALLMULTICAST _BV(8)
  84. #define WIFI_MACCTRL_ENFORCEPROTECTION _BV(10) // strict protection
  85. #define WIFI_MACCTRL_ADHOCGPROTECTIONMODE _BV(13) // 802.11g protection mode

  86. /* BSS type */
  87. #define BSS_INFRASTRUCTURE 0x01
  88. #define BSS_INDEPENDENT 0x02
  89. #define BSS_ANY 0x03

  90. /* Table 45: IEEE 802.11 Standard IE Translated to Marvell IE */
  91. /* PDF中的表45有一些拼写错误, MRVIIE应该改为MRVLIE */
  92. #define MRVLIETYPES_SSIDPARAMSET 0x0000
  93. #define MRVLIETYPES_RATESPARAMSET 0x0001
  94. #define MRVLIETYPES_DSPARAMSET 0x0003
  95. #define MRVLIETYPES_CFPARAMSET 0x0004
  96. #define MRVLIETYPES_IBSSPARAMSET 0x0006
  97. #define MRVLIETYPES_RSNPARAMSET 0x0030
  98. #define MRVLIETYPES_VENDORPARAMSET 0x00dd

  99. #define MRVLIETYPES_KEYPARAMSET 0x0100
  100. #define MRVLIETYPES_CHANLISTPARAMSET 0x0101
  101. #define MRVLIETYPES_TSFTIMESTAMP 0x0113
  102. #define MRVLIETYPES_AUTHTYPE 0x011f

  103. #define MRVLIE_PAYLOADLEN(s) (sizeof(s) - sizeof((s).header)) // 已知结构体大小sizeof(s), 求数据域的大小
  104. #define MRVLIE_STRUCTLEN(s) (sizeof((s).header) + (s).header.length) // 已知数据域大小, 求整个结构体的大小

  105. typedef __packed struct
  106. {
  107.         uint8_t type;
  108.         uint8_t length;
  109.         uint8_t data[1];
  110. } IEEEType;

  111. typedef __packed struct
  112. {
  113.         uint16_t ie_length; // Total information element length
  114.         uint8_t bssid[6]; // BSSID
  115.         uint8_t rssi; // RSSI value as received from peer
  116.         
  117.         /* Probe Response/Beacon Payload */
  118.         uint64_t pkt_time_stamp; // Timestamp
  119.         uint16_t bcn_interval; // Beacon interval
  120.         uint16_t cap_info; // Capabilities information
  121.         IEEEType ie_parameters; // 存放的是一些IEEE类型的数据
  122. } WiFi_BssDescSet;

  123. typedef __packed struct
  124. {
  125.         uint8_t oui[3];
  126.         uint8_t oui_type;
  127.         uint8_t oui_subtype;
  128.         uint8_t version;
  129. } WiFi_VendorHeader;

  130. typedef __packed struct
  131. {
  132.         uint16_t type;
  133.         uint16_t length;
  134. } MrvlIEHeader;

  135. typedef __packed struct
  136. {
  137.         MrvlIEHeader header;
  138.         uint16_t auth_type;
  139. } MrvlIETypes_AuthType_t;

  140. typedef uint16_t MrvlIETypes_CapInfo_t; // Section 7.3.1.4: IEEE 802.11-1999 Spec

  141. typedef __packed struct
  142. {
  143.         MrvlIEHeader header;
  144.         uint8_t count;
  145.         uint8_t period;
  146.         uint16_t max_duration;
  147.         uint16_t duration_remaining;
  148. } MrvlIETypes_CfParamSet_t;

  149. /*typedef __packed struct
  150. {
  151.         MrvlIEHeader header;
  152.         __packed struct
  153.         {
  154.                 uint8_t band_config_type;
  155.                 uint8_t chan_number;
  156.         } channels[1];
  157. } MrvlIETypes_ChanBandList_t;*/

  158. typedef __packed struct
  159. {
  160.         MrvlIEHeader header;
  161.         __packed struct
  162.         {
  163.                 uint8_t band_config_type;
  164.                 uint8_t chan_number;
  165.                 uint8_t scan_type;
  166.                 uint16_t min_scan_time;
  167.                 uint16_t max_scan_time;
  168.         } channels[1];
  169. } MrvlIETypes_ChanListParamSet_t;

  170. typedef __packed struct
  171. {
  172.         MrvlIEHeader header;
  173.         uint8_t channel;
  174. } MrvlIETypes_DsParamSet_t;

  175. typedef MrvlIETypes_DsParamSet_t MrvlIETypes_PhyParamDSSet_t;

  176. typedef __packed struct
  177. {
  178.         MrvlIEHeader header;
  179.         uint16_t atim_window;
  180. } MrvlIETypes_IbssParamSet_t;

  181. typedef __packed struct
  182. {
  183.         MrvlIEHeader header;
  184.         uint16_t key_type_id;
  185.         uint16_t key_info;
  186.         uint16_t key_len;
  187.         uint8_t key[32];
  188. } MrvlIETypes_KeyParamSet_t;

  189. typedef __packed struct
  190. {
  191.         MrvlIEHeader header;
  192.         uint8_t rates[14];
  193. } MrvlIETypes_RatesParamSet_t;

  194. typedef __packed struct
  195. {
  196.         MrvlIEHeader header;
  197.         uint8_t rsn[64];
  198. } MrvlIETypes_RsnParamSet_t;

  199. typedef __packed struct
  200. {
  201.         MrvlIEHeader header;
  202.         uint8_t ssid[32];
  203. } MrvlIETypes_SSIDParamSet_t;

  204. typedef __packed struct
  205. {
  206.         MrvlIEHeader header;
  207.         uint64_t tsf_table[1];
  208. } MrvlIETypes_TsfTimestamp_t;

  209. // 整个结构体的最大大小为256字节
  210. typedef __packed struct
  211. {
  212.         MrvlIEHeader header;
  213.         uint8_t vendor[64]; // 通常情况下64字节已足够
  214. } MrvlIETypes_VendorParamSet_t;

  215. typedef __packed struct
  216. {
  217.         uint16_t length;
  218.         uint16_t type;
  219. } WiFi_SDIOFrameHeader;

  220. typedef __packed struct
  221. {
  222.         WiFi_SDIOFrameHeader frame_header;
  223.         uint16_t cmd_code;
  224.         uint16_t size;
  225.         uint16_t seq_num;
  226.         uint16_t result;
  227. } WiFi_CommandHeader;

  228. /* Table 2: Fields in Receive Packet Descriptor */
  229. typedef __packed struct
  230. {
  231.         WiFi_SDIOFrameHeader header;
  232.         uint16_t reserved1;
  233.         uint8_t snr; // Signal to noise ratio for this packet (dB)
  234.         uint8_t reserved2;
  235.         uint16_t rx_packet_length; // Number of bytes in the payload
  236.         uint8_t nf; // Noise floor for this packet (dBm). Noise floor is always negative. The absolute value is passed.
  237.         uint8_t rx_rate; // Rate at which this packet is received
  238.         uint32_t rx_packet_offset; // Offset from the start of the packet to the beginning of the payload data packet
  239.         uint32_t reserved3;
  240.         uint8_t priority; // Specifies the user priority of received packet
  241.         uint8_t reserved4[3];
  242.         uint8_t payload[1]; // 数据链路层上的帧
  243. } WiFi_DataRx;

  244. /* Table 3: Fields in Transmit Packet Descriptor */
  245. typedef __packed struct
  246. {
  247.         WiFi_SDIOFrameHeader header;
  248.         uint32_t reserved1;
  249.         uint32_t tx_control; // See 3.2.1 Per-Packet Settings
  250.         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)
  251.         uint16_t tx_packet_length; // Number of bytes in the payload data frame
  252.         uint16_t tx_dest_addr_high; // Destination MAC address bytes 4 to 5
  253.         uint32_t tx_dest_addr_low; // Destination MAC address bytes 0 to 3
  254.         uint8_t priority; // Specifies the user priority of transmit packet
  255.         uint8_t flags;
  256.         uint8_t pkt_delay_2ms; // Amount of time the packet has been queued in the driver layer for WMM implementations
  257.         uint8_t reserved2;
  258.         uint8_t payload[1]; // 数据链路层上的帧
  259. } WiFi_DataTx;

  260. typedef __packed struct
  261. {
  262.         WiFi_CommandHeader header;
  263.         uint16_t action;
  264. } WiFi_Cmd_KeyMaterial;

  265. typedef __packed struct
  266. {
  267.         WiFi_CommandHeader header;
  268.         uint16_t action;
  269.         uint8_t mac_addr[6];
  270. } WiFi_Cmd_MACAddr;

  271. typedef __packed struct
  272. {
  273.         WiFi_CommandHeader header;
  274.         uint16_t action;
  275.         uint16_t reserved;
  276. } WiFi_Cmd_MACCtrl;

  277. typedef __packed struct
  278. {
  279.         WiFi_CommandHeader header;
  280.         uint8_t ssid[32];
  281.         uint8_t bss_type;
  282.         uint16_t bcn_period;
  283.         uint8_t reserved1;
  284.         MrvlIETypes_IbssParamSet_t ibss_param_set; // ATIM window length in TU
  285.         uint32_t reserved2;
  286.         MrvlIETypes_DsParamSet_t ds_param_set; // The channel for ad-hoc network
  287.         uint16_t reserved3[3];
  288.         MrvlIETypes_CapInfo_t cap_info; // Capability information
  289.         uint8_t data_rate[14];
  290. } WiFi_CmdRequest_ADHOCStart;

  291. typedef __packed struct
  292. {
  293.         WiFi_CommandHeader header;
  294.         uint8_t peer_sta_addr[6]; // Peer MAC address
  295.         MrvlIETypes_CapInfo_t cap_info; // Capability information
  296.         uint16_t listen_interval; // Listen interval
  297.         uint16_t bcn_period; // Beacon period
  298.         uint8_t dtim_period; // DTIM period
  299. } WiFi_CmdRequest_Associate;

  300. typedef __packed struct
  301. {
  302.         WiFi_CommandHeader header;
  303.         uint8_t bss_type;
  304.         uint8_t bss_id[6];
  305. } WiFi_CmdRequest_Scan;

  306. typedef __packed struct
  307. {
  308.         WiFi_CommandHeader header;
  309.         uint16_t capability;
  310.         uint16_t status_code;
  311.         uint16_t association_id;
  312.         IEEEType ie_buffer;
  313. } WiFi_CmdResponse_Associate;

  314. typedef __packed struct
  315. {
  316.         WiFi_CommandHeader header;
  317.         uint16_t buf_size;
  318.         uint8_t num_of_set;
  319. } WiFi_CmdResponse_Scan;

  320. typedef __packed struct
  321. {
  322.         MrvlIETypes_SSIDParamSet_t ssid;
  323.         uint8_t mac_addr[6];
  324.         MrvlIETypes_CapInfo_t cap_info;
  325.         uint16_t bcn_period;
  326.         uint8_t channel;
  327.         MrvlIETypes_RatesParamSet_t rates;
  328.         MrvlIETypes_RsnParamSet_t rsn;
  329.         MrvlIETypes_VendorParamSet_t wpa;
  330.         MrvlIETypes_VendorParamSet_t wwm;
  331.         MrvlIETypes_VendorParamSet_t wps;
  332. } WiFi_SSIDInfo;

  333. #define WiFi_DropPacket() WiFi_ReceivePacket(0, 0)
  334. #define WiFi_GetBlockSize() _BV((SDIO->DCTRL & SDIO_DCTRL_DBLOCKSIZE) >> 4)
  335. #define WiFi_GetMACAddr(addr) WiFi_MACAddr((addr), WIFI_ACT_GET)
  336. #define WiFi_PacketArrived() (WiFi_Read(1, WIFI_CARDSTATUS) & WIFI_CARDSTATUS_UPLDCARDRDY)
  337. #define WiFi_ResendCommand(cmd) WiFi_SendCommand(0, (cmd), 0)
  338. #define WiFi_SetMACAddr(addr) WiFi_MACAddr((uint8_t *)(addr), WIFI_ACT_SET)
  339. #define WiFi_ShowShortResponse() printf("Command response received: CMD%d, RESP_%08x\n", SDIO->RESPCMD, SDIO->RESP1)

  340. uint16_t WiFi_Associate(const char *ssid);
  341. void WiFi_CheckCmdTimeout(void);
  342. uint16_t WiFi_Connect(const char *ssid, const char *password);
  343. uint8_t WiFi_DownloadFirmware(void);
  344. uint16_t WiFi_GetPacketLength(void);
  345. void WiFi_Init(void);
  346. uint16_t WiFi_KeyMaterial(MrvlIETypes_KeyParamSet_t *keys, uint16_t size, uint8_t action);
  347. void WiFi_MACAddr(uint8_t addr[6], uint8_t action);
  348. void WiFi_MACControl(uint16_t action);
  349. uint16_t WiFi_PacketPending(void);
  350. void WiFi_PrepareTimer(uint16_t nms);
  351. uint8_t WiFi_Read(uint8_t func, uint32_t addr);
  352. void WiFi_ReadData(uint8_t func, uint32_t addr, uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags);
  353. uint16_t WiFi_ReadPort(void *buf, uint16_t size, uint16_t bufsize);
  354. uint16_t WiFi_ReceivePacket(void *buf, uint16_t bufsize);
  355. uint16_t WiFi_ReceiveResponse(void *buf, uint16_t bufsize);
  356. void WiFi_Scan(void);
  357. uint8_t WiFi_ScanSSID(const char *ssid, WiFi_SSIDInfo *info, uint8_t *buffer, uint16_t bufsize);
  358. void WiFi_SendCMD52(uint8_t func, uint32_t addr, uint8_t data, uint32_t flags);
  359. void WiFi_SendCMD53(uint8_t func, uint32_t addr, uint16_t count, uint32_t flags);
  360. void WiFi_SendCommand(uint16_t com_code, void *data, uint16_t size);
  361. uint8_t WiFi_SendPacket(WiFi_DataTx *packet, uint16_t packet_len);
  362. void WiFi_SetBlockSize(uint8_t func);
  363. uint8_t WiFi_SetKeyMaterial(uint16_t type, uint16_t info, const uint8_t *key, uint16_t len);
  364. void WiFi_ShowCIS(uint8_t func);
  365. void WiFi_ShowKeyMaterials(void);
  366. uint8_t WiFi_StartADHOC(const char *ssid);
  367. uint8_t WiFi_Wait(uint8_t status);
  368. uint8_t WiFi_Write(uint8_t func, uint32_t addr, uint8_t value);
  369. void WiFi_WriteData(uint8_t func, uint32_t addr, const uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags);
  370. uint8_t WiFi_WritePort(const void *data, uint16_t size);
复制代码
【WiFi.c】
  1. #include <stdio.h>
  2. #include <stm32f10x.h>
  3. #include <string.h>
  4. #include "WiFi.h"

  5. extern const unsigned char firmware_helper_sd[2516];
  6. extern const unsigned char firmware_sd8686[122916];

  7. //const uint8_t wifi_mac_addr[] = {0x62, 0x1d, 0x2f, 0x00, 0x4e, 0x2d}; // MAC地址的第一个字节必须为偶数! 否则为多播地址

  8. static uint16_t rca;
  9. static uint16_t wifi_timeout = WIFI_DEFAULTTIMEOUT;
  10. static uint32_t io_addr;
  11. static uint16_t wifi_pending_size = 0; // 未读的数据包大小

  12. void delay(uint16_t n);
  13. void dump_data(uint8_t *data, uint16_t len);

  14. /* 关联一个热点 */
  15. uint16_t WiFi_Associate(const char *ssid)
  16. {
  17.         uint8_t buffer[2048];
  18.         WiFi_SSIDInfo info;
  19.         WiFi_CmdRequest_Associate *cmd = (WiFi_CmdRequest_Associate *)buffer;
  20.         WiFi_CmdResponse_Associate *resp = (WiFi_CmdResponse_Associate *)buffer;
  21.         MrvlIETypes_DsParamSet_t *ds;
  22.         MrvlIETypes_CfParamSet_t *cf;
  23.         MrvlIETypes_AuthType_t *auth;
  24.         MrvlIETypes_RsnParamSet_t *rsn;

  25.         if (!WiFi_ScanSSID(ssid, &info, buffer, sizeof(buffer)))
  26.         {
  27.                 printf("Cannot find AP: %s!\n", ssid);
  28.                 return WIFI_ASSOCIATION_NOTFOUND;
  29.         }
  30.         
  31.         memcpy(cmd->peer_sta_addr, info.mac_addr, sizeof(info.mac_addr));
  32.         cmd->cap_info = info.cap_info;
  33.         cmd->listen_interval = 10;
  34.         cmd->bcn_period = info.bcn_period;
  35.         cmd->dtim_period = 0;
  36.         memcpy(cmd + 1, &info.ssid, MRVLIE_STRUCTLEN(info.ssid));
  37.         
  38.         ds = (MrvlIETypes_DsParamSet_t *)((uint8_t *)(cmd + 1) + MRVLIE_STRUCTLEN(info.ssid));
  39.         ds->header.type = MRVLIETYPES_DSPARAMSET;
  40.         ds->header.length = 1;
  41.         ds->channel = info.channel;
  42.         
  43.         cf = (MrvlIETypes_CfParamSet_t *)(ds + 1);
  44.         memset(cf, 0, sizeof(MrvlIETypes_CfParamSet_t));
  45.         cf->header.type = MRVLIETYPES_CFPARAMSET;
  46.         cf->header.length = MRVLIE_PAYLOADLEN(*cf);
  47.         
  48.         memcpy(cf + 1, &info.rates, MRVLIE_STRUCTLEN(info.rates));
  49.         auth = (MrvlIETypes_AuthType_t *)((uint8_t *)(cf + 1) + MRVLIE_STRUCTLEN(info.rates));
  50.         auth->header.type = MRVLIETYPES_AUTHTYPE;
  51.         auth->header.length = MRVLIE_PAYLOADLEN(*auth);
  52.         auth->auth_type = AUTH_MODE_OPEN;
  53.         
  54.         rsn = (MrvlIETypes_RsnParamSet_t *)(auth + 1);
  55.         if (info.rsn.header.type)
  56.         {
  57.                 // WPA2网络必须在命令中加入RSN参数才能成功连接
  58.                 memcpy(rsn, &info.rsn, MRVLIE_STRUCTLEN(info.rsn));
  59.                 WiFi_SendCommand(CMD_802_11_ASSOCIATE, buffer, (uint8_t *)rsn - buffer + MRVLIE_STRUCTLEN(info.rsn));
  60.         }
  61.         else
  62.                 WiFi_SendCommand(CMD_802_11_ASSOCIATE, buffer, (uint8_t *)rsn - buffer); // 其余网络不需要RSN参数
  63.         
  64.         if (!WiFi_ReceiveResponse(buffer, sizeof(buffer)))
  65.         {
  66.                 printf("Association with %s failed!\n", ssid);
  67.                 return WIFI_ASSOCIATION_ERROR;
  68.         }
  69.         
  70.         //printf("capability=0x%04x, status_code=0x%04x, aid=0x%04x\n", resp->capability, resp->status_code, resp->association_id);
  71.         if (resp->association_id == 0xffff)
  72.                 return ((-resp->capability) << 8) | resp->status_code;
  73.         return WIFI_ASSOCIATION_SUCCESS;
  74. }

  75. /* 检查命令是否收到了回应, 若没收到则重发命令 */
  76. void WiFi_CheckCmdTimeout(void)
  77. {
  78.         while (SDIO->STA & SDIO_STA_CTIMEOUT)
  79.         {
  80.                 SDIO->ICR = SDIO_ICR_CTIMEOUTC; // 清除标志
  81.                 SDIO->CMD = SDIO->CMD; // 重发
  82.                 printf("Timeout! Resend CMD%d\n", SDIO->CMD & SDIO_CMD_CMDINDEX);
  83.                 while (SDIO->STA & SDIO_STA_CMDACT);
  84.         }
  85. }

  86. /* 连接WiFi热点, 并输入密码 */
  87. uint16_t WiFi_Connect(const char *ssid, const char *password)
  88. {
  89.         uint16_t ret;
  90.         do
  91.         {
  92.                 ret = WiFi_Associate(ssid);
  93.                 if (ret != WIFI_ASSOCIATION_SUCCESS)
  94.                 {
  95.                         printf("WiFi_Associate returned 0x%04x\n", ret);
  96.                         delay(2000); // 等待一段时间后重连
  97.                 }
  98.         } while (WIFI_ASSOCIATION_TIMEOUT(ret) || ret == WIFI_ASSOCIATION_NOTFOUND); // 若连接超时, 或未扫描到热点, 则重连
  99.         
  100.         if (ret != WIFI_ASSOCIATION_SUCCESS)
  101.                 return ret;
  102.         
  103.         printf("Connected to %s!\n", ssid);
  104.         return ret;
  105. }

  106. /* 下载固件 */
  107. // 参考文档: marvell-88w8686-固件下载程序说明.doc
  108. uint8_t WiFi_DownloadFirmware(void)
  109. {
  110.         uint8_t helper_buf[64];
  111.         const uint8_t *data;
  112.         uint16_t size;
  113.         uint32_t len;
  114.         
  115.         // 块大小设为32
  116.         SDIO->DCTRL = (SDIO->DCTRL & ~SDIO_DCTRL_DBLOCKSIZE) | SDIO_DCTRL_DBLOCKSIZE_2 | SDIO_DCTRL_DBLOCKSIZE_0;
  117.         WiFi_SetBlockSize(1); // 应用到Function 1
  118.         
  119.         // 下载helper
  120.         io_addr = WiFi_Read(1, 0x00) | (WiFi_Read(1, 0x01) << 8) | (WiFi_Read(1, 0x02) << 16);
  121.         data = firmware_helper_sd;
  122.         len = sizeof(firmware_helper_sd);
  123.         while (len)
  124.         {
  125.                 // 每次下载64字节, 其中前4字节为本次下载的数据量
  126.                 size = (len > 60) ? 60 : len;
  127.                 *(uint32_t *)helper_buf = size;
  128.                 memcpy(helper_buf + 4, data, size);
  129.                
  130.                 WiFi_Wait(WIFI_CARDSTATUS_DNLDCARDRDY);
  131.                 WiFi_WritePort(helper_buf, sizeof(helper_buf));
  132.                 len -= size;
  133.                 data += size;
  134.         }
  135.         *(uint32_t *)helper_buf = 0;
  136.         WiFi_WritePort(helper_buf, sizeof(helper_buf)); // 以空数据包结束
  137.         
  138.         // 下载固件
  139.         data = firmware_sd8686;
  140.         len = sizeof(firmware_sd8686);
  141.         while (len)
  142.         {
  143.                 WiFi_Wait(WIFI_CARDSTATUS_DNLDCARDRDY);
  144.                 while ((size = WiFi_Read(1, WIFI_SQREADBASEADDR0) | (WiFi_Read(1, WIFI_SQREADBASEADDR1) << 8)) == 0); // 获取本次下载的字节数
  145.                 //printf("Required: %d bytes, Remaining: %d bytes\n", size, len);
  146.                
  147.                 if (size & 1)
  148.                 {
  149.                         // 若size为奇数(如17), 则说明接收端有CRC校验错误, 应重新传送上一次的内容(这部分代码省略)
  150.                         printf("Error: an odd size is invalid!\n");
  151.                         return 0;
  152.                 }
  153.                 if (size > len)
  154.                         size = len;
  155.                
  156.                 if (!WiFi_WritePort(data, size))
  157.                 {
  158.                         printf("Data transfer error! SDIO->STA=0x%08x\n", SDIO->STA);
  159.                         return 0;
  160.                 }
  161.                
  162.                 len -= size;
  163.                 data += size;
  164.         }
  165.         
  166.         // 等待Firmware启动
  167.         while (WiFi_GetPacketLength() == 0xfedc);
  168.         printf("Firmware is successfully downloaded!\n");
  169.         return 1;
  170. }

  171. /* 获取数据帧大小 */
  172. uint16_t WiFi_GetPacketLength(void)
  173. {
  174.         return WiFi_Read(1, 0x34) | (WiFi_Read(1, 0x35) << 8);
  175. }

  176. /* 初始化WiFi模块 */
  177. // SDIO Simplified Specification Version 3.00: 3. SDIO Card Initialization
  178. void WiFi_Init(void)
  179. {
  180.         printf("Initialization begins...\n");
  181.         SDIO->POWER = SDIO_POWER_PWRCTRL;
  182.         SDIO->CLKCR = SDIO_CLKCR_CLKEN | 178; // 初始化时最高允许的频率: 72MHz/(178+2)=400kHz
  183.         delay(5); // 延时可防止CMD5重发
  184.         
  185.         // 不需要发送CMD0, 因为SD I/O card的初始化命令是CMD52
  186.         // 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)
  187.         
  188.         /* 发送CMD5: IO_SEND_OP_COND */
  189.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 5;
  190.         while (SDIO->STA & SDIO_STA_CMDACT);
  191.         WiFi_CheckCmdTimeout(); // 为了保险起见还是要检查一下是否要重发命令
  192.         if (SDIO->STA & SDIO_STA_CMDREND)
  193.         {
  194.                 SDIO->ICR = SDIO_ICR_CMDRENDC;
  195.                 WiFi_ShowShortResponse();
  196.         }
  197.         
  198.         /* 设置参数VDD Voltage Window: 3.2~3.4V, 并再次发送CMD5 */
  199.         SDIO->ARG = 0x300000;
  200.         SDIO->CMD = SDIO->CMD;
  201.         while (SDIO->STA & SDIO_STA_CMDACT);
  202.         if (SDIO->STA & SDIO_STA_CMDREND)
  203.         {
  204.                 SDIO->ICR = SDIO_ICR_CMDRENDC;
  205.                 WiFi_ShowShortResponse();
  206.                 if (SDIO->RESP1 & _BV(31))
  207.                 {
  208.                         // Card is ready to operate after initialization
  209.                         printf("Number of I/O Functions: %d\n", (SDIO->RESP1 >> 28) & 7);
  210.                         printf("Memory Present: %d\n", (SDIO->RESP1 & _BV(27)) != 0);
  211.                 }
  212.         }
  213.         
  214.         /* 获取WiFi模块地址 (CMD3: SEND_RELATIVE_ADDR, Ask the card to publish a new relative address (RCA)) */
  215.         SDIO->ARG = 0;
  216.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 3;
  217.         while (SDIO->STA & SDIO_STA_CMDACT);
  218.         if (SDIO->STA & SDIO_STA_CMDREND)
  219.         {
  220.                 SDIO->ICR = SDIO_ICR_CMDRENDC;
  221.                 rca = SDIO->RESP1 >> 16;
  222.                 printf("Relative card address: 0x%04x\n", rca);
  223.         }
  224.         
  225.         /* 选中WiFi模块 (CMD7: SELECT/DESELECT_CARD) */
  226.         SDIO->ARG = rca << 16;
  227.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 7;
  228.         while (SDIO->STA & SDIO_STA_CMDACT);
  229.         if (SDIO->STA & SDIO_STA_CMDREND)
  230.         {
  231.                 SDIO->ICR = SDIO_ICR_CMDRENDC;
  232.                 printf("Card selected! status=0x%08x\n", SDIO->RESP1);
  233.         }
  234.         
  235.         // 提高时钟频率
  236.         SDIO->CLKCR = (SDIO->CLKCR & ~SDIO_CLKCR_CLKDIV) | 70; // 72MHz/(70+2)=1MHz
  237.         SDIO->DTIMER = 1000000; // 当频率为1MHz时, 超时时间为1秒
  238.         //SDIO->CLKCR = (SDIO->CLKCR & ~SDIO_CLKCR_CLKDIV) | 1; // 72MHz/(1+2)=24MHz
  239.         
  240.         /* 选择总线宽度 (Wide Bus Selection) */
  241.         // For an SDIO card a write to the CCCR using CMD52 is used to select bus width. (See 4.5 Bus Width)
  242.         // CMD52: IO_RW_DIRECT, CCCR: Card Common Control Registers
  243.         WiFi_Write(0, 0x07, WiFi_Read(0, 0x07) | 0x02); // Bus Width: 4-bit bus
  244.         SDIO->CLKCR |= SDIO_CLKCR_WIDBUS_0;
  245.         
  246.         // 初始化Function 1
  247.         WiFi_Write(0, 0x02, 0x02); // IOE1=1 (Enable Function)
  248.         while ((WiFi_Read(0, 3) & 0x02) == 0); // 等到IOR1=1 (I/O Function Ready)
  249.         
  250.         // 显示CIS信息
  251.         //WiFi_ShowCIS(0);
  252.         //WiFi_ShowCIS(1);
  253.         
  254.         // 下载固件
  255.         WiFi_DownloadFirmware();
  256.         
  257.         // 设置数据块大小为256字节
  258.         SDIO->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3;
  259.         WiFi_SetBlockSize(0);
  260.         WiFi_SetBlockSize(1);
  261.         
  262.         // 允许发送和接收
  263.         // 不使用带有LLC子层的802.2SNAP帧格式, 这样LLC和SNAP这8个字节的内容就不会夹在数据链路层的源地址字段与数据字段之间
  264.         WiFi_MACControl(WIFI_MACCTRL_ETHERNET2 | WIFI_MACCTRL_TX | WIFI_MACCTRL_RX);
  265. }

  266. /* 获取或设置密钥 */
  267. uint16_t WiFi_KeyMaterial(MrvlIETypes_KeyParamSet_t *keys, uint16_t size, uint8_t action)
  268. {
  269.         uint8_t buffer[256];
  270.         uint8_t ret_size;
  271.         WiFi_Cmd_KeyMaterial *cmd = (WiFi_Cmd_KeyMaterial *)buffer;
  272.         cmd->action = action;
  273.         if (action == WIFI_ACT_SET)
  274.         {
  275.                 memcpy(cmd + 1, keys, size);
  276.                 WiFi_SendCommand(CMD_802_11_KEY_MATERIAL, buffer, sizeof(WiFi_Cmd_KeyMaterial) + size);
  277.         }
  278.         else
  279.                 WiFi_SendCommand(CMD_802_11_KEY_MATERIAL, buffer, sizeof(WiFi_Cmd_KeyMaterial));
  280.         WiFi_ReceiveResponse(buffer, sizeof(buffer));
  281.         
  282.         if (action == WIFI_ACT_GET)
  283.         {
  284.                 ret_size = cmd->header.size - sizeof(cmd->header) - sizeof(cmd->action);
  285.                 if (ret_size <= size)
  286.                         memcpy(keys, cmd + 1, ret_size);
  287.                 else
  288.                         printf("WiFi_KeyMaterial: Buffer size is too small! %d bytes required!\n", ret_size);
  289.                 return ret_size; // action=get时返回读取的数据大小
  290.         }
  291.         else
  292.                 return cmd->header.result; // action=set时返回命令执行结果值
  293. }

  294. /* 获取或设置MAC地址 */
  295. void WiFi_MACAddr(uint8_t addr[6], uint8_t action)
  296. {
  297.         WiFi_Cmd_MACAddr cmd;
  298.         cmd.action = action;
  299.         if (action == WIFI_ACT_SET)
  300.                 memcpy(cmd.mac_addr, addr, 6);
  301.         
  302.         WiFi_SendCommand(CMD_802_11_MAC_ADDR, &cmd, sizeof(cmd));
  303.         WiFi_ReceiveResponse(&cmd, sizeof(cmd));
  304.         if (action == WIFI_ACT_GET)
  305.                 memcpy(addr, cmd.mac_addr, 6);
  306. }

  307. /* 配置MAC */
  308. void WiFi_MACControl(uint16_t action)
  309. {
  310.         WiFi_Cmd_MACCtrl cmd;
  311.         cmd.action = action;
  312.         cmd.reserved = 0;
  313.         WiFi_SendCommand(CMD_MAC_CONTROL, &cmd, sizeof(cmd));
  314.         WiFi_ReceiveResponse(&cmd, sizeof(cmd));
  315. }

  316. /* 获取滞留的数据包大小 */
  317. uint16_t WiFi_PacketPending(void)
  318. {
  319.         return wifi_pending_size;
  320. }

  321. /* 准备好超时计时器 */
  322. void WiFi_PrepareTimer(uint16_t nms)
  323. {
  324.         TIM6->ARR = 10 * nms - 1;
  325.         TIM6->PSC = 7199; // 72MHz/7200=10kHz
  326.         TIM6->EGR = TIM_EGR_UG; // 保存设置
  327.         TIM6->SR &= ~TIM_SR_UIF; // 清除溢出标志位
  328.         TIM6->CR1 = TIM_CR1_OPM | TIM_CR1_CEN; // 开始计时, 模式为非循环模式
  329. }

  330. /* 读寄存器 */
  331. uint8_t WiFi_Read(uint8_t func, uint32_t addr)
  332. {
  333.         WiFi_SendCMD52(func, addr, NULL, NULL);
  334.         if (SDIO->STA & SDIO_STA_CMDREND)
  335.         {
  336.                 SDIO->ICR = SDIO_ICR_CMDRENDC;
  337.                 return SDIO->RESP1 & 0xff;
  338.         }
  339.         else
  340.         {
  341.                 printf("WiFi_Read failed, SDIO->STA=0x%08x!\n", SDIO->STA);
  342.                 return 0;
  343.         }
  344. }

  345. /* 读数据 */
  346. // count为要发送的字节数或块数, bufsize为data缓冲区的大小
  347. // bufsize=0时, 只读取数据不存入缓冲区
  348. void WiFi_ReadData(uint8_t func, uint32_t addr, uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags)
  349. {
  350.         uint32_t len, temp;
  351.         if (flags & CMD53_BLOCKMODE)
  352.         {
  353.                 len = count * WiFi_GetBlockSize(); // count表示数据块数
  354.                 SDIO->DCTRL &= ~SDIO_DCTRL_DTMODE; // Block模式
  355.         }
  356.         else
  357.         {
  358.                 len = count; // count表示字节数
  359.                 if (len % 4 != 0)
  360.                 {
  361.                         len += 4 - len % 4; // WiFi模块要求写入的字节数必须为4的整数倍
  362.                         count = len;
  363.                 }
  364.                 SDIO->DCTRL |= SDIO_DCTRL_DTMODE; // Multibyte模式
  365.         }
  366.         SDIO->DLEN = len;
  367.         SDIO->DCTRL |= SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTEN; // 设置传输方向为从模块到主机
  368.         
  369.         WiFi_SendCMD53(func, addr, count, flags);
  370.         while (len)
  371.         {
  372.                 if (SDIO->STA & SDIO_STA_RXDAVL)
  373.                 {
  374.                         // 若有数据到来就读取数据
  375.                         len -= 4;
  376.                         if (bufsize >= 4)
  377.                         {
  378.                                 *(uint32_t *)data = SDIO->FIFO;
  379.                                 data += 4;
  380.                         }
  381.                         else
  382.                         {
  383.                                 temp = SDIO->FIFO;
  384.                                 if (bufsize > 0)
  385.                                 {
  386.                                         // 写入缓冲区最后1~3字节
  387.                                         memcpy(data, &temp, bufsize);
  388.                                         bufsize = 0;
  389.                                 }
  390.                         }
  391.                 }
  392.                
  393.                 if (SDIO->STA & SDIO_STA_DTIMEOUT)
  394.                 {
  395.                         printf("Data Timeout!\n");
  396.                         break;
  397.                 }
  398.                 else if (SDIO->STA & SDIO_STA_DCRCFAIL)
  399.                 {
  400.                         printf("Data CRC check failed! %d bytes are lost\n", len);
  401.                         break;
  402.                 }
  403.         }
  404.         
  405.         while (SDIO->STA & (SDIO_STA_CMDACT | SDIO_STA_RXACT));
  406.         SDIO->DCTRL &= ~SDIO_DCTRL_DTEN;
  407.         
  408.         SDIO->ICR = SDIO_STA_DATAEND | SDIO_ICR_CMDRENDC;
  409.         if (flags & CMD53_BLOCKMODE)
  410.                 SDIO->ICR = SDIO_ICR_DBCKENDC;
  411.         
  412.         // 通过判断SDIO->STA是否等于0可知传输是否成功
  413. }

  414. uint16_t WiFi_ReadPort(void *buf, uint16_t size, uint16_t bufsize)
  415. {
  416.         uint16_t block_num, block_size;
  417.         block_size = WiFi_GetBlockSize();
  418.         
  419.         // 读取数据
  420.         WiFi_Wait(0); // 发送CMD53前必须IOReady=1
  421.         if (size >= 512 || size % block_size == 0)
  422.         {
  423.                 // 采用Block模式传输
  424.                 block_num = size / block_size;
  425.                 if (size % block_size != 0)
  426.                         block_num++;
  427.                
  428.                 WiFi_ReadData(1, io_addr, buf, block_num, bufsize, CMD53_BLOCKMODE);
  429.         }
  430.         else
  431.                 WiFi_ReadData(1, io_addr, buf, size, bufsize, 0);
  432.         
  433.         return SDIO->STA == 0;
  434. }

  435. /* 接收数据帧 */
  436. uint16_t WiFi_ReceivePacket(void *buf, uint16_t bufsize)
  437. {
  438.         uint16_t size;
  439.         if (wifi_pending_size)
  440.         {
  441.                 size = wifi_pending_size; // 先读取滞留的数据包
  442.                 wifi_pending_size = 0;
  443.         }
  444.         else
  445.                 size = WiFi_GetPacketLength();
  446.         return WiFi_ReadPort(buf, size, bufsize);
  447. }

  448. /* 接收WiFi命令的回应 */
  449. uint16_t WiFi_ReceiveResponse(void *buf, uint16_t bufsize)
  450. {
  451.         uint8_t retry_cnt = 0; // 重试次数
  452.         uint8_t wait_status, resend;
  453.         uint16_t size;
  454.         WiFi_CommandHeader *cmd = (WiFi_CommandHeader *)buf;
  455.         WiFi_SDIOFrameHeader temp;
  456.         
  457.         // 等待数据准备好
  458.         do
  459.         {
  460.                 wait_status = WiFi_Wait(WIFI_CARDSTATUS_UPLDCARDRDY);
  461.                
  462.                 WiFi_ReadPort(&temp, sizeof(temp), sizeof(temp)); // 试着读取头部信息
  463.                 if (temp.type == WIFI_SDIOFRAME_DATA && temp.length > 0) // 若读取到一个数据帧的头部
  464.                 {
  465.                         // 若读到的是一个数据帧, 不是命令回应
  466.                         // 则直接丢掉该数据帧, 然后重发命令, 保证命令执行成功
  467.                         printf("A packet of %d byte(s) preempted the command!\n", temp.length);
  468.                         wifi_pending_size = temp.length;
  469.                         WiFi_DropPacket(); // 必须读取完整个数据包, 只读完头部不算
  470.                         resend = 1;
  471.                 }
  472.                 else if (wait_status == 0)
  473.                 {
  474.                         // 若WiFi_Wait返回0, 则说明超时 (状态位在规定的时间内未置位)
  475.                         resend = 1;
  476.                         retry_cnt++;
  477.                         if (retry_cnt >= 5)
  478.                         {
  479.                                 printf("No response!\n");
  480.                                 return 0;
  481.                         }
  482.                 }
  483.                 else
  484.                         resend = 0;
  485.                
  486.                 if (resend)
  487.                 {
  488.                         if (cmd->frame_header.type == WIFI_SDIOFRAME_COMMAND)
  489.                         {
  490.                                 // 若超时后还没收到数据, 则重发命令, 然后再次执行WiFi_Wait
  491.                                 printf("Resend WiFi command 0x%04x! size=%d\n", cmd->cmd_code, cmd->frame_header.length);
  492.                                 WiFi_ResendCommand(buf);
  493.                         }
  494.                         else
  495.                                 return 0; // 若buf中的内容不是命令, 则直接退出
  496.                 }
  497.         } while (resend);
  498.         
  499.         size = WiFi_GetPacketLength();
  500.         if (size > bufsize)
  501.                 printf("WiFi_ReceiveResponse: Buffer size is too small! %d bytes required!\n", size);
  502.         return WiFi_ReadPort(buf, size, bufsize);
  503. }

  504. /* 扫描全部热点 (仅显示) */
  505. void WiFi_Scan(void)
  506. {
  507.         // 必须把STM32启动文件*.s中的Stack_Size改大, 否则函数中无法创建大数组
  508.         // Stack_Size=0x00000c00
  509.         uint8_t buffer[2048]; // 用于接收返回的WiFi接入点信息, 需要较大的内存空间来存放
  510.         uint8_t i, j, n;
  511.         uint8_t ssid[33], channel, wpa;
  512.         uint16_t ie_size;
  513.         
  514.         WiFi_CmdRequest_Scan *cmd = (WiFi_CmdRequest_Scan *)buffer; // 用buffer空间来存放要发送的命令
  515.         MrvlIETypes_ChanListParamSet_t *chanlist = (MrvlIETypes_ChanListParamSet_t *)(buffer + sizeof(WiFi_CmdRequest_Scan));
  516.         
  517.         WiFi_CmdResponse_Scan *resp = (WiFi_CmdResponse_Scan *)buffer;
  518.         WiFi_BssDescSet *bss_desc_set;
  519.         WiFi_VendorHeader *vendor;
  520.         IEEEType *ie_params;
  521.         //MrvlIETypes_TsfTimestamp_t *tft_table;
  522.         
  523.         // 分4次扫描14个通道
  524.         for (i = 0; i < 4; i++)
  525.         {
  526.                 cmd->bss_type = BSS_ANY;
  527.                 memset(cmd->bss_id, 0, sizeof(cmd->bss_id));
  528.                
  529.                 // 通道的基本参数
  530.                 n = (i == 3) ? 2 : 4; // 本次要扫描的通道数
  531.                 chanlist->header.type = MRVLIETYPES_CHANLISTPARAMSET;
  532.                 chanlist->header.length = n * sizeof(chanlist->channels);
  533.                 for (j = 0; j < n; j++)
  534.                 {
  535.                         chanlist->channels[j].band_config_type = 0;
  536.                         chanlist->channels[j].chan_number = 4 * i + j + 1; // 通道号
  537.                         chanlist->channels[j].scan_type = 0;
  538.                         chanlist->channels[j].min_scan_time = 0;
  539.                         chanlist->channels[j].max_scan_time = 100;
  540.                 }
  541.                
  542.                 // 发送命令并接收数据
  543.                 WiFi_SendCommand(CMD_802_11_SCAN, buffer, sizeof(WiFi_CmdRequest_Scan) + sizeof(chanlist->header) + chanlist->header.length);
  544.                 WiFi_ReceiveResponse(buffer, sizeof(buffer)); // 接收的数据会将cmd和chanlist中的内容覆盖掉
  545.                
  546.                 // 显示热点信息, num_of_set为热点数
  547.                 if (resp->num_of_set > 0)
  548.                 {
  549.                         bss_desc_set = (WiFi_BssDescSet *)(buffer + sizeof(WiFi_CmdResponse_Scan));
  550.                         for (j = 0; j < resp->num_of_set; j++)
  551.                         {
  552.                                 wpa = 0;
  553.                                 ie_params = &bss_desc_set->ie_parameters;
  554.                                 ie_size = bss_desc_set->ie_length - (sizeof(WiFi_BssDescSet) - sizeof(bss_desc_set->ie_length) - sizeof(bss_desc_set->ie_parameters));
  555.                                 while (ie_size > 0)
  556.                                 {
  557.                                         switch (ie_params->type)
  558.                                         {
  559.                                         case MRVLIETYPES_SSIDPARAMSET:
  560.                                                 // SSID名称
  561.                                                 memcpy(ssid, ie_params->data, ie_params->length);
  562.                                                 ssid[ie_params->length] = '\0';
  563.                                                 break;
  564.                                         case MRVLIETYPES_DSPARAMSET:
  565.                                                 // 通道号
  566.                                                 channel = ie_params->data[0];
  567.                                                 break;
  568.                                         case MRVLIETYPES_RSNPARAMSET:
  569.                                                 wpa = 2;
  570.                                                 break;
  571.                                         case MRVLIETYPES_VENDORPARAMSET:
  572.                                                 if (wpa == 0)
  573.                                                 {
  574.                                                         vendor = (WiFi_VendorHeader *)ie_params->data;
  575.                                                         if (vendor->oui[0] == 0x00 && vendor->oui[1] == 0x50 && vendor->oui[2] == 0xf2 && vendor->oui_type == 0x01)
  576.                                                                 wpa = 1;
  577.                                                 }
  578.                                                 break;
  579.                                         }
  580.                                         ie_size -= ie_params->length + 2;
  581.                                         ie_params = (IEEEType *)((uint8_t *)ie_params + ie_params->length + 2);
  582.                                 }
  583.                                 if (ie_size != 0)
  584.                                         printf("ie_parameters error!\n");
  585.                                 
  586.                                 printf("SSID '%s', ", ssid); // 热点名称
  587.                                 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地址
  588.                                 printf("RSSI %d, Channel %d\n", bss_desc_set->rssi, channel); // 信号强度和通道号
  589.                                 //printf("  Timestamp %lld, Beacon interval %d\n", bss_desc_set->pkt_time_stamp, bss_desc_set->bcn_interval);
  590.                                 
  591.                                 printf("  Capability: 0x%04x", bss_desc_set->cap_info);
  592.                                 if (bss_desc_set->cap_info & WIFI_CAPABILITY_PRIVACY)
  593.                                 {
  594.                                         if (wpa == 1)
  595.                                                 printf("(WPA: ON, ");
  596.                                         else if (wpa == 2)
  597.                                                 printf("(WPA2: ON, ");
  598.                                         else
  599.                                                 printf("(WEP: ON, ");
  600.                                 }
  601.                                 else
  602.                                         printf("(WEP: OFF, ");
  603.                                 
  604.                                 if (bss_desc_set->cap_info & WIFI_CAPABILITY_IBSS)
  605.                                         printf("mode: Ad-Hoc)\n");
  606.                                 else
  607.                                         printf("mode: Infrastructure)\n");
  608.                                 
  609.                                 // 转向下一个热点信息
  610.                                 bss_desc_set = (WiFi_BssDescSet *)((uint8_t *)bss_desc_set + sizeof(bss_desc_set->ie_length) + bss_desc_set->ie_length);
  611.                         }
  612.                         
  613.                         // resp->buf_size就是bss_desc_set的总大小
  614.                         // 因此tft_table == buffer + sizeof(WiFi_CmdResponse_Scan) + resp->buf_size
  615.                         /*tft_table = (MrvlIETypes_TsfTimestamp_t *)bss_desc_set;
  616.                         if (tft_table->header.type == MRVLIETYPES_TSFTIMESTAMP && tft_table->header.length == resp->num_of_set * sizeof(uint64_t))
  617.                         {
  618.                                 printf("Timestamps: ");
  619.                                 for (j = 0; j < resp->num_of_set; j++)
  620.                                         printf("%lld ", tft_table->tsf_table[j]);
  621.                                 printf("\n");
  622.                         }*/
  623.                         
  624.                         // TSF timestamp table是整个数据的末尾, 后面没有Channel/band table
  625.                         //if (((uint8_t *)tft_table - buffer) + sizeof(tft_table->header) + resp->num_of_set * sizeof(uint64_t) == cmd->header.frame_header.length)
  626.                         //        printf("data end!\n");
  627.                 }
  628.         }
  629. }

  630. /* 扫描指定名称的热点 */
  631. // buffer用来存放返回的全部结果, 因此bufsize应该足够大
  632. // info用来存放从buffer中提取出来的一些常用信息
  633. uint8_t WiFi_ScanSSID(const char *ssid, WiFi_SSIDInfo *info, uint8_t *buffer, uint16_t bufsize)
  634. {
  635.         uint8_t i;
  636.         uint16_t ie_size;
  637.         WiFi_CmdRequest_Scan *cmd = (WiFi_CmdRequest_Scan *)buffer;
  638.         WiFi_CmdResponse_Scan *resp = (WiFi_CmdResponse_Scan *)buffer;
  639.         WiFi_BssDescSet *bss_desc_set = (WiFi_BssDescSet *)(resp + 1);
  640.         MrvlIETypes_ChanListParamSet_t *chan_list;
  641.         IEEEType *ie_params;
  642.         WiFi_VendorHeader *vendor;
  643.         
  644.         cmd->bss_type = BSS_ANY;
  645.         memset(cmd->bss_id, 0, sizeof(cmd->bss_id));
  646.         
  647.         // 添加ssid参数
  648.         info->ssid.header.type = MRVLIETYPES_SSIDPARAMSET;
  649.         info->ssid.header.length = strlen(ssid);
  650.         memcpy(info->ssid.ssid, ssid, info->ssid.header.length);
  651.         memcpy(cmd + 1, &info->ssid, MRVLIE_STRUCTLEN(info->ssid));
  652.         
  653.         chan_list = (MrvlIETypes_ChanListParamSet_t *)((uint8_t *)(cmd + 1) + MRVLIE_STRUCTLEN(info->ssid));
  654.         chan_list->header.type = MRVLIETYPES_CHANLISTPARAMSET;
  655.         chan_list->header.length = 14 * sizeof(chan_list->channels); // 一次性扫描14个通道
  656.         for (i = 0; i < 14; i++)
  657.         {
  658.                 chan_list->channels[i].band_config_type = 0;
  659.                 chan_list->channels[i].chan_number = i + 1;
  660.                 chan_list->channels[i].scan_type = 0;
  661.                 chan_list->channels[i].min_scan_time = 0;
  662.                 chan_list->channels[i].max_scan_time = 100;
  663.         }
  664.         
  665.         WiFi_SendCommand(CMD_802_11_SCAN, buffer, ((uint8_t *)chan_list - buffer) + MRVLIE_STRUCTLEN(*chan_list));
  666.         wifi_timeout = 3000; // 延长超时时间
  667.         WiFi_ReceiveResponse(buffer, bufsize);
  668.         wifi_timeout = WIFI_DEFAULTTIMEOUT;
  669.         
  670.         if (resp->num_of_set == 0)
  671.                 return 0; // 失败
  672.         
  673.         // bss_desc_set以扫描到的第一个信息项为准
  674.         memcpy(info->mac_addr, bss_desc_set->bssid, sizeof(info->mac_addr));
  675.         info->cap_info = bss_desc_set->cap_info;
  676.         info->bcn_period = bss_desc_set->bcn_interval;
  677.         
  678.         // 若type=0, 则表明没有该项的信息 (除SSID结构体外, 因为SSID的type=MRVLIETYPES_SSIDPARAMSET=0)
  679.         info->rates.header.type = 0;
  680.         info->rsn.header.type = 0;
  681.         info->wpa.header.type = 0;
  682.         info->wwm.header.type = 0;
  683.         info->wps.header.type = 0;
  684.         
  685.         ie_params = &bss_desc_set->ie_parameters;
  686.         ie_size = bss_desc_set->ie_length - (sizeof(WiFi_BssDescSet) - sizeof(bss_desc_set->ie_length) - sizeof(bss_desc_set->ie_parameters));
  687.         while (ie_size > 0)
  688.         {
  689.                 switch (ie_params->type)
  690.                 {
  691.                 case MRVLIETYPES_RATESPARAMSET:
  692.                         // 速率
  693.                         info->rates.header.type = MRVLIETYPES_RATESPARAMSET;
  694.                         info->rates.header.length = ie_params->length;
  695.                         if (info->rates.header.length > sizeof(info->rates.rates))
  696.                                 info->rates.header.length = sizeof(info->rates.rates);
  697.                         memcpy(info->rates.rates, ie_params->data, ie_params->length);
  698.                         break;
  699.                 case MRVLIETYPES_DSPARAMSET:
  700.                         // 通道号
  701.                         info->channel = ie_params->data[0];
  702.                         break;
  703.                 case MRVLIETYPES_RSNPARAMSET:
  704.                         // 通常只有一个RSN信息 (与WPA2相关)
  705.                         // printf("RSN len=%d\n", ie_params->length);
  706.                         info->rsn.header.type = MRVLIETYPES_RSNPARAMSET;
  707.                         info->rsn.header.length = ie_params->length;
  708.                         if (info->rsn.header.length > sizeof(info->rsn.rsn))
  709.                                 info->rsn.header.length = sizeof(info->rsn.rsn);
  710.                         memcpy(info->rsn.rsn, ie_params->data, info->rsn.header.length);
  711.                         break;
  712.                 case MRVLIETYPES_VENDORPARAMSET:
  713.                         // 通常会有多项VENDOR信息 (与WPA相关)
  714.                         vendor = (WiFi_VendorHeader *)ie_params->data;
  715.                         if (vendor->oui[0] == 0x00 && vendor->oui[1] == 0x50 && vendor->oui[2] == 0xf2)
  716.                         {
  717.                                 switch (vendor->oui_type)
  718.                                 {
  719.                                 case 0x01:
  720.                                         // wpa_oui
  721.                                         info->wpa.header.type = MRVLIETYPES_VENDORPARAMSET;
  722.                                         info->wpa.header.length = ie_params->length;
  723.                                         if (info->wpa.header.length > sizeof(info->wpa.vendor))
  724.                                                 info->wpa.header.length = sizeof(info->wpa.vendor);
  725.                                         memcpy(info->wpa.vendor, ie_params->data, info->wpa.header.length);
  726.                                         break;
  727.                                 case 0x02:
  728.                                         // wmm_oui
  729.                                         if (ie_params->length == 24) // 合法大小
  730.                                         {
  731.                                                 info->wwm.header.type = MRVLIETYPES_VENDORPARAMSET;
  732.                                                 info->wwm.header.length = ie_params->length;
  733.                                                 memcpy(info->wwm.vendor, ie_params->data, ie_params->length);
  734.                                         }
  735.                                         break;
  736.                                 case 0x04:
  737.                                         // wps_oui
  738.                                         info->wps.header.type = MRVLIETYPES_VENDORPARAMSET;
  739.                                         info->wps.header.length = ie_params->length;
  740.                                         if (info->wps.header.length > sizeof(info->wps.vendor))
  741.                                                 info->wps.header.length = sizeof(info->wps.vendor);
  742.                                         memcpy(info->wps.vendor, ie_params->data, info->wps.header.length);
  743.                                         break;
  744.                                 }
  745.                         }
  746.                         break;
  747.                 }
  748.                 ie_size -= ie_params->length + 2;
  749.                 ie_params = (IEEEType *)((uint8_t *)ie_params + ie_params->length + 2);
  750.         }
  751.         
  752.         return 1; // 成功
  753. }

  754. void WiFi_SendCMD52(uint8_t func, uint32_t addr, uint8_t data, uint32_t flags)
  755. {
  756.         SDIO->ARG = (func << 28) | (addr << 9) | data | flags;
  757.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 52;
  758.         while (SDIO->STA & SDIO_STA_CMDACT);
  759. }

  760. void WiFi_SendCMD53(uint8_t func, uint32_t addr, uint16_t count, uint32_t flags)
  761. {
  762.         // 当count=512时, 和0x1ff相与后为0, 符合要求
  763.         SDIO->ARG = (func << 28) | (addr << 9) | (count & 0x1ff) | flags;
  764.         SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 53;
  765. }

  766. /* 发送WiFi命令 */
  767. void WiFi_SendCommand(uint16_t com_code, void *data, uint16_t size)
  768. {
  769.         static uint16_t seq_num = 0;
  770.         WiFi_CommandHeader *cmdhdr = (WiFi_CommandHeader *)data;
  771.         
  772.         if (size != 0)
  773.         {
  774.                 cmdhdr->frame_header.length = size;
  775.                 cmdhdr->frame_header.type = WIFI_SDIOFRAME_COMMAND;
  776.                 cmdhdr->cmd_code = com_code;
  777.                 cmdhdr->size = size - sizeof(WiFi_SDIOFrameHeader); // 命令大小包括命令头部, 但不包括SDIO帧头部
  778.                 cmdhdr->seq_num = seq_num++;
  779.                 cmdhdr->result = 0;
  780.         }
  781.         else
  782.                 size = cmdhdr->frame_header.length; // 重发命令时不填写cmdhdr
  783.         
  784.         // 发送命令前若恰好有数据帧到来, 则直接丢弃
  785.         if (WiFi_PacketPending() || WiFi_PacketArrived())
  786.         {
  787.                 printf("A new packet happends to arrive when sending command! Drop it!\n");
  788.                 WiFi_DropPacket();
  789.         }
  790.         
  791.         WiFi_WritePort(data, size);
  792. }

  793. /* 发送数据帧 */
  794. uint8_t WiFi_SendPacket(WiFi_DataTx *packet, uint16_t packet_len)
  795. {
  796.         uint8_t ret;
  797.         
  798.         // 有关发送数据包的细节, 请参考Firmware Specification PDF的Chapter 3: Data Path
  799.         packet->header.length = sizeof(WiFi_DataTx) - sizeof(packet->payload) + packet_len;
  800.         packet->header.type = WIFI_SDIOFRAME_DATA;
  801.         
  802.         packet->reserved1 = 0;
  803.         packet->tx_control = 0; // 控制信息的格式请参考3.2.1 Per-Packet Settings
  804.         packet->tx_packet_offset = sizeof(WiFi_DataTx) - sizeof(packet->payload) - sizeof(packet->header); // 不包括SDIOFrameHeader
  805.         packet->tx_packet_length = packet_len;
  806.         memcpy((void *)&packet->tx_dest_addr_high, packet->payload, 6);
  807.         packet->priority = 0;
  808.         packet->flags = 0;
  809.         packet->pkt_delay_2ms = 0;
  810.         packet->reserved2 = 0;
  811.         
  812.         // 若现在有新收到的数据帧, 则暂存数据包大小
  813.         // 未读取之前不会收到新的数据帧
  814.         if (WiFi_PacketArrived())
  815.                 wifi_pending_size = WiFi_GetPacketLength();
  816.         
  817.         ret = WiFi_WritePort(packet, packet->header.length);
  818.         WiFi_Wait(WIFI_CARDSTATUS_DNLDCARDRDY); // WiFi模块收到数据后, 会将该位置1
  819.         return ret;
  820. }

  821. /* 将SDIO->DCTRL中的块大小信息应用到WiFi模块指定的功能区上 */
  822. void WiFi_SetBlockSize(uint8_t func)
  823. {
  824.         // Part E1: 6.9 Card Common Control Registers (CCCR), 6.10 Function Basic Registers (FBR)
  825.         uint16_t size = WiFi_GetBlockSize();
  826.         WiFi_Write(0, (func << 8) | 0x10, size & 0xff);
  827.         WiFi_Write(0, (func << 8) | 0x11, size >> 8);
  828. }

  829. /* 设置密钥 */
  830. uint8_t WiFi_SetKeyMaterial(uint16_t type, uint16_t info, const uint8_t *key, uint16_t len)
  831. {
  832.         MrvlIETypes_KeyParamSet_t key_param;
  833.         if (len > sizeof(key_param.key))
  834.                 return CMD_STATUS_ERROR;
  835.         key_param.header.type = MRVLIETYPES_KEYPARAMSET;
  836.         key_param.header.length = (key_param.key - (uint8_t *)&key_param) - sizeof(key_param.header) + len;
  837.         key_param.key_type_id = type;
  838.         key_param.key_info = info;
  839.         key_param.key_len = len; // 当len=0时可保留key的值, 只更新key_info
  840.         if (len)
  841.                 memcpy(key_param.key, key, len);
  842.         return WiFi_KeyMaterial(&key_param, MRVLIE_STRUCTLEN(key_param), WIFI_ACT_SET);
  843. }

  844. /* 显示WiFi模块信息 */
  845. void WiFi_ShowCIS(uint8_t func)
  846. {
  847.         uint8_t data[255];
  848.         uint8_t i, len;
  849.         uint8_t tpl_code, tpl_link; // 16.2 Basic Tuple Format and Tuple Chain Structure
  850.         uint32_t cis_ptr;
  851.         
  852.         // 获取CIS的地址
  853.         cis_ptr = (func << 8) | 0x9;
  854.         cis_ptr        = WiFi_Read(0, cis_ptr) | (WiFi_Read(0, cis_ptr + 1) << 8) | (WiFi_Read(0, cis_ptr + 2) << 16);
  855.         printf("Pointer to Function %d Card Information Structure (CIS): 0x%08x\n", func, cis_ptr);
  856.         
  857.         // 遍历CIS, 直到尾节点
  858.         while ((tpl_code = WiFi_Read(0, cis_ptr++)) != CISTPL_END)
  859.         {
  860.                 if (tpl_code == CISTPL_NULL)
  861.                         continue;
  862.                
  863.                 tpl_link = WiFi_Read(0, cis_ptr++); // 本结点数据的大小
  864.                 for (i = 0; i < tpl_link; i++)
  865.                         data[i] = WiFi_Read(0, cis_ptr + i);
  866.                
  867.                 printf("[CIS Tuple 0x%02x] addr=0x%08x size=%d\n", tpl_code, cis_ptr - 2, tpl_link);
  868.                 dump_data(data, tpl_link);
  869.                 switch (tpl_code)
  870.                 {
  871.                 case CISTPL_VERS_1:
  872.                         i = 2;
  873.                         while (data[i] != 0xff)
  874.                         {
  875.                                 len = strlen((char *)&data[i]);
  876.                                 if (len != 0)
  877.                                         printf("%s\n", data + i);
  878.                                 i += len + 1;
  879.                         }
  880.                         break;
  881.                 case CISTPL_MANFID:
  882.                         // 16.6 CISTPL_MANFID: Manufacturer Identification String Tuple
  883.                         printf("SDIO Card manufacturer code: 0x%04x\n", *(uint16_t *)data); // TPLMID_MANF
  884.                         printf("manufacturer information (Part Number and/or Revision): 0x%04x\n", *(uint16_t *)(data + 2)); // TPLMID_CARD
  885.                         break;
  886.                 case CISTPL_FUNCID:
  887.                         // 16.7.1 CISTPL_FUNCID: Function Identification Tuple
  888.                         printf("Card function code: 0x%02x\n", data[0]); // TPLFID_FUNCTION
  889.                         printf("System initialization bit mask: 0x%02x\n", data[1]); // TPLFID_SYSINIT
  890.                         break;
  891.                 case CISTPL_FUNCE:
  892.                         // 16.7.2 CISTPL_FUNCE: Function Extension Tuple
  893.                         if (data[0] == 0)
  894.                         {
  895.                                 // 16.7.3 CISTPL_FUNCE Tuple for Function 0 (Extended Data 00h)
  896.                                 printf("maximum block size: %d\n", *(uint16_t *)(data + 1));
  897.                                 printf("maximum transfer rate code: 0x%02x\n", data[3]);
  898.                         }
  899.                         else
  900.                         {
  901.                                 // 16.7.4 CISTPL_FUNCE Tuple for Function 1-7 (Extended Data 01h)
  902.                                 printf("maximum block size: %d\n", *(uint16_t *)(data + 0x0c)); // TPLFE_MAX_BLK_SIZE
  903.                         }
  904.                 }
  905.                
  906.                 cis_ptr += tpl_link;
  907.                 if (tpl_link == 0xff)
  908.                         break; // 当TPL_LINK为0xff时说明当前结点为尾节点
  909.         }
  910. }

  911. /* 显示所有密钥 */
  912. void WiFi_ShowKeyMaterials(void)
  913. {
  914.         uint8_t buffer[256];
  915.         uint16_t size;
  916.         MrvlIETypes_KeyParamSet_t *key = (MrvlIETypes_KeyParamSet_t *)buffer;
  917.         
  918.         size = WiFi_KeyMaterial(key, sizeof(buffer), WIFI_ACT_GET);
  919.         while (size)
  920.         {
  921.                 printf("Type %d, Info 0x%04x, Len %d\n", key->key_type_id, key->key_info, key->key_len);
  922.                 dump_data(key->key, key->key_len);
  923.                 size -= MRVLIE_STRUCTLEN(*key);
  924.                 key = (MrvlIETypes_KeyParamSet_t *)((uint8_t *)key + MRVLIE_STRUCTLEN(*key));
  925.         }
  926.         if (size == 0)
  927.                 printf("data end!\n");
  928. }

  929. /* 创建一个Ad-Hoc型的WiFi热点 */
  930. uint8_t WiFi_StartADHOC(const char *ssid)
  931. {
  932.         WiFi_CmdRequest_ADHOCStart cmd;
  933.         memset(&cmd, 0, sizeof(cmd)); // 由于命令中含有Reserved区域, 所以必须先清零
  934.         
  935.         strncpy((char *)cmd.ssid, ssid, sizeof(cmd.ssid));
  936.         cmd.bss_type = BSS_INDEPENDENT;
  937.         cmd.bcn_period = 100;
  938.         cmd.ibss_param_set.header.type = MRVLIETYPES_IBSSPARAMSET;
  939.         cmd.ibss_param_set.header.length = MRVLIE_PAYLOADLEN(cmd.ibss_param_set);
  940.         cmd.ibss_param_set.atim_window = 0;
  941.         cmd.ds_param_set.header.type = MRVLIETYPES_DSPARAMSET;
  942.         cmd.ds_param_set.header.length = MRVLIE_PAYLOADLEN(cmd.ds_param_set);
  943.         cmd.ds_param_set.channel = 1;
  944.         cmd.cap_info = WIFI_CAPABILITY_IBSS/* | WIFI_CAPABILITY_PRIVACY*/;
  945.         *(uint32_t *)cmd.data_rate = 0x968b8482;
  946.         
  947.         WiFi_SendCommand(CMD_802_11_AD_HOC_START, &cmd, sizeof(cmd));
  948.         WiFi_ReceiveResponse(&cmd, sizeof(cmd));
  949.         return cmd.header.result;
  950. }

  951. /* 在规定的超时时间内, 等待指定的卡状态位置位(自动包括IO Ready位), 若成功则返回1 */
  952. uint8_t WiFi_Wait(uint8_t status)
  953. {
  954.         status |= WIFI_CARDSTATUS_IOREADY;
  955.         WiFi_PrepareTimer(wifi_timeout);
  956.         while ((WiFi_Read(1, WIFI_CARDSTATUS) & status) != status)
  957.         {
  958.                 if (TIM6->SR & TIM_SR_UIF)
  959.                 {
  960.                         // 若超时时间已到
  961.                         TIM6->SR &= ~TIM_SR_UIF;
  962.                         printf("WiFi_Wait(0x%02x): timeout!\n", status);
  963.                         return 0;
  964.                 }
  965.         }
  966.         TIM6->CR1 &=~ TIM_CR1_CEN; // 关闭定时器
  967.         return 1;
  968. }

  969. /* 写寄存器, 返回写入后寄存器的实际内容 */
  970. uint8_t WiFi_Write(uint8_t func, uint32_t addr, uint8_t value)
  971. {
  972.         WiFi_SendCMD52(func, addr, value, CMD52_WRITE | CMD52_READAFTERWRITE);
  973.         if (SDIO->STA & SDIO_STA_CMDREND)
  974.         {
  975.                 SDIO->ICR = SDIO_ICR_CMDRENDC;
  976.                 return SDIO->RESP1 & 0xff;
  977.         }
  978.         else
  979.         {
  980.                 printf("WiFi_Write failed, SDIO->STA=0x%08x!\n", SDIO->STA);
  981.                 return 0;
  982.         }
  983. }

  984. /* 写数据 */
  985. // count为要发送的字节数或块数, bufsize为data缓冲区的大小
  986. void WiFi_WriteData(uint8_t func, uint32_t addr, const uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags)
  987. {
  988.         uint32_t len, temp;
  989.         if (flags & CMD53_BLOCKMODE)
  990.         {
  991.                 len = count * WiFi_GetBlockSize();
  992.                 SDIO->DCTRL &= ~SDIO_DCTRL_DTMODE;
  993.         }
  994.         else
  995.         {
  996.                 len = count;
  997.                 if (len % 4 != 0)
  998.                 {
  999.                         len += 4 - len % 4; // WiFi模块要求写入的字节数必须为4的整数倍
  1000.                         count = len;
  1001.                 }
  1002.                 SDIO->DCTRL |= SDIO_DCTRL_DTMODE;
  1003.         }
  1004.         SDIO->DLEN = len;
  1005.         SDIO->DCTRL &= ~SDIO_DCTRL_DTDIR; // 设置传输方向: 从主机到模块
  1006.         
  1007.         WiFi_SendCMD53(func, addr, count, flags | CMD53_WRITE);
  1008.         while (SDIO->STA & SDIO_STA_CMDACT);
  1009.         if ((SDIO->STA & SDIO_STA_CMDREND) == 0)
  1010.         {
  1011.                 printf("WiFi_WriteData: CMD53 no response!\n");
  1012.                 return;
  1013.         }
  1014.         SDIO->ICR = SDIO_ICR_CMDRENDC;
  1015.         
  1016.         SDIO->DCTRL |= SDIO_DCTRL_DTEN; // 开始发送数据
  1017.         while (len)
  1018.         {
  1019.                 len -= 4;
  1020.                 if (bufsize >= 4)
  1021.                 {
  1022.                         SDIO->FIFO = *(uint32_t *)data;
  1023.                         data += 4;
  1024.                         bufsize -= 4;
  1025.                 }
  1026.                 else if (bufsize > 0)
  1027.                 {
  1028.                         // 发送缓冲区最后1~3字节
  1029.                         temp = 0; // 不足的位用0填充
  1030.                         memcpy(&temp, data, bufsize);
  1031.                         SDIO->FIFO = temp;
  1032.                         bufsize = 0;
  1033.                 }
  1034.                 else
  1035.                         SDIO->FIFO = 0; // 缓冲区已用完, 因此发送0
  1036.                 while (SDIO->STA & SDIO_STA_TXFIFOF); // 如果FIFO已满则等待
  1037.         }
  1038.         
  1039.         while (SDIO->STA & SDIO_STA_TXACT); // 等待发送完毕
  1040.         SDIO->DCTRL &= ~SDIO_DCTRL_DTEN; // 数据传输完毕后DTEN应及时清零, 防止后续对DCTRL寄存器操作后误启动数据传输导致超时或CRC校验错误
  1041.         
  1042.         // 清除相关标志位
  1043.         SDIO->ICR = SDIO_ICR_DATAENDC;
  1044.         if (flags & CMD53_BLOCKMODE)
  1045.                 SDIO->ICR = SDIO_ICR_DBCKENDC;
  1046. }

  1047. uint8_t WiFi_WritePort(const void *data, uint16_t size)
  1048. {
  1049.         uint16_t block_num, block_size;
  1050.         block_size = WiFi_GetBlockSize();
  1051.         
  1052.         WiFi_Wait(0); // 发送CMD53前必须IOReady=1
  1053.         if (size >= 512 || size % block_size == 0)
  1054.         {
  1055.                 // 采用Block模式传输
  1056.                 block_num = size / block_size;
  1057.                 if (size % block_size != 0)
  1058.                         block_num++;
  1059.                
  1060.                 WiFi_WriteData(1, io_addr, data, block_num, size, CMD53_BLOCKMODE);
  1061.         }
  1062.         else
  1063.                 WiFi_WriteData(1, io_addr, data, size, size, 0);
  1064.         return SDIO->STA == 0;
  1065. }
复制代码


在工程的所在文件夹创建一个lwip文件夹。
然后在lwip的官方网站下载lwip-2.0.2.zip,打开压缩包中的lwip-2.0.2/src文件夹,解压以下文件夹到工程的lwip目录下。

core/
core/ipv4
include/lwip
include/netif
netif/ethernet.c
netif/ethernetif.c

解压后,将里面的c文件都添加到工程的lwip分组下。
具体添加的文件请看下图:


接下来,创建lwip/include/arch/cc.h文件,内容如下:
  1.     #define PACK_STRUCT_BEGIN __packed // struct前的__packed  
复制代码
创建lwip/include/lwipopts.h文件,内容如下:
  1.     #define NO_SYS 1 // 无操作系统  
  2.       
  3.     #define LWIP_NETCONN 0  
  4.     #define LWIP_SOCKET 0  
  5.     #define LWIP_STATS 0  
  6.       
  7.     #define MEM_ALIGNMENT 4 // STM32单片机是32位的单片机, 因此是4字节对齐的  
  8.       
  9.     #define SYS_LIGHTWEIGHT_PROT 0 // 不进行临界区保护 (在中断中调用lwip函数时要小心)  
复制代码
打开lwip/netif/ethernetif.c文件,按照下面的中文提示修改代码:
  1. /**
  2. * @file
  3. * Ethernet Interface Skeleton
  4. *
  5. */

  6. /*
  7. * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
  8. * All rights reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without modification,
  11. * are permitted provided that the following conditions are met:
  12. *
  13. * 1. Redistributions of source code must retain the above copyright notice,
  14. *    this list of conditions and the following disclaimer.
  15. * 2. Redistributions in binary form must reproduce the above copyright notice,
  16. *    this list of conditions and the following disclaimer in the documentation
  17. *    and/or other materials provided with the distribution.
  18. * 3. The name of the author may not be used to endorse or promote products
  19. *    derived from this software without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  22. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  23. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
  24. * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  26. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  27. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  29. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  30. * OF SUCH DAMAGE.
  31. *
  32. * This file is part of the lwIP TCP/IP stack.
  33. *
  34. * Author: Adam Dunkels <adam@sics.se>
  35. *
  36. */

  37. /*
  38. * This file is a skeleton for developing Ethernet network interface
  39. * drivers for lwIP. Add code to the low_level functions and do a
  40. * search-and-replace for the word "ethernetif" to replace it with
  41. * something that better describes your network interface.
  42. */

  43. #include "lwip/opt.h"

  44. #if 1 // 允许编译器编译该文件

  45. #include "lwip/def.h"
  46. #include "lwip/mem.h"
  47. #include "lwip/pbuf.h"
  48. #include "lwip/stats.h"
  49. #include "lwip/snmp.h"
  50. #include "lwip/ethip6.h"
  51. #include "lwip/etharp.h"
  52. #include "netif/ppp/pppoe.h"

  53. /* Define those to better describe your network interface. */
  54. #define IFNAME0 'e'
  55. #define IFNAME1 'n'

  56. #include <string.h> // memcpy函数所在的头文件
  57. #include "WiFi.h" // WiFi模块驱动程序头文件

  58. void dump_data(uint8_t *data, uint16_t len);

  59. /**
  60. * Helper struct to hold private data used to operate your ethernet interface.
  61. * Keeping the ethernet address of the MAC in this struct is not necessary
  62. * as it is already kept in the struct netif.
  63. * But this is only an example, anyway...
  64. */
  65. struct ethernetif {
  66.   struct eth_addr *ethaddr;
  67.   /* Add whatever per-interface state that is needed here. */
  68. };

  69. /* Forward declarations. */
  70. // 这里必须去掉static
  71. /*static */void  ethernetif_input(struct netif *netif);

  72. /**
  73. * In this function, the hardware should be initialized.
  74. * Called from ethernetif_init().
  75. *
  76. * @param netif the already initialized lwip network interface structure
  77. *        for this ethernetif
  78. */
  79. static void
  80. low_level_init(struct netif *netif)
  81. {
  82.   struct ethernetif *ethernetif = netif->state;

  83.   /* set MAC hardware address length */
  84.   netif->hwaddr_len = ETHARP_HWADDR_LEN;

  85.   /* set MAC hardware address */
  86.   WiFi_GetMACAddr(netif->hwaddr); // 获取网卡的默认MAC地址
  87.   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]);

  88.   /* maximum transfer unit */
  89.   netif->mtu = 1500;

  90.   /* device capabilities */
  91.   /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
  92.   netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;

  93. #if LWIP_IPV6 && LWIP_IPV6_MLD
  94.   /*
  95.    * For hardware/netifs that implement MAC filtering.
  96.    * All-nodes link-local is handled by default, so we must let the hardware know
  97.    * to allow multicast packets in.
  98.    * Should set mld_mac_filter previously. */
  99.   if (netif->mld_mac_filter != NULL) {
  100.     ip6_addr_t ip6_allnodes_ll;
  101.     ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
  102.     netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER);
  103.   }
  104. #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */

  105.   /* Do whatever else is needed to initialize interface. */
  106. }

  107. /**
  108. * This function should do the actual transmission of the packet. The packet is
  109. * contained in the pbuf that is passed to the function. This pbuf
  110. * might be chained.
  111. *
  112. * @param netif the lwip network interface structure for this ethernetif
  113. * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
  114. * @return ERR_OK if the packet could be sent
  115. *         an err_t value if the packet couldn't be sent
  116. *
  117. * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
  118. *       strange results. You might consider waiting for space in the DMA queue
  119. *       to become available since the stack doesn't retry to send a packet
  120. *       dropped because of memory failure (except for the TCP timers).
  121. */

  122. static err_t
  123. low_level_output(struct netif *netif, struct pbuf *p)
  124. {
  125.   struct ethernetif *ethernetif = netif->state;
  126.   struct pbuf *q;
  127.         
  128.   // 添加的变量
  129.   uint8_t buffer[1792];
  130.   WiFi_DataTx *packet = (WiFi_DataTx *)buffer;
  131.   uint8_t *bufptr = packet->payload;

  132.   //initiate transfer();

  133. #if ETH_PAD_SIZE
  134.   pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
  135. #endif

  136.   for (q = p; q != NULL; q = q->next) {
  137.     /* Send the data from the pbuf to the interface, one pbuf at a
  138.        time. The size of the data in each pbuf is kept in the ->len
  139.        variable. */
  140.     //send data from(q->payload, q->len);
  141.         memcpy(bufptr, q->payload, q->len); // 复制数据包内容
  142.         bufptr += q->len; // 指针前移
  143.   }

  144.   //signal that packet should be sent();
  145.   WiFi_SendPacket(packet, bufptr - packet->payload); // 发送数据包
  146.   
  147.   // 打印数据包内容
  148.   printf("[Send] size=%d\n", packet->tx_packet_length);
  149.   dump_data(packet->payload, packet->tx_packet_length);

  150.   MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
  151.   if (((u8_t*)p->payload)[0] & 1) {
  152.     /* broadcast or multicast packet*/
  153.     MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
  154.   } else {
  155.     /* unicast packet */
  156.     MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
  157.   }
  158.   /* increase ifoutdiscards or ifouterrors on error */

  159. #if ETH_PAD_SIZE
  160.   pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
  161. #endif

  162.   LINK_STATS_INC(link.xmit);

  163.   return ERR_OK;
  164. }

  165. /**
  166. * Should allocate a pbuf and transfer the bytes of the incoming
  167. * packet from the interface into the pbuf.
  168. *
  169. * @param netif the lwip network interface structure for this ethernetif
  170. * @return a pbuf filled with the received packet (including MAC header)
  171. *         NULL on memory error
  172. */
  173. static struct pbuf *
  174. low_level_input(struct netif *netif)
  175. {
  176.   struct ethernetif *ethernetif = netif->state;
  177.   struct pbuf *p, *q;
  178.   u16_t len;
  179.         
  180.   // 添加的变量
  181.   uint8_t buffer[1792]; // 由于WiFi模块本身不支持使用多个CMD53命令读取数据包, 所以必须建立一个缓冲区, 一次性读取完
  182.   WiFi_DataRx *packet = (WiFi_DataRx *)buffer;
  183.   uint8_t *bufptr = packet->payload;

  184.   /* Obtain the size of the packet and put it into the "len"
  185.      variable. */
  186.   len = WiFi_ReceivePacket(buffer, sizeof(buffer)); // 读取整个数据包, 返回值包含头部大小
  187.   if (len == 0)
  188.   {
  189.           // 若读取失败, 则不分配pbuf, 退出本函数
  190.           p = NULL;
  191.           goto after_alloc;
  192.   }
  193.   len = packet->rx_packet_length; // 获取数据包的大小
  194.         
  195.   // 打印数据包内容
  196.   printf("[Recv] size=%d\n", len);
  197.   dump_data(packet->payload, len);

  198. #if ETH_PAD_SIZE
  199.   len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
  200. #endif

  201.   /* We allocate a pbuf chain of pbufs from the pool. */
  202.   p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
  203.   
  204. after_alloc: // 添加此标记

  205.   if (p != NULL) {

  206. #if ETH_PAD_SIZE
  207.     pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
  208. #endif

  209.     /* We iterate over the pbuf chain until we have read the entire
  210.      * packet into the pbuf. */
  211.     for (q = p; q != NULL; q = q->next) {
  212.       /* Read enough bytes to fill this pbuf in the chain. The
  213.        * available data in the pbuf is given by the q->len
  214.        * variable.
  215.        * This does not necessarily have to be a memcpy, you can also preallocate
  216.        * pbufs for a DMA-enabled MAC and after receiving truncate it to the
  217.        * actually received size. In this case, ensure the tot_len member of the
  218.        * pbuf is the sum of the chained pbuf len members.
  219.        */
  220.       //read data into(q->payload, q->len);
  221.                 memcpy(q->payload, bufptr, q->len); // 复制数据包内容
  222.                 bufptr += q->len; // 指针前移
  223.     }
  224.     //acknowledge that packet has been read(); // 无需确认

  225.     MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
  226.     if (((u8_t*)p->payload)[0] & 1) {
  227.       /* broadcast or multicast packet*/
  228.       MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
  229.     } else {
  230.       /* unicast packet*/
  231.       MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
  232.     }
  233. #if ETH_PAD_SIZE
  234.     pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
  235. #endif

  236.     LINK_STATS_INC(link.recv);
  237.   } else {
  238.     //drop packet(); // 注释掉此行
  239.     LINK_STATS_INC(link.memerr);
  240.     LINK_STATS_INC(link.drop);
  241.     MIB2_STATS_NETIF_INC(netif, ifindiscards);
  242.   }

  243.   return p;
  244. }

  245. /**
  246. * This function should be called when a packet is ready to be read
  247. * from the interface. It uses the function low_level_input() that
  248. * should handle the actual reception of bytes from the network
  249. * interface. Then the type of the received packet is determined and
  250. * the appropriate input function is called.
  251. *
  252. * @param netif the lwip network interface structure for this ethernetif
  253. */
  254. // 必须去掉static
  255. /*static */void
  256. ethernetif_input(struct netif *netif)
  257. {
  258.   struct ethernetif *ethernetif;
  259.   struct eth_hdr *ethhdr;
  260.   struct pbuf *p;

  261.   ethernetif = netif->state;

  262.   /* move received packet into a new pbuf */
  263.   p = low_level_input(netif);
  264.   /* if no packet could be read, silently ignore this */
  265.   if (p != NULL) {
  266.     /* pass all packets to ethernet_input, which decides what packets it supports */
  267.     if (netif->input(p, netif) != ERR_OK) {
  268.       LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
  269.       pbuf_free(p);
  270.       p = NULL;
  271.     }
  272.   }
  273. }

  274. /**
  275. * Should be called at the beginning of the program to set up the
  276. * network interface. It calls the function low_level_init() to do the
  277. * actual setup of the hardware.
  278. *
  279. * This function should be passed as a parameter to netif_add().
  280. *
  281. * @param netif the lwip network interface structure for this ethernetif
  282. * @return ERR_OK if the loopif is initialized
  283. *         ERR_MEM if private data couldn't be allocated
  284. *         any other err_t on error
  285. */
  286. err_t
  287. ethernetif_init(struct netif *netif)
  288. {
  289.   struct ethernetif *ethernetif;

  290.   LWIP_ASSERT("netif != NULL", (netif != NULL));

  291.   ethernetif = mem_malloc(sizeof(struct ethernetif));
  292.   if (ethernetif == NULL) {
  293.     LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
  294.     return ERR_MEM;
  295.   }

  296. #if LWIP_NETIF_HOSTNAME
  297.   /* Initialize interface hostname */
  298.   netif->hostname = "lwip";
  299. #endif /* LWIP_NETIF_HOSTNAME */

  300.   /*
  301.    * Initialize the snmp variables and counters inside the struct netif.
  302.    * The last argument should be replaced with your link speed, in units
  303.    * of bits per second.
  304.    */
  305.   MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);

  306.   netif->state = ethernetif;
  307.   netif->name[0] = IFNAME0;
  308.   netif->name[1] = IFNAME1;
  309.   /* We directly use etharp_output() here to save a function call.
  310.    * You can instead declare your own function an call etharp_output()
  311.    * from it if you have to do some checks before sending (e.g. if link
  312.    * is available...) */
  313.   netif->output = etharp_output;
  314. #if LWIP_IPV6
  315.   netif->output_ip6 = ethip6_output;
  316. #endif /* LWIP_IPV6 */
  317.   netif->linkoutput = low_level_output;

  318.   ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);

  319.   /* initialize the hardware */
  320.   low_level_init(netif);

  321.   return ERR_OK;
  322. }

  323. #endif /* 0 */
复制代码

在项目属性中,设置Include Paths为:.;.\lwip\include
其中点表示工程根目录。

另外,为了在程序中使用printf函数,Target选项卡下的Use MicroLIB复选框也要勾选上。

编译并下载程序,电脑和WiFi模块要连同一个WiFi热点。
电脑的IP地址要手动配置。IP地址为192.168.43.71(最后一个数随便),子网掩码为255.255.255.0,网关为192.168.43.1。
配置完成后,即可用电脑上的浏览器访问开发板上面的HTTP服务器。

评分

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

查看全部评分

回复

使用道具 举报

该用户从未签到

0

主题

12

帖子

0

蝴蝶豆

初级会员

最后登录
2017-9-14
发表于 2017-9-11 09:32:08 | 显示全部楼层
楼主你好,我最近也在做esp8266数据传输。做了一个stm32控制的tcp server可以传递数据,但是传递时间有点慢。可以和你讨论一下吗?我的qq是1632401541
回复 支持 0 反对 1

使用道具 举报

该用户从未签到

3

主题

1002

帖子

363

蝴蝶豆

版主

最后登录
2021-4-15
发表于 2017-7-21 11:10:56 | 显示全部楼层
个人给个建议,大量代码最好用文件的形式...然后将一些注意的地方,和自己整个开发过程的经验!!!!
回复 支持 反对

使用道具 举报

  • TA的每日心情
    开心
    2018-2-6 09:20
  • 签到天数: 1 天

    [LV.1]初来乍到

    1182

    主题

    4967

    帖子

    1

    蝴蝶豆

    论坛元老

    最后登录
    2020-3-17
    发表于 2017-7-24 15:03:19 | 显示全部楼层
    版主说的是,不过还是谢谢楼主分享
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    39

    主题

    975

    帖子

    45

    蝴蝶豆

    论坛元老

    最后登录
    2021-3-21
    发表于 2017-9-11 11:09:22 | 显示全部楼层
    Mark....

    多谢分享
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|论坛-意法半导体STM32/STM8技术社区

    GMT+8, 2024-3-29 00:43 , Processed in 0.195966 second(s), 40 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表