在线时间11 小时
UID3257111
ST金币94
蝴蝶豆0
注册时间2016-3-31
该用户从未签到
初级会员
- 最后登录
- 2020-8-3
|
本程序所用的单片机型号为:STM32F103RE
PB12端口为外接的WiFi模块电源开关,当PB12输出低电平时接通电源。
注意:WM-G-MR-09模块的芯片组(Chip Set)就是Marvell 88W8686。
该程序目前只能连接没有设密码的路由器,创建热点时也无法设置密码。
固件内容请参考:http://blog.csdn.net/zlk1214/article/details/74612925
注意必须把STM32启动文件*.s中的函数堆栈大小Stack_Size改大,否则函数中无法创建大数组!
- Stack_Size EQU 0x00000c00
复制代码 【main.c】
- #include <stdio.h>
- #include <stm32f10x.h>
- #include <string.h>
- #include "lwip/init.h" // lwip_init函数所在的头文件
- #include "lwip/timeouts.h" // sys_check_timeouts函数所在的头文件
- #include "netif/ethernet.h" // ethernet_input函数所在头文件
- #include "WiFi.h"
- // 这两个函数位于ethernetif.c中, 但没有头文件声明
- err_t ethernetif_init(struct netif *netif);
- void ethernetif_input(struct netif *netif);
- // httptest.c中的函数
- void init_http(void);
- // 延时n毫秒
- void delay(uint16_t n)
- {
- WiFi_PrepareTimer(n);
- while ((TIM6->SR & TIM_SR_UIF) == 0); // 等待计时完毕
- TIM6->SR &= ~TIM_SR_UIF; // 清除溢出标志
- }
- void dump_data(uint8_t *data, uint16_t len)
- {
- while (len--)
- printf("%02X", *data++);
- printf("\n");
- }
- int fputc(int ch, FILE *fp)
- {
- if (fp == stdout)
- {
- if (ch == '\n')
- {
- while ((USART1->SR & USART_SR_TXE) == 0);
- USART1->DR = '\r';
- }
- while ((USART1->SR & USART_SR_TXE) == 0);
- USART1->DR = ch;
- }
- return ch;
- }
- // RTC时间转化为毫秒数
- uint32_t sys_now(void)
- {
- uint32_t tmp = (RTC->CNTH << 16) | RTC->CNTL; // 秒
- tmp = tmp * 1000 + (32767 - RTC->DIVL) * 1000 / 32768; // 毫秒
- return tmp;
- }
- int main(void)
- {
- struct ip4_addr ipaddr, netmask, gw;
- struct netif wifi_88w8686;
- uint32_t last_check = 0;
-
- RCC->AHBENR = RCC_AHBENR_SDIOEN;
- RCC->APB1ENR = RCC_APB1ENR_PWREN | RCC_APB1ENR_TIM6EN;
- RCC->APB2ENR = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | RCC_APB2ENR_USART1EN;
-
- GPIOA->CRH = 0x000004b0;
- GPIOB->CRH = 0x00030000; // PB12为外接的WiFi模块电源开关, PB12=0时打开WiFi模块
- GPIOC->CRH = 0x000bbbbb;
- GPIOD->CRL = 0x00000b00;
-
- USART1->BRR = 0x271; // 波特率: 115200
- USART1->CR1 = USART_CR1_UE | USART_CR1_TE;
-
- PWR->CR = PWR_CR_DBP; // 允许写入后备寄存器
- if ((RCC->CSR & RCC_CSR_LSION) == 0)
- {
- RCC->CSR |= RCC_CSR_LSION; // 开内部低速晶振LSI
- while ((RCC->CSR & RCC_CSR_LSIRDY) == 0);
- //printf("LSI Ready!\n");
- }
- if ((RCC->BDCR & RCC_BDCR_RTCEN) == 0)
- {
- // 若RTC还没有打开, 则初始化RTC
- RCC->BDCR |= RCC_BDCR_RTCEN; // 打开RTC外设, 但暂不开始走时
-
- RTC->CRL |= RTC_CRL_CNF; // 进入RTC配置模式
- RTC->PRLH = 0;
- RTC->PRLL = 39999; // 定时1s (PRLH和PRLL寄存器只能写不能读)
- //RTC->CNTH = 0;
- //RTC->CNTL = 50; // 初始时间
- RTC->CRL &= ~RTC_CRL_CNF; // 保存设置
-
- RCC->BDCR |= RCC_BDCR_RTCSEL_1; // 选LSI作为RTC时钟, 准备走时
- while ((RTC->CRL & RTC_CRL_RTOFF) == 0); // 等待设置生效
- // RTC从此处开始走时
- }
-
- WiFi_Init();
- WiFi_Scan();
-
- //WiFi_StartADHOC("Marvell_88W8686"); // 创建一个热点
- WiFi_Connect("vivo Y29L", NULL); // 连接一个WiFi热点 (目前还不支持设密码)
-
- lwip_init();
- IP4_ADDR(&ipaddr, 192, 168, 43, 10); // IP地址
- IP4_ADDR(&netmask, 255, 255, 255, 0); // 子网掩码
- IP4_ADDR(&gw, 192, 168, 43, 1); // 网关
-
- netif_add(&wifi_88w8686, &ipaddr, &netmask, &gw, NULL, ethernetif_init, ethernet_input);
- netif_set_default(&wifi_88w8686); // 设为默认网卡
- netif_set_up(&wifi_88w8686);
-
- init_http();
-
- while (1)
- {
- if (WiFi_PacketPending() || WiFi_PacketArrived())
- ethernetif_input(&wifi_88w8686);
-
- // sys_check_timeouts函数千万不能调用的太频繁, 否则会出错!(例如开机后要等1~2分钟DHCP才能分配到IP地址)
- if (sys_now() - last_check > 200)
- {
- last_check = sys_now();
- //printf("Time: %d\n", last_check);
- sys_check_timeouts();
- }
- }
- }
复制代码 【httptest.c】
- #include <string.h>
- #include "lwip/tcp.h" // 一般情况下需要包含的头文件
- #define STR_AND_SIZE(str) (str), strlen(str)
- err_t http_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
- {
- char len[10]; // 存放HTML内容的长度
- char str[200]; // 存放HTML内容
-
- char name[100];
- char *pstr;
- uint8_t i = 0;
- if (p != NULL)
- {
- // 提取页面名称
- pstr = (char *)p->payload;
- while (*pstr++ != ' ');
- while (*pstr != ' ')
- name[i++] = *pstr++;
- name[i] = '\0'; // 不要忘了结束name字符串
- tcp_recved(tpcb, p->tot_len);
-
- // 生成HTML内容
- sprintf(str, "<meta charset="gb2312"><title>获取网页名称</title><div style="font-family:Arial"><b>请求的网页文件名称是: </b>%s</div>", name);
-
- sprintf(len, "%d", strlen(str)); // HTML内容的长度
- tcp_write(tpcb, STR_AND_SIZE("HTTP/1.1 200 OK\r\nContent-Length: "), TCP_WRITE_FLAG_MORE);
- tcp_write(tpcb, STR_AND_SIZE(len), TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
- 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);
- tcp_write(tpcb, STR_AND_SIZE(str), TCP_WRITE_FLAG_COPY); // 发送HTML内容
- pbuf_free(p);
- }
- return ERR_OK;
- }
- err_t http_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
- {
- tcp_recv(newpcb, http_recv);
- return ERR_OK;
- }
- void init_http(void)
- {
- struct tcp_pcb *tpcb = tcp_new();
- tcp_bind(tpcb, IP_ADDR_ANY, 80);
- tpcb = tcp_listen(tpcb);
- tcp_accept(tpcb, http_accept);
- }
复制代码 【WiFi.h】
- #define _BV(n) (1u << (n))
- #define CMD52_WRITE _BV(31)
- #define CMD52_READAFTERWRITE _BV(27)
- #define CMD53_WRITE _BV(31)
- #define CMD53_BLOCKMODE _BV(27)
- #define CMD53_INCREMENTING _BV(26)
- // 16.5 SDIO Card Metaformat
- #define CISTPL_NULL 0x00 // Null tuple
- #define CISTPL_VERS_1 0x15 // Level 1 version/product-information
- #define CISTPL_MANFID 0x20 // Manufacturer Identification String Tuple
- #define CISTPL_FUNCID 0x21 // Function Identification Tuple
- #define CISTPL_FUNCE 0x22 // Function Extensions
- #define CISTPL_END 0xff // The End-of-chain Tuple
- #define WIFI_DEFAULTTIMEOUT 1500 // WiFi命令回应的超时时间(ms)
- #define WIFI_SQREADBASEADDR0 0x10
- #define WIFI_SQREADBASEADDR1 0x11
- #define WIFI_SQREADBASEADDR2 0x12
- #define WIFI_SQREADBASEADDR3 0x13
- #define WIFI_CARDSTATUS 0x20 // Card Status
- #define WIFI_CARDSTATUS_IOREADY _BV(3) // I/O Ready Indicator
- #define WIFI_CARDSTATUS_CISCARDRDY _BV(2) // Card Information Structure Card Ready
- #define WIFI_CARDSTATUS_UPLDCARDRDY _BV(1) // Upload Card Ready
- #define WIFI_CARDSTATUS_DNLDCARDRDY _BV(0) // Download Card Ready
- #define WIFI_CAPABILITY_BSS _BV(0)
- #define WIFI_CAPABILITY_IBSS _BV(1)
- #define WIFI_CAPABILITY_CF_POLLABLE _BV(2)
- #define WIFI_CAPABILITY_CF_POLL_REQUEST _BV(3)
- #define WIFI_CAPABILITY_PRIVACY _BV(4)
- #define WIFI_CAPABILITY_SHORT_PREAMBLE _BV(5)
- #define WIFI_CAPABILITY_PBCC _BV(6)
- #define WIFI_CAPABILITY_CHANNEL_AGILITY _BV(7)
- #define WIFI_CAPABILITY_SPECTRUM_MGMT _BV(8)
- #define WIFI_CAPABILITY_QOS _BV(9)
- #define WIFI_CAPABILITY_SHORT_SLOT _BV(10)
- #define WIFI_CAPABILITY_DSSS_OFDM _BV(13)
- #define WIFI_SDIOFRAME_DATA 0x00
- #define WIFI_SDIOFRAME_COMMAND 0x01
- #define WIFI_SDIOFRAME_EVENT 0x03
- /* Command List */
- #define CMD_802_11_SCAN 0x0006 // Starts the scan process
- #define CMD_802_11_ASSOCIATE 0x0012 // Initiate an association with the AP
- #define CMD_MAC_CONTROL 0x0028 // Controls hardware MAC
- #define CMD_802_11_AD_HOC_START 0x002b // Starts an Ad-Hoc network
- #define CMD_802_11_MAC_ADDR 0x004d // WLAN MAC address
- #define CMD_802_11_KEY_MATERIAL 0x005e // Gets/sets key material used to do Tx encryption or Rx decryption
- #define CMD_802_11_BG_SCAN_CONFIG 0x006b // Gets/sets background scan configuration
- #define CMD_802_11_BG_SCAN_QUERY 0x006c // Gets background scan results
- /* Command Result Codes */
- #define CMD_STATUS_SUCCESS 0x0000 // No error
- #define CMD_STATUS_ERROR 0x0001 // Command failed
- #define CMD_STATUS_UNSUPPORTED 0x0002 // Command is not supported
- #define WIFI_ACT_GET 0
- #define WIFI_ACT_SET 1
- /* Authentication Type to be used to authenticate with AP */
- #define AUTH_MODE_OPEN 0x00
- #define AUTH_MODE_SHARED 0x01
- #define AUTH_MODE_NETWORK_EAP 0x80
- /* WiFi_Associate return value */
- #define WIFI_ASSOCIATION_NOTFOUND 0xfffe
- #define WIFI_ASSOCIATION_ERROR 0xffff
- #define WIFI_ASSOCIATION_SUCCESS 0x0000 // 连接成功
- #define WIFI_ASSOCIATION_INTERNALERROR 0x0101
- #define WIFI_ASSOCIATION_AUTHUNHANDLED(ret) (((ret) & 0xff00) == 0x200) // 未处理的认证帧
- #define WIFI_ASSOCIATION_UNSUPPORTEDAUTHALG 0x0213
- #define WIFI_ASSOCIATION_INVALIDSEQUENCENUMBER 0x0214
- #define WIFI_ASSOCIATION_AUTHREFUSED(ret) (((ret) & 0xff00) == 0x300) // 认证失败
- #define WIFI_ASSOCIATION_TIMEOUT(ret) (((ret) & 0xff00) == 0x400) // 超时
- #define WIFI_ASSOCIATION_ASSOCTIMEOUT 0x0401 // 连接超时
- #define WIFI_ASSOCIATION_AUTHTIMEOUT 0x402 // 认证超时
- #define WIFI_ASSOCIATION_NETWORKJOINTIMEOUT 0x403 // 加入网络时超时
- #define WIFI_KEYTYPE_WEP 0
- #define WIFI_KEYTYPE_TKIP 1
- #define WIFI_KEYTYPE_AES 2
- #define WIFI_KEYINFO_KEYENABLED _BV(2)
- #define WIFI_KEYINFO_UNICASTKEY _BV(1)
- #define WIFI_KEYINFO_MULTICASTKEY _BV(0)
- #define WIFI_MACCTRL_RX _BV(0)
- #define WIFI_MACCTRL_TX _BV(1) // 此位必须要置1才能发送数据!!!
- #define WIFI_MACCTRL_LOOPBACK _BV(2)
- #define WIFI_MACCTRL_WEP _BV(3)
- #define WIFI_MACCTRL_ETHERNET2 _BV(4)
- #define WIFI_MACCTRL_PROMISCUOUS _BV(7)
- #define WIFI_MACCTRL_ALLMULTICAST _BV(8)
- #define WIFI_MACCTRL_ENFORCEPROTECTION _BV(10) // strict protection
- #define WIFI_MACCTRL_ADHOCGPROTECTIONMODE _BV(13) // 802.11g protection mode
- /* BSS type */
- #define BSS_INFRASTRUCTURE 0x01
- #define BSS_INDEPENDENT 0x02
- #define BSS_ANY 0x03
- /* Table 45: IEEE 802.11 Standard IE Translated to Marvell IE */
- /* PDF中的表45有一些拼写错误, MRVIIE应该改为MRVLIE */
- #define MRVLIETYPES_SSIDPARAMSET 0x0000
- #define MRVLIETYPES_RATESPARAMSET 0x0001
- #define MRVLIETYPES_DSPARAMSET 0x0003
- #define MRVLIETYPES_CFPARAMSET 0x0004
- #define MRVLIETYPES_IBSSPARAMSET 0x0006
- #define MRVLIETYPES_RSNPARAMSET 0x0030
- #define MRVLIETYPES_VENDORPARAMSET 0x00dd
- #define MRVLIETYPES_KEYPARAMSET 0x0100
- #define MRVLIETYPES_CHANLISTPARAMSET 0x0101
- #define MRVLIETYPES_TSFTIMESTAMP 0x0113
- #define MRVLIETYPES_AUTHTYPE 0x011f
- #define MRVLIE_PAYLOADLEN(s) (sizeof(s) - sizeof((s).header)) // 已知结构体大小sizeof(s), 求数据域的大小
- #define MRVLIE_STRUCTLEN(s) (sizeof((s).header) + (s).header.length) // 已知数据域大小, 求整个结构体的大小
- typedef __packed struct
- {
- uint8_t type;
- uint8_t length;
- uint8_t data[1];
- } IEEEType;
- typedef __packed struct
- {
- uint16_t ie_length; // Total information element length
- uint8_t bssid[6]; // BSSID
- uint8_t rssi; // RSSI value as received from peer
-
- /* Probe Response/Beacon Payload */
- uint64_t pkt_time_stamp; // Timestamp
- uint16_t bcn_interval; // Beacon interval
- uint16_t cap_info; // Capabilities information
- IEEEType ie_parameters; // 存放的是一些IEEE类型的数据
- } WiFi_BssDescSet;
- typedef __packed struct
- {
- uint8_t oui[3];
- uint8_t oui_type;
- uint8_t oui_subtype;
- uint8_t version;
- } WiFi_VendorHeader;
- typedef __packed struct
- {
- uint16_t type;
- uint16_t length;
- } MrvlIEHeader;
- typedef __packed struct
- {
- MrvlIEHeader header;
- uint16_t auth_type;
- } MrvlIETypes_AuthType_t;
- typedef uint16_t MrvlIETypes_CapInfo_t; // Section 7.3.1.4: IEEE 802.11-1999 Spec
- typedef __packed struct
- {
- MrvlIEHeader header;
- uint8_t count;
- uint8_t period;
- uint16_t max_duration;
- uint16_t duration_remaining;
- } MrvlIETypes_CfParamSet_t;
- /*typedef __packed struct
- {
- MrvlIEHeader header;
- __packed struct
- {
- uint8_t band_config_type;
- uint8_t chan_number;
- } channels[1];
- } MrvlIETypes_ChanBandList_t;*/
- typedef __packed struct
- {
- MrvlIEHeader header;
- __packed struct
- {
- uint8_t band_config_type;
- uint8_t chan_number;
- uint8_t scan_type;
- uint16_t min_scan_time;
- uint16_t max_scan_time;
- } channels[1];
- } MrvlIETypes_ChanListParamSet_t;
- typedef __packed struct
- {
- MrvlIEHeader header;
- uint8_t channel;
- } MrvlIETypes_DsParamSet_t;
- typedef MrvlIETypes_DsParamSet_t MrvlIETypes_PhyParamDSSet_t;
- typedef __packed struct
- {
- MrvlIEHeader header;
- uint16_t atim_window;
- } MrvlIETypes_IbssParamSet_t;
- typedef __packed struct
- {
- MrvlIEHeader header;
- uint16_t key_type_id;
- uint16_t key_info;
- uint16_t key_len;
- uint8_t key[32];
- } MrvlIETypes_KeyParamSet_t;
- typedef __packed struct
- {
- MrvlIEHeader header;
- uint8_t rates[14];
- } MrvlIETypes_RatesParamSet_t;
- typedef __packed struct
- {
- MrvlIEHeader header;
- uint8_t rsn[64];
- } MrvlIETypes_RsnParamSet_t;
- typedef __packed struct
- {
- MrvlIEHeader header;
- uint8_t ssid[32];
- } MrvlIETypes_SSIDParamSet_t;
- typedef __packed struct
- {
- MrvlIEHeader header;
- uint64_t tsf_table[1];
- } MrvlIETypes_TsfTimestamp_t;
- // 整个结构体的最大大小为256字节
- typedef __packed struct
- {
- MrvlIEHeader header;
- uint8_t vendor[64]; // 通常情况下64字节已足够
- } MrvlIETypes_VendorParamSet_t;
- typedef __packed struct
- {
- uint16_t length;
- uint16_t type;
- } WiFi_SDIOFrameHeader;
- typedef __packed struct
- {
- WiFi_SDIOFrameHeader frame_header;
- uint16_t cmd_code;
- uint16_t size;
- uint16_t seq_num;
- uint16_t result;
- } WiFi_CommandHeader;
- /* Table 2: Fields in Receive Packet Descriptor */
- typedef __packed struct
- {
- WiFi_SDIOFrameHeader header;
- uint16_t reserved1;
- uint8_t snr; // Signal to noise ratio for this packet (dB)
- uint8_t reserved2;
- uint16_t rx_packet_length; // Number of bytes in the payload
- uint8_t nf; // Noise floor for this packet (dBm). Noise floor is always negative. The absolute value is passed.
- uint8_t rx_rate; // Rate at which this packet is received
- uint32_t rx_packet_offset; // Offset from the start of the packet to the beginning of the payload data packet
- uint32_t reserved3;
- uint8_t priority; // Specifies the user priority of received packet
- uint8_t reserved4[3];
- uint8_t payload[1]; // 数据链路层上的帧
- } WiFi_DataRx;
- /* Table 3: Fields in Transmit Packet Descriptor */
- typedef __packed struct
- {
- WiFi_SDIOFrameHeader header;
- uint32_t reserved1;
- uint32_t tx_control; // See 3.2.1 Per-Packet Settings
- 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)
- uint16_t tx_packet_length; // Number of bytes in the payload data frame
- uint16_t tx_dest_addr_high; // Destination MAC address bytes 4 to 5
- uint32_t tx_dest_addr_low; // Destination MAC address bytes 0 to 3
- uint8_t priority; // Specifies the user priority of transmit packet
- uint8_t flags;
- uint8_t pkt_delay_2ms; // Amount of time the packet has been queued in the driver layer for WMM implementations
- uint8_t reserved2;
- uint8_t payload[1]; // 数据链路层上的帧
- } WiFi_DataTx;
- typedef __packed struct
- {
- WiFi_CommandHeader header;
- uint16_t action;
- } WiFi_Cmd_KeyMaterial;
- typedef __packed struct
- {
- WiFi_CommandHeader header;
- uint16_t action;
- uint8_t mac_addr[6];
- } WiFi_Cmd_MACAddr;
- typedef __packed struct
- {
- WiFi_CommandHeader header;
- uint16_t action;
- uint16_t reserved;
- } WiFi_Cmd_MACCtrl;
- typedef __packed struct
- {
- WiFi_CommandHeader header;
- uint8_t ssid[32];
- uint8_t bss_type;
- uint16_t bcn_period;
- uint8_t reserved1;
- MrvlIETypes_IbssParamSet_t ibss_param_set; // ATIM window length in TU
- uint32_t reserved2;
- MrvlIETypes_DsParamSet_t ds_param_set; // The channel for ad-hoc network
- uint16_t reserved3[3];
- MrvlIETypes_CapInfo_t cap_info; // Capability information
- uint8_t data_rate[14];
- } WiFi_CmdRequest_ADHOCStart;
- typedef __packed struct
- {
- WiFi_CommandHeader header;
- uint8_t peer_sta_addr[6]; // Peer MAC address
- MrvlIETypes_CapInfo_t cap_info; // Capability information
- uint16_t listen_interval; // Listen interval
- uint16_t bcn_period; // Beacon period
- uint8_t dtim_period; // DTIM period
- } WiFi_CmdRequest_Associate;
- typedef __packed struct
- {
- WiFi_CommandHeader header;
- uint8_t bss_type;
- uint8_t bss_id[6];
- } WiFi_CmdRequest_Scan;
- typedef __packed struct
- {
- WiFi_CommandHeader header;
- uint16_t capability;
- uint16_t status_code;
- uint16_t association_id;
- IEEEType ie_buffer;
- } WiFi_CmdResponse_Associate;
- typedef __packed struct
- {
- WiFi_CommandHeader header;
- uint16_t buf_size;
- uint8_t num_of_set;
- } WiFi_CmdResponse_Scan;
- typedef __packed struct
- {
- MrvlIETypes_SSIDParamSet_t ssid;
- uint8_t mac_addr[6];
- MrvlIETypes_CapInfo_t cap_info;
- uint16_t bcn_period;
- uint8_t channel;
- MrvlIETypes_RatesParamSet_t rates;
- MrvlIETypes_RsnParamSet_t rsn;
- MrvlIETypes_VendorParamSet_t wpa;
- MrvlIETypes_VendorParamSet_t wwm;
- MrvlIETypes_VendorParamSet_t wps;
- } WiFi_SSIDInfo;
- #define WiFi_DropPacket() WiFi_ReceivePacket(0, 0)
- #define WiFi_GetBlockSize() _BV((SDIO->DCTRL & SDIO_DCTRL_DBLOCKSIZE) >> 4)
- #define WiFi_GetMACAddr(addr) WiFi_MACAddr((addr), WIFI_ACT_GET)
- #define WiFi_PacketArrived() (WiFi_Read(1, WIFI_CARDSTATUS) & WIFI_CARDSTATUS_UPLDCARDRDY)
- #define WiFi_ResendCommand(cmd) WiFi_SendCommand(0, (cmd), 0)
- #define WiFi_SetMACAddr(addr) WiFi_MACAddr((uint8_t *)(addr), WIFI_ACT_SET)
- #define WiFi_ShowShortResponse() printf("Command response received: CMD%d, RESP_%08x\n", SDIO->RESPCMD, SDIO->RESP1)
- uint16_t WiFi_Associate(const char *ssid);
- void WiFi_CheckCmdTimeout(void);
- uint16_t WiFi_Connect(const char *ssid, const char *password);
- uint8_t WiFi_DownloadFirmware(void);
- uint16_t WiFi_GetPacketLength(void);
- void WiFi_Init(void);
- uint16_t WiFi_KeyMaterial(MrvlIETypes_KeyParamSet_t *keys, uint16_t size, uint8_t action);
- void WiFi_MACAddr(uint8_t addr[6], uint8_t action);
- void WiFi_MACControl(uint16_t action);
- uint16_t WiFi_PacketPending(void);
- void WiFi_PrepareTimer(uint16_t nms);
- uint8_t WiFi_Read(uint8_t func, uint32_t addr);
- void WiFi_ReadData(uint8_t func, uint32_t addr, uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags);
- uint16_t WiFi_ReadPort(void *buf, uint16_t size, uint16_t bufsize);
- uint16_t WiFi_ReceivePacket(void *buf, uint16_t bufsize);
- uint16_t WiFi_ReceiveResponse(void *buf, uint16_t bufsize);
- void WiFi_Scan(void);
- uint8_t WiFi_ScanSSID(const char *ssid, WiFi_SSIDInfo *info, uint8_t *buffer, uint16_t bufsize);
- void WiFi_SendCMD52(uint8_t func, uint32_t addr, uint8_t data, uint32_t flags);
- void WiFi_SendCMD53(uint8_t func, uint32_t addr, uint16_t count, uint32_t flags);
- void WiFi_SendCommand(uint16_t com_code, void *data, uint16_t size);
- uint8_t WiFi_SendPacket(WiFi_DataTx *packet, uint16_t packet_len);
- void WiFi_SetBlockSize(uint8_t func);
- uint8_t WiFi_SetKeyMaterial(uint16_t type, uint16_t info, const uint8_t *key, uint16_t len);
- void WiFi_ShowCIS(uint8_t func);
- void WiFi_ShowKeyMaterials(void);
- uint8_t WiFi_StartADHOC(const char *ssid);
- uint8_t WiFi_Wait(uint8_t status);
- uint8_t WiFi_Write(uint8_t func, uint32_t addr, uint8_t value);
- void WiFi_WriteData(uint8_t func, uint32_t addr, const uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags);
- uint8_t WiFi_WritePort(const void *data, uint16_t size);
复制代码 【WiFi.c】
- #include <stdio.h>
- #include <stm32f10x.h>
- #include <string.h>
- #include "WiFi.h"
- extern const unsigned char firmware_helper_sd[2516];
- extern const unsigned char firmware_sd8686[122916];
- //const uint8_t wifi_mac_addr[] = {0x62, 0x1d, 0x2f, 0x00, 0x4e, 0x2d}; // MAC地址的第一个字节必须为偶数! 否则为多播地址
- static uint16_t rca;
- static uint16_t wifi_timeout = WIFI_DEFAULTTIMEOUT;
- static uint32_t io_addr;
- static uint16_t wifi_pending_size = 0; // 未读的数据包大小
- void delay(uint16_t n);
- void dump_data(uint8_t *data, uint16_t len);
- /* 关联一个热点 */
- uint16_t WiFi_Associate(const char *ssid)
- {
- uint8_t buffer[2048];
- WiFi_SSIDInfo info;
- WiFi_CmdRequest_Associate *cmd = (WiFi_CmdRequest_Associate *)buffer;
- WiFi_CmdResponse_Associate *resp = (WiFi_CmdResponse_Associate *)buffer;
- MrvlIETypes_DsParamSet_t *ds;
- MrvlIETypes_CfParamSet_t *cf;
- MrvlIETypes_AuthType_t *auth;
- MrvlIETypes_RsnParamSet_t *rsn;
- if (!WiFi_ScanSSID(ssid, &info, buffer, sizeof(buffer)))
- {
- printf("Cannot find AP: %s!\n", ssid);
- return WIFI_ASSOCIATION_NOTFOUND;
- }
-
- memcpy(cmd->peer_sta_addr, info.mac_addr, sizeof(info.mac_addr));
- cmd->cap_info = info.cap_info;
- cmd->listen_interval = 10;
- cmd->bcn_period = info.bcn_period;
- cmd->dtim_period = 0;
- memcpy(cmd + 1, &info.ssid, MRVLIE_STRUCTLEN(info.ssid));
-
- ds = (MrvlIETypes_DsParamSet_t *)((uint8_t *)(cmd + 1) + MRVLIE_STRUCTLEN(info.ssid));
- ds->header.type = MRVLIETYPES_DSPARAMSET;
- ds->header.length = 1;
- ds->channel = info.channel;
-
- cf = (MrvlIETypes_CfParamSet_t *)(ds + 1);
- memset(cf, 0, sizeof(MrvlIETypes_CfParamSet_t));
- cf->header.type = MRVLIETYPES_CFPARAMSET;
- cf->header.length = MRVLIE_PAYLOADLEN(*cf);
-
- memcpy(cf + 1, &info.rates, MRVLIE_STRUCTLEN(info.rates));
- auth = (MrvlIETypes_AuthType_t *)((uint8_t *)(cf + 1) + MRVLIE_STRUCTLEN(info.rates));
- auth->header.type = MRVLIETYPES_AUTHTYPE;
- auth->header.length = MRVLIE_PAYLOADLEN(*auth);
- auth->auth_type = AUTH_MODE_OPEN;
-
- rsn = (MrvlIETypes_RsnParamSet_t *)(auth + 1);
- if (info.rsn.header.type)
- {
- // WPA2网络必须在命令中加入RSN参数才能成功连接
- memcpy(rsn, &info.rsn, MRVLIE_STRUCTLEN(info.rsn));
- WiFi_SendCommand(CMD_802_11_ASSOCIATE, buffer, (uint8_t *)rsn - buffer + MRVLIE_STRUCTLEN(info.rsn));
- }
- else
- WiFi_SendCommand(CMD_802_11_ASSOCIATE, buffer, (uint8_t *)rsn - buffer); // 其余网络不需要RSN参数
-
- if (!WiFi_ReceiveResponse(buffer, sizeof(buffer)))
- {
- printf("Association with %s failed!\n", ssid);
- return WIFI_ASSOCIATION_ERROR;
- }
-
- //printf("capability=0x%04x, status_code=0x%04x, aid=0x%04x\n", resp->capability, resp->status_code, resp->association_id);
- if (resp->association_id == 0xffff)
- return ((-resp->capability) << 8) | resp->status_code;
- return WIFI_ASSOCIATION_SUCCESS;
- }
- /* 检查命令是否收到了回应, 若没收到则重发命令 */
- void WiFi_CheckCmdTimeout(void)
- {
- while (SDIO->STA & SDIO_STA_CTIMEOUT)
- {
- SDIO->ICR = SDIO_ICR_CTIMEOUTC; // 清除标志
- SDIO->CMD = SDIO->CMD; // 重发
- printf("Timeout! Resend CMD%d\n", SDIO->CMD & SDIO_CMD_CMDINDEX);
- while (SDIO->STA & SDIO_STA_CMDACT);
- }
- }
- /* 连接WiFi热点, 并输入密码 */
- uint16_t WiFi_Connect(const char *ssid, const char *password)
- {
- uint16_t ret;
- do
- {
- ret = WiFi_Associate(ssid);
- if (ret != WIFI_ASSOCIATION_SUCCESS)
- {
- printf("WiFi_Associate returned 0x%04x\n", ret);
- delay(2000); // 等待一段时间后重连
- }
- } while (WIFI_ASSOCIATION_TIMEOUT(ret) || ret == WIFI_ASSOCIATION_NOTFOUND); // 若连接超时, 或未扫描到热点, 则重连
-
- if (ret != WIFI_ASSOCIATION_SUCCESS)
- return ret;
-
- printf("Connected to %s!\n", ssid);
- return ret;
- }
- /* 下载固件 */
- // 参考文档: marvell-88w8686-固件下载程序说明.doc
- uint8_t WiFi_DownloadFirmware(void)
- {
- uint8_t helper_buf[64];
- const uint8_t *data;
- uint16_t size;
- uint32_t len;
-
- // 块大小设为32
- SDIO->DCTRL = (SDIO->DCTRL & ~SDIO_DCTRL_DBLOCKSIZE) | SDIO_DCTRL_DBLOCKSIZE_2 | SDIO_DCTRL_DBLOCKSIZE_0;
- WiFi_SetBlockSize(1); // 应用到Function 1
-
- // 下载helper
- io_addr = WiFi_Read(1, 0x00) | (WiFi_Read(1, 0x01) << 8) | (WiFi_Read(1, 0x02) << 16);
- data = firmware_helper_sd;
- len = sizeof(firmware_helper_sd);
- while (len)
- {
- // 每次下载64字节, 其中前4字节为本次下载的数据量
- size = (len > 60) ? 60 : len;
- *(uint32_t *)helper_buf = size;
- memcpy(helper_buf + 4, data, size);
-
- WiFi_Wait(WIFI_CARDSTATUS_DNLDCARDRDY);
- WiFi_WritePort(helper_buf, sizeof(helper_buf));
- len -= size;
- data += size;
- }
- *(uint32_t *)helper_buf = 0;
- WiFi_WritePort(helper_buf, sizeof(helper_buf)); // 以空数据包结束
-
- // 下载固件
- data = firmware_sd8686;
- len = sizeof(firmware_sd8686);
- while (len)
- {
- WiFi_Wait(WIFI_CARDSTATUS_DNLDCARDRDY);
- while ((size = WiFi_Read(1, WIFI_SQREADBASEADDR0) | (WiFi_Read(1, WIFI_SQREADBASEADDR1) << 8)) == 0); // 获取本次下载的字节数
- //printf("Required: %d bytes, Remaining: %d bytes\n", size, len);
-
- if (size & 1)
- {
- // 若size为奇数(如17), 则说明接收端有CRC校验错误, 应重新传送上一次的内容(这部分代码省略)
- printf("Error: an odd size is invalid!\n");
- return 0;
- }
- if (size > len)
- size = len;
-
- if (!WiFi_WritePort(data, size))
- {
- printf("Data transfer error! SDIO->STA=0x%08x\n", SDIO->STA);
- return 0;
- }
-
- len -= size;
- data += size;
- }
-
- // 等待Firmware启动
- while (WiFi_GetPacketLength() == 0xfedc);
- printf("Firmware is successfully downloaded!\n");
- return 1;
- }
- /* 获取数据帧大小 */
- uint16_t WiFi_GetPacketLength(void)
- {
- return WiFi_Read(1, 0x34) | (WiFi_Read(1, 0x35) << 8);
- }
- /* 初始化WiFi模块 */
- // SDIO Simplified Specification Version 3.00: 3. SDIO Card Initialization
- void WiFi_Init(void)
- {
- printf("Initialization begins...\n");
- SDIO->POWER = SDIO_POWER_PWRCTRL;
- SDIO->CLKCR = SDIO_CLKCR_CLKEN | 178; // 初始化时最高允许的频率: 72MHz/(178+2)=400kHz
- delay(5); // 延时可防止CMD5重发
-
- // 不需要发送CMD0, 因为SD I/O card的初始化命令是CMD52
- // 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)
-
- /* 发送CMD5: IO_SEND_OP_COND */
- SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 5;
- while (SDIO->STA & SDIO_STA_CMDACT);
- WiFi_CheckCmdTimeout(); // 为了保险起见还是要检查一下是否要重发命令
- if (SDIO->STA & SDIO_STA_CMDREND)
- {
- SDIO->ICR = SDIO_ICR_CMDRENDC;
- WiFi_ShowShortResponse();
- }
-
- /* 设置参数VDD Voltage Window: 3.2~3.4V, 并再次发送CMD5 */
- SDIO->ARG = 0x300000;
- SDIO->CMD = SDIO->CMD;
- while (SDIO->STA & SDIO_STA_CMDACT);
- if (SDIO->STA & SDIO_STA_CMDREND)
- {
- SDIO->ICR = SDIO_ICR_CMDRENDC;
- WiFi_ShowShortResponse();
- if (SDIO->RESP1 & _BV(31))
- {
- // Card is ready to operate after initialization
- printf("Number of I/O Functions: %d\n", (SDIO->RESP1 >> 28) & 7);
- printf("Memory Present: %d\n", (SDIO->RESP1 & _BV(27)) != 0);
- }
- }
-
- /* 获取WiFi模块地址 (CMD3: SEND_RELATIVE_ADDR, Ask the card to publish a new relative address (RCA)) */
- SDIO->ARG = 0;
- SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 3;
- while (SDIO->STA & SDIO_STA_CMDACT);
- if (SDIO->STA & SDIO_STA_CMDREND)
- {
- SDIO->ICR = SDIO_ICR_CMDRENDC;
- rca = SDIO->RESP1 >> 16;
- printf("Relative card address: 0x%04x\n", rca);
- }
-
- /* 选中WiFi模块 (CMD7: SELECT/DESELECT_CARD) */
- SDIO->ARG = rca << 16;
- SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 7;
- while (SDIO->STA & SDIO_STA_CMDACT);
- if (SDIO->STA & SDIO_STA_CMDREND)
- {
- SDIO->ICR = SDIO_ICR_CMDRENDC;
- printf("Card selected! status=0x%08x\n", SDIO->RESP1);
- }
-
- // 提高时钟频率
- SDIO->CLKCR = (SDIO->CLKCR & ~SDIO_CLKCR_CLKDIV) | 70; // 72MHz/(70+2)=1MHz
- SDIO->DTIMER = 1000000; // 当频率为1MHz时, 超时时间为1秒
- //SDIO->CLKCR = (SDIO->CLKCR & ~SDIO_CLKCR_CLKDIV) | 1; // 72MHz/(1+2)=24MHz
-
- /* 选择总线宽度 (Wide Bus Selection) */
- // For an SDIO card a write to the CCCR using CMD52 is used to select bus width. (See 4.5 Bus Width)
- // CMD52: IO_RW_DIRECT, CCCR: Card Common Control Registers
- WiFi_Write(0, 0x07, WiFi_Read(0, 0x07) | 0x02); // Bus Width: 4-bit bus
- SDIO->CLKCR |= SDIO_CLKCR_WIDBUS_0;
-
- // 初始化Function 1
- WiFi_Write(0, 0x02, 0x02); // IOE1=1 (Enable Function)
- while ((WiFi_Read(0, 3) & 0x02) == 0); // 等到IOR1=1 (I/O Function Ready)
-
- // 显示CIS信息
- //WiFi_ShowCIS(0);
- //WiFi_ShowCIS(1);
-
- // 下载固件
- WiFi_DownloadFirmware();
-
- // 设置数据块大小为256字节
- SDIO->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3;
- WiFi_SetBlockSize(0);
- WiFi_SetBlockSize(1);
-
- // 允许发送和接收
- // 不使用带有LLC子层的802.2SNAP帧格式, 这样LLC和SNAP这8个字节的内容就不会夹在数据链路层的源地址字段与数据字段之间
- WiFi_MACControl(WIFI_MACCTRL_ETHERNET2 | WIFI_MACCTRL_TX | WIFI_MACCTRL_RX);
- }
- /* 获取或设置密钥 */
- uint16_t WiFi_KeyMaterial(MrvlIETypes_KeyParamSet_t *keys, uint16_t size, uint8_t action)
- {
- uint8_t buffer[256];
- uint8_t ret_size;
- WiFi_Cmd_KeyMaterial *cmd = (WiFi_Cmd_KeyMaterial *)buffer;
- cmd->action = action;
- if (action == WIFI_ACT_SET)
- {
- memcpy(cmd + 1, keys, size);
- WiFi_SendCommand(CMD_802_11_KEY_MATERIAL, buffer, sizeof(WiFi_Cmd_KeyMaterial) + size);
- }
- else
- WiFi_SendCommand(CMD_802_11_KEY_MATERIAL, buffer, sizeof(WiFi_Cmd_KeyMaterial));
- WiFi_ReceiveResponse(buffer, sizeof(buffer));
-
- if (action == WIFI_ACT_GET)
- {
- ret_size = cmd->header.size - sizeof(cmd->header) - sizeof(cmd->action);
- if (ret_size <= size)
- memcpy(keys, cmd + 1, ret_size);
- else
- printf("WiFi_KeyMaterial: Buffer size is too small! %d bytes required!\n", ret_size);
- return ret_size; // action=get时返回读取的数据大小
- }
- else
- return cmd->header.result; // action=set时返回命令执行结果值
- }
- /* 获取或设置MAC地址 */
- void WiFi_MACAddr(uint8_t addr[6], uint8_t action)
- {
- WiFi_Cmd_MACAddr cmd;
- cmd.action = action;
- if (action == WIFI_ACT_SET)
- memcpy(cmd.mac_addr, addr, 6);
-
- WiFi_SendCommand(CMD_802_11_MAC_ADDR, &cmd, sizeof(cmd));
- WiFi_ReceiveResponse(&cmd, sizeof(cmd));
- if (action == WIFI_ACT_GET)
- memcpy(addr, cmd.mac_addr, 6);
- }
- /* 配置MAC */
- void WiFi_MACControl(uint16_t action)
- {
- WiFi_Cmd_MACCtrl cmd;
- cmd.action = action;
- cmd.reserved = 0;
- WiFi_SendCommand(CMD_MAC_CONTROL, &cmd, sizeof(cmd));
- WiFi_ReceiveResponse(&cmd, sizeof(cmd));
- }
- /* 获取滞留的数据包大小 */
- uint16_t WiFi_PacketPending(void)
- {
- return wifi_pending_size;
- }
- /* 准备好超时计时器 */
- void WiFi_PrepareTimer(uint16_t nms)
- {
- TIM6->ARR = 10 * nms - 1;
- TIM6->PSC = 7199; // 72MHz/7200=10kHz
- TIM6->EGR = TIM_EGR_UG; // 保存设置
- TIM6->SR &= ~TIM_SR_UIF; // 清除溢出标志位
- TIM6->CR1 = TIM_CR1_OPM | TIM_CR1_CEN; // 开始计时, 模式为非循环模式
- }
- /* 读寄存器 */
- uint8_t WiFi_Read(uint8_t func, uint32_t addr)
- {
- WiFi_SendCMD52(func, addr, NULL, NULL);
- if (SDIO->STA & SDIO_STA_CMDREND)
- {
- SDIO->ICR = SDIO_ICR_CMDRENDC;
- return SDIO->RESP1 & 0xff;
- }
- else
- {
- printf("WiFi_Read failed, SDIO->STA=0x%08x!\n", SDIO->STA);
- return 0;
- }
- }
- /* 读数据 */
- // count为要发送的字节数或块数, bufsize为data缓冲区的大小
- // bufsize=0时, 只读取数据不存入缓冲区
- void WiFi_ReadData(uint8_t func, uint32_t addr, uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags)
- {
- uint32_t len, temp;
- if (flags & CMD53_BLOCKMODE)
- {
- len = count * WiFi_GetBlockSize(); // count表示数据块数
- SDIO->DCTRL &= ~SDIO_DCTRL_DTMODE; // Block模式
- }
- else
- {
- len = count; // count表示字节数
- if (len % 4 != 0)
- {
- len += 4 - len % 4; // WiFi模块要求写入的字节数必须为4的整数倍
- count = len;
- }
- SDIO->DCTRL |= SDIO_DCTRL_DTMODE; // Multibyte模式
- }
- SDIO->DLEN = len;
- SDIO->DCTRL |= SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTEN; // 设置传输方向为从模块到主机
-
- WiFi_SendCMD53(func, addr, count, flags);
- while (len)
- {
- if (SDIO->STA & SDIO_STA_RXDAVL)
- {
- // 若有数据到来就读取数据
- len -= 4;
- if (bufsize >= 4)
- {
- *(uint32_t *)data = SDIO->FIFO;
- data += 4;
- }
- else
- {
- temp = SDIO->FIFO;
- if (bufsize > 0)
- {
- // 写入缓冲区最后1~3字节
- memcpy(data, &temp, bufsize);
- bufsize = 0;
- }
- }
- }
-
- if (SDIO->STA & SDIO_STA_DTIMEOUT)
- {
- printf("Data Timeout!\n");
- break;
- }
- else if (SDIO->STA & SDIO_STA_DCRCFAIL)
- {
- printf("Data CRC check failed! %d bytes are lost\n", len);
- break;
- }
- }
-
- while (SDIO->STA & (SDIO_STA_CMDACT | SDIO_STA_RXACT));
- SDIO->DCTRL &= ~SDIO_DCTRL_DTEN;
-
- SDIO->ICR = SDIO_STA_DATAEND | SDIO_ICR_CMDRENDC;
- if (flags & CMD53_BLOCKMODE)
- SDIO->ICR = SDIO_ICR_DBCKENDC;
-
- // 通过判断SDIO->STA是否等于0可知传输是否成功
- }
- uint16_t WiFi_ReadPort(void *buf, uint16_t size, uint16_t bufsize)
- {
- uint16_t block_num, block_size;
- block_size = WiFi_GetBlockSize();
-
- // 读取数据
- WiFi_Wait(0); // 发送CMD53前必须IOReady=1
- if (size >= 512 || size % block_size == 0)
- {
- // 采用Block模式传输
- block_num = size / block_size;
- if (size % block_size != 0)
- block_num++;
-
- WiFi_ReadData(1, io_addr, buf, block_num, bufsize, CMD53_BLOCKMODE);
- }
- else
- WiFi_ReadData(1, io_addr, buf, size, bufsize, 0);
-
- return SDIO->STA == 0;
- }
- /* 接收数据帧 */
- uint16_t WiFi_ReceivePacket(void *buf, uint16_t bufsize)
- {
- uint16_t size;
- if (wifi_pending_size)
- {
- size = wifi_pending_size; // 先读取滞留的数据包
- wifi_pending_size = 0;
- }
- else
- size = WiFi_GetPacketLength();
- return WiFi_ReadPort(buf, size, bufsize);
- }
- /* 接收WiFi命令的回应 */
- uint16_t WiFi_ReceiveResponse(void *buf, uint16_t bufsize)
- {
- uint8_t retry_cnt = 0; // 重试次数
- uint8_t wait_status, resend;
- uint16_t size;
- WiFi_CommandHeader *cmd = (WiFi_CommandHeader *)buf;
- WiFi_SDIOFrameHeader temp;
-
- // 等待数据准备好
- do
- {
- wait_status = WiFi_Wait(WIFI_CARDSTATUS_UPLDCARDRDY);
-
- WiFi_ReadPort(&temp, sizeof(temp), sizeof(temp)); // 试着读取头部信息
- if (temp.type == WIFI_SDIOFRAME_DATA && temp.length > 0) // 若读取到一个数据帧的头部
- {
- // 若读到的是一个数据帧, 不是命令回应
- // 则直接丢掉该数据帧, 然后重发命令, 保证命令执行成功
- printf("A packet of %d byte(s) preempted the command!\n", temp.length);
- wifi_pending_size = temp.length;
- WiFi_DropPacket(); // 必须读取完整个数据包, 只读完头部不算
- resend = 1;
- }
- else if (wait_status == 0)
- {
- // 若WiFi_Wait返回0, 则说明超时 (状态位在规定的时间内未置位)
- resend = 1;
- retry_cnt++;
- if (retry_cnt >= 5)
- {
- printf("No response!\n");
- return 0;
- }
- }
- else
- resend = 0;
-
- if (resend)
- {
- if (cmd->frame_header.type == WIFI_SDIOFRAME_COMMAND)
- {
- // 若超时后还没收到数据, 则重发命令, 然后再次执行WiFi_Wait
- printf("Resend WiFi command 0x%04x! size=%d\n", cmd->cmd_code, cmd->frame_header.length);
- WiFi_ResendCommand(buf);
- }
- else
- return 0; // 若buf中的内容不是命令, 则直接退出
- }
- } while (resend);
-
- size = WiFi_GetPacketLength();
- if (size > bufsize)
- printf("WiFi_ReceiveResponse: Buffer size is too small! %d bytes required!\n", size);
- return WiFi_ReadPort(buf, size, bufsize);
- }
- /* 扫描全部热点 (仅显示) */
- void WiFi_Scan(void)
- {
- // 必须把STM32启动文件*.s中的Stack_Size改大, 否则函数中无法创建大数组
- // Stack_Size=0x00000c00
- uint8_t buffer[2048]; // 用于接收返回的WiFi接入点信息, 需要较大的内存空间来存放
- uint8_t i, j, n;
- uint8_t ssid[33], channel, wpa;
- uint16_t ie_size;
-
- WiFi_CmdRequest_Scan *cmd = (WiFi_CmdRequest_Scan *)buffer; // 用buffer空间来存放要发送的命令
- MrvlIETypes_ChanListParamSet_t *chanlist = (MrvlIETypes_ChanListParamSet_t *)(buffer + sizeof(WiFi_CmdRequest_Scan));
-
- WiFi_CmdResponse_Scan *resp = (WiFi_CmdResponse_Scan *)buffer;
- WiFi_BssDescSet *bss_desc_set;
- WiFi_VendorHeader *vendor;
- IEEEType *ie_params;
- //MrvlIETypes_TsfTimestamp_t *tft_table;
-
- // 分4次扫描14个通道
- for (i = 0; i < 4; i++)
- {
- cmd->bss_type = BSS_ANY;
- memset(cmd->bss_id, 0, sizeof(cmd->bss_id));
-
- // 通道的基本参数
- n = (i == 3) ? 2 : 4; // 本次要扫描的通道数
- chanlist->header.type = MRVLIETYPES_CHANLISTPARAMSET;
- chanlist->header.length = n * sizeof(chanlist->channels);
- for (j = 0; j < n; j++)
- {
- chanlist->channels[j].band_config_type = 0;
- chanlist->channels[j].chan_number = 4 * i + j + 1; // 通道号
- chanlist->channels[j].scan_type = 0;
- chanlist->channels[j].min_scan_time = 0;
- chanlist->channels[j].max_scan_time = 100;
- }
-
- // 发送命令并接收数据
- WiFi_SendCommand(CMD_802_11_SCAN, buffer, sizeof(WiFi_CmdRequest_Scan) + sizeof(chanlist->header) + chanlist->header.length);
- WiFi_ReceiveResponse(buffer, sizeof(buffer)); // 接收的数据会将cmd和chanlist中的内容覆盖掉
-
- // 显示热点信息, num_of_set为热点数
- if (resp->num_of_set > 0)
- {
- bss_desc_set = (WiFi_BssDescSet *)(buffer + sizeof(WiFi_CmdResponse_Scan));
- for (j = 0; j < resp->num_of_set; j++)
- {
- wpa = 0;
- ie_params = &bss_desc_set->ie_parameters;
- ie_size = bss_desc_set->ie_length - (sizeof(WiFi_BssDescSet) - sizeof(bss_desc_set->ie_length) - sizeof(bss_desc_set->ie_parameters));
- while (ie_size > 0)
- {
- switch (ie_params->type)
- {
- case MRVLIETYPES_SSIDPARAMSET:
- // SSID名称
- memcpy(ssid, ie_params->data, ie_params->length);
- ssid[ie_params->length] = '\0';
- break;
- case MRVLIETYPES_DSPARAMSET:
- // 通道号
- channel = ie_params->data[0];
- break;
- case MRVLIETYPES_RSNPARAMSET:
- wpa = 2;
- break;
- case MRVLIETYPES_VENDORPARAMSET:
- if (wpa == 0)
- {
- vendor = (WiFi_VendorHeader *)ie_params->data;
- if (vendor->oui[0] == 0x00 && vendor->oui[1] == 0x50 && vendor->oui[2] == 0xf2 && vendor->oui_type == 0x01)
- wpa = 1;
- }
- break;
- }
- ie_size -= ie_params->length + 2;
- ie_params = (IEEEType *)((uint8_t *)ie_params + ie_params->length + 2);
- }
- if (ie_size != 0)
- printf("ie_parameters error!\n");
-
- printf("SSID '%s', ", ssid); // 热点名称
- 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地址
- printf("RSSI %d, Channel %d\n", bss_desc_set->rssi, channel); // 信号强度和通道号
- //printf(" Timestamp %lld, Beacon interval %d\n", bss_desc_set->pkt_time_stamp, bss_desc_set->bcn_interval);
-
- printf(" Capability: 0x%04x", bss_desc_set->cap_info);
- if (bss_desc_set->cap_info & WIFI_CAPABILITY_PRIVACY)
- {
- if (wpa == 1)
- printf("(WPA: ON, ");
- else if (wpa == 2)
- printf("(WPA2: ON, ");
- else
- printf("(WEP: ON, ");
- }
- else
- printf("(WEP: OFF, ");
-
- if (bss_desc_set->cap_info & WIFI_CAPABILITY_IBSS)
- printf("mode: Ad-Hoc)\n");
- else
- printf("mode: Infrastructure)\n");
-
- // 转向下一个热点信息
- bss_desc_set = (WiFi_BssDescSet *)((uint8_t *)bss_desc_set + sizeof(bss_desc_set->ie_length) + bss_desc_set->ie_length);
- }
-
- // resp->buf_size就是bss_desc_set的总大小
- // 因此tft_table == buffer + sizeof(WiFi_CmdResponse_Scan) + resp->buf_size
- /*tft_table = (MrvlIETypes_TsfTimestamp_t *)bss_desc_set;
- if (tft_table->header.type == MRVLIETYPES_TSFTIMESTAMP && tft_table->header.length == resp->num_of_set * sizeof(uint64_t))
- {
- printf("Timestamps: ");
- for (j = 0; j < resp->num_of_set; j++)
- printf("%lld ", tft_table->tsf_table[j]);
- printf("\n");
- }*/
-
- // TSF timestamp table是整个数据的末尾, 后面没有Channel/band table
- //if (((uint8_t *)tft_table - buffer) + sizeof(tft_table->header) + resp->num_of_set * sizeof(uint64_t) == cmd->header.frame_header.length)
- // printf("data end!\n");
- }
- }
- }
- /* 扫描指定名称的热点 */
- // buffer用来存放返回的全部结果, 因此bufsize应该足够大
- // info用来存放从buffer中提取出来的一些常用信息
- uint8_t WiFi_ScanSSID(const char *ssid, WiFi_SSIDInfo *info, uint8_t *buffer, uint16_t bufsize)
- {
- uint8_t i;
- uint16_t ie_size;
- WiFi_CmdRequest_Scan *cmd = (WiFi_CmdRequest_Scan *)buffer;
- WiFi_CmdResponse_Scan *resp = (WiFi_CmdResponse_Scan *)buffer;
- WiFi_BssDescSet *bss_desc_set = (WiFi_BssDescSet *)(resp + 1);
- MrvlIETypes_ChanListParamSet_t *chan_list;
- IEEEType *ie_params;
- WiFi_VendorHeader *vendor;
-
- cmd->bss_type = BSS_ANY;
- memset(cmd->bss_id, 0, sizeof(cmd->bss_id));
-
- // 添加ssid参数
- info->ssid.header.type = MRVLIETYPES_SSIDPARAMSET;
- info->ssid.header.length = strlen(ssid);
- memcpy(info->ssid.ssid, ssid, info->ssid.header.length);
- memcpy(cmd + 1, &info->ssid, MRVLIE_STRUCTLEN(info->ssid));
-
- chan_list = (MrvlIETypes_ChanListParamSet_t *)((uint8_t *)(cmd + 1) + MRVLIE_STRUCTLEN(info->ssid));
- chan_list->header.type = MRVLIETYPES_CHANLISTPARAMSET;
- chan_list->header.length = 14 * sizeof(chan_list->channels); // 一次性扫描14个通道
- for (i = 0; i < 14; i++)
- {
- chan_list->channels[i].band_config_type = 0;
- chan_list->channels[i].chan_number = i + 1;
- chan_list->channels[i].scan_type = 0;
- chan_list->channels[i].min_scan_time = 0;
- chan_list->channels[i].max_scan_time = 100;
- }
-
- WiFi_SendCommand(CMD_802_11_SCAN, buffer, ((uint8_t *)chan_list - buffer) + MRVLIE_STRUCTLEN(*chan_list));
- wifi_timeout = 3000; // 延长超时时间
- WiFi_ReceiveResponse(buffer, bufsize);
- wifi_timeout = WIFI_DEFAULTTIMEOUT;
-
- if (resp->num_of_set == 0)
- return 0; // 失败
-
- // bss_desc_set以扫描到的第一个信息项为准
- memcpy(info->mac_addr, bss_desc_set->bssid, sizeof(info->mac_addr));
- info->cap_info = bss_desc_set->cap_info;
- info->bcn_period = bss_desc_set->bcn_interval;
-
- // 若type=0, 则表明没有该项的信息 (除SSID结构体外, 因为SSID的type=MRVLIETYPES_SSIDPARAMSET=0)
- info->rates.header.type = 0;
- info->rsn.header.type = 0;
- info->wpa.header.type = 0;
- info->wwm.header.type = 0;
- info->wps.header.type = 0;
-
- ie_params = &bss_desc_set->ie_parameters;
- ie_size = bss_desc_set->ie_length - (sizeof(WiFi_BssDescSet) - sizeof(bss_desc_set->ie_length) - sizeof(bss_desc_set->ie_parameters));
- while (ie_size > 0)
- {
- switch (ie_params->type)
- {
- case MRVLIETYPES_RATESPARAMSET:
- // 速率
- info->rates.header.type = MRVLIETYPES_RATESPARAMSET;
- info->rates.header.length = ie_params->length;
- if (info->rates.header.length > sizeof(info->rates.rates))
- info->rates.header.length = sizeof(info->rates.rates);
- memcpy(info->rates.rates, ie_params->data, ie_params->length);
- break;
- case MRVLIETYPES_DSPARAMSET:
- // 通道号
- info->channel = ie_params->data[0];
- break;
- case MRVLIETYPES_RSNPARAMSET:
- // 通常只有一个RSN信息 (与WPA2相关)
- // printf("RSN len=%d\n", ie_params->length);
- info->rsn.header.type = MRVLIETYPES_RSNPARAMSET;
- info->rsn.header.length = ie_params->length;
- if (info->rsn.header.length > sizeof(info->rsn.rsn))
- info->rsn.header.length = sizeof(info->rsn.rsn);
- memcpy(info->rsn.rsn, ie_params->data, info->rsn.header.length);
- break;
- case MRVLIETYPES_VENDORPARAMSET:
- // 通常会有多项VENDOR信息 (与WPA相关)
- vendor = (WiFi_VendorHeader *)ie_params->data;
- if (vendor->oui[0] == 0x00 && vendor->oui[1] == 0x50 && vendor->oui[2] == 0xf2)
- {
- switch (vendor->oui_type)
- {
- case 0x01:
- // wpa_oui
- info->wpa.header.type = MRVLIETYPES_VENDORPARAMSET;
- info->wpa.header.length = ie_params->length;
- if (info->wpa.header.length > sizeof(info->wpa.vendor))
- info->wpa.header.length = sizeof(info->wpa.vendor);
- memcpy(info->wpa.vendor, ie_params->data, info->wpa.header.length);
- break;
- case 0x02:
- // wmm_oui
- if (ie_params->length == 24) // 合法大小
- {
- info->wwm.header.type = MRVLIETYPES_VENDORPARAMSET;
- info->wwm.header.length = ie_params->length;
- memcpy(info->wwm.vendor, ie_params->data, ie_params->length);
- }
- break;
- case 0x04:
- // wps_oui
- info->wps.header.type = MRVLIETYPES_VENDORPARAMSET;
- info->wps.header.length = ie_params->length;
- if (info->wps.header.length > sizeof(info->wps.vendor))
- info->wps.header.length = sizeof(info->wps.vendor);
- memcpy(info->wps.vendor, ie_params->data, info->wps.header.length);
- break;
- }
- }
- break;
- }
- ie_size -= ie_params->length + 2;
- ie_params = (IEEEType *)((uint8_t *)ie_params + ie_params->length + 2);
- }
-
- return 1; // 成功
- }
- void WiFi_SendCMD52(uint8_t func, uint32_t addr, uint8_t data, uint32_t flags)
- {
- SDIO->ARG = (func << 28) | (addr << 9) | data | flags;
- SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 52;
- while (SDIO->STA & SDIO_STA_CMDACT);
- }
- void WiFi_SendCMD53(uint8_t func, uint32_t addr, uint16_t count, uint32_t flags)
- {
- // 当count=512时, 和0x1ff相与后为0, 符合要求
- SDIO->ARG = (func << 28) | (addr << 9) | (count & 0x1ff) | flags;
- SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 53;
- }
- /* 发送WiFi命令 */
- void WiFi_SendCommand(uint16_t com_code, void *data, uint16_t size)
- {
- static uint16_t seq_num = 0;
- WiFi_CommandHeader *cmdhdr = (WiFi_CommandHeader *)data;
-
- if (size != 0)
- {
- cmdhdr->frame_header.length = size;
- cmdhdr->frame_header.type = WIFI_SDIOFRAME_COMMAND;
- cmdhdr->cmd_code = com_code;
- cmdhdr->size = size - sizeof(WiFi_SDIOFrameHeader); // 命令大小包括命令头部, 但不包括SDIO帧头部
- cmdhdr->seq_num = seq_num++;
- cmdhdr->result = 0;
- }
- else
- size = cmdhdr->frame_header.length; // 重发命令时不填写cmdhdr
-
- // 发送命令前若恰好有数据帧到来, 则直接丢弃
- if (WiFi_PacketPending() || WiFi_PacketArrived())
- {
- printf("A new packet happends to arrive when sending command! Drop it!\n");
- WiFi_DropPacket();
- }
-
- WiFi_WritePort(data, size);
- }
- /* 发送数据帧 */
- uint8_t WiFi_SendPacket(WiFi_DataTx *packet, uint16_t packet_len)
- {
- uint8_t ret;
-
- // 有关发送数据包的细节, 请参考Firmware Specification PDF的Chapter 3: Data Path
- packet->header.length = sizeof(WiFi_DataTx) - sizeof(packet->payload) + packet_len;
- packet->header.type = WIFI_SDIOFRAME_DATA;
-
- packet->reserved1 = 0;
- packet->tx_control = 0; // 控制信息的格式请参考3.2.1 Per-Packet Settings
- packet->tx_packet_offset = sizeof(WiFi_DataTx) - sizeof(packet->payload) - sizeof(packet->header); // 不包括SDIOFrameHeader
- packet->tx_packet_length = packet_len;
- memcpy((void *)&packet->tx_dest_addr_high, packet->payload, 6);
- packet->priority = 0;
- packet->flags = 0;
- packet->pkt_delay_2ms = 0;
- packet->reserved2 = 0;
-
- // 若现在有新收到的数据帧, 则暂存数据包大小
- // 未读取之前不会收到新的数据帧
- if (WiFi_PacketArrived())
- wifi_pending_size = WiFi_GetPacketLength();
-
- ret = WiFi_WritePort(packet, packet->header.length);
- WiFi_Wait(WIFI_CARDSTATUS_DNLDCARDRDY); // WiFi模块收到数据后, 会将该位置1
- return ret;
- }
- /* 将SDIO->DCTRL中的块大小信息应用到WiFi模块指定的功能区上 */
- void WiFi_SetBlockSize(uint8_t func)
- {
- // Part E1: 6.9 Card Common Control Registers (CCCR), 6.10 Function Basic Registers (FBR)
- uint16_t size = WiFi_GetBlockSize();
- WiFi_Write(0, (func << 8) | 0x10, size & 0xff);
- WiFi_Write(0, (func << 8) | 0x11, size >> 8);
- }
- /* 设置密钥 */
- uint8_t WiFi_SetKeyMaterial(uint16_t type, uint16_t info, const uint8_t *key, uint16_t len)
- {
- MrvlIETypes_KeyParamSet_t key_param;
- if (len > sizeof(key_param.key))
- return CMD_STATUS_ERROR;
- key_param.header.type = MRVLIETYPES_KEYPARAMSET;
- key_param.header.length = (key_param.key - (uint8_t *)&key_param) - sizeof(key_param.header) + len;
- key_param.key_type_id = type;
- key_param.key_info = info;
- key_param.key_len = len; // 当len=0时可保留key的值, 只更新key_info
- if (len)
- memcpy(key_param.key, key, len);
- return WiFi_KeyMaterial(&key_param, MRVLIE_STRUCTLEN(key_param), WIFI_ACT_SET);
- }
- /* 显示WiFi模块信息 */
- void WiFi_ShowCIS(uint8_t func)
- {
- uint8_t data[255];
- uint8_t i, len;
- uint8_t tpl_code, tpl_link; // 16.2 Basic Tuple Format and Tuple Chain Structure
- uint32_t cis_ptr;
-
- // 获取CIS的地址
- cis_ptr = (func << 8) | 0x9;
- cis_ptr = WiFi_Read(0, cis_ptr) | (WiFi_Read(0, cis_ptr + 1) << 8) | (WiFi_Read(0, cis_ptr + 2) << 16);
- printf("Pointer to Function %d Card Information Structure (CIS): 0x%08x\n", func, cis_ptr);
-
- // 遍历CIS, 直到尾节点
- while ((tpl_code = WiFi_Read(0, cis_ptr++)) != CISTPL_END)
- {
- if (tpl_code == CISTPL_NULL)
- continue;
-
- tpl_link = WiFi_Read(0, cis_ptr++); // 本结点数据的大小
- for (i = 0; i < tpl_link; i++)
- data[i] = WiFi_Read(0, cis_ptr + i);
-
- printf("[CIS Tuple 0x%02x] addr=0x%08x size=%d\n", tpl_code, cis_ptr - 2, tpl_link);
- dump_data(data, tpl_link);
- switch (tpl_code)
- {
- case CISTPL_VERS_1:
- i = 2;
- while (data[i] != 0xff)
- {
- len = strlen((char *)&data[i]);
- if (len != 0)
- printf("%s\n", data + i);
- i += len + 1;
- }
- break;
- case CISTPL_MANFID:
- // 16.6 CISTPL_MANFID: Manufacturer Identification String Tuple
- printf("SDIO Card manufacturer code: 0x%04x\n", *(uint16_t *)data); // TPLMID_MANF
- printf("manufacturer information (Part Number and/or Revision): 0x%04x\n", *(uint16_t *)(data + 2)); // TPLMID_CARD
- break;
- case CISTPL_FUNCID:
- // 16.7.1 CISTPL_FUNCID: Function Identification Tuple
- printf("Card function code: 0x%02x\n", data[0]); // TPLFID_FUNCTION
- printf("System initialization bit mask: 0x%02x\n", data[1]); // TPLFID_SYSINIT
- break;
- case CISTPL_FUNCE:
- // 16.7.2 CISTPL_FUNCE: Function Extension Tuple
- if (data[0] == 0)
- {
- // 16.7.3 CISTPL_FUNCE Tuple for Function 0 (Extended Data 00h)
- printf("maximum block size: %d\n", *(uint16_t *)(data + 1));
- printf("maximum transfer rate code: 0x%02x\n", data[3]);
- }
- else
- {
- // 16.7.4 CISTPL_FUNCE Tuple for Function 1-7 (Extended Data 01h)
- printf("maximum block size: %d\n", *(uint16_t *)(data + 0x0c)); // TPLFE_MAX_BLK_SIZE
- }
- }
-
- cis_ptr += tpl_link;
- if (tpl_link == 0xff)
- break; // 当TPL_LINK为0xff时说明当前结点为尾节点
- }
- }
- /* 显示所有密钥 */
- void WiFi_ShowKeyMaterials(void)
- {
- uint8_t buffer[256];
- uint16_t size;
- MrvlIETypes_KeyParamSet_t *key = (MrvlIETypes_KeyParamSet_t *)buffer;
-
- size = WiFi_KeyMaterial(key, sizeof(buffer), WIFI_ACT_GET);
- while (size)
- {
- printf("Type %d, Info 0x%04x, Len %d\n", key->key_type_id, key->key_info, key->key_len);
- dump_data(key->key, key->key_len);
- size -= MRVLIE_STRUCTLEN(*key);
- key = (MrvlIETypes_KeyParamSet_t *)((uint8_t *)key + MRVLIE_STRUCTLEN(*key));
- }
- if (size == 0)
- printf("data end!\n");
- }
- /* 创建一个Ad-Hoc型的WiFi热点 */
- uint8_t WiFi_StartADHOC(const char *ssid)
- {
- WiFi_CmdRequest_ADHOCStart cmd;
- memset(&cmd, 0, sizeof(cmd)); // 由于命令中含有Reserved区域, 所以必须先清零
-
- strncpy((char *)cmd.ssid, ssid, sizeof(cmd.ssid));
- cmd.bss_type = BSS_INDEPENDENT;
- cmd.bcn_period = 100;
- cmd.ibss_param_set.header.type = MRVLIETYPES_IBSSPARAMSET;
- cmd.ibss_param_set.header.length = MRVLIE_PAYLOADLEN(cmd.ibss_param_set);
- cmd.ibss_param_set.atim_window = 0;
- cmd.ds_param_set.header.type = MRVLIETYPES_DSPARAMSET;
- cmd.ds_param_set.header.length = MRVLIE_PAYLOADLEN(cmd.ds_param_set);
- cmd.ds_param_set.channel = 1;
- cmd.cap_info = WIFI_CAPABILITY_IBSS/* | WIFI_CAPABILITY_PRIVACY*/;
- *(uint32_t *)cmd.data_rate = 0x968b8482;
-
- WiFi_SendCommand(CMD_802_11_AD_HOC_START, &cmd, sizeof(cmd));
- WiFi_ReceiveResponse(&cmd, sizeof(cmd));
- return cmd.header.result;
- }
- /* 在规定的超时时间内, 等待指定的卡状态位置位(自动包括IO Ready位), 若成功则返回1 */
- uint8_t WiFi_Wait(uint8_t status)
- {
- status |= WIFI_CARDSTATUS_IOREADY;
- WiFi_PrepareTimer(wifi_timeout);
- while ((WiFi_Read(1, WIFI_CARDSTATUS) & status) != status)
- {
- if (TIM6->SR & TIM_SR_UIF)
- {
- // 若超时时间已到
- TIM6->SR &= ~TIM_SR_UIF;
- printf("WiFi_Wait(0x%02x): timeout!\n", status);
- return 0;
- }
- }
- TIM6->CR1 &=~ TIM_CR1_CEN; // 关闭定时器
- return 1;
- }
- /* 写寄存器, 返回写入后寄存器的实际内容 */
- uint8_t WiFi_Write(uint8_t func, uint32_t addr, uint8_t value)
- {
- WiFi_SendCMD52(func, addr, value, CMD52_WRITE | CMD52_READAFTERWRITE);
- if (SDIO->STA & SDIO_STA_CMDREND)
- {
- SDIO->ICR = SDIO_ICR_CMDRENDC;
- return SDIO->RESP1 & 0xff;
- }
- else
- {
- printf("WiFi_Write failed, SDIO->STA=0x%08x!\n", SDIO->STA);
- return 0;
- }
- }
- /* 写数据 */
- // count为要发送的字节数或块数, bufsize为data缓冲区的大小
- void WiFi_WriteData(uint8_t func, uint32_t addr, const uint8_t *data, uint16_t count, uint16_t bufsize, uint32_t flags)
- {
- uint32_t len, temp;
- if (flags & CMD53_BLOCKMODE)
- {
- len = count * WiFi_GetBlockSize();
- SDIO->DCTRL &= ~SDIO_DCTRL_DTMODE;
- }
- else
- {
- len = count;
- if (len % 4 != 0)
- {
- len += 4 - len % 4; // WiFi模块要求写入的字节数必须为4的整数倍
- count = len;
- }
- SDIO->DCTRL |= SDIO_DCTRL_DTMODE;
- }
- SDIO->DLEN = len;
- SDIO->DCTRL &= ~SDIO_DCTRL_DTDIR; // 设置传输方向: 从主机到模块
-
- WiFi_SendCMD53(func, addr, count, flags | CMD53_WRITE);
- while (SDIO->STA & SDIO_STA_CMDACT);
- if ((SDIO->STA & SDIO_STA_CMDREND) == 0)
- {
- printf("WiFi_WriteData: CMD53 no response!\n");
- return;
- }
- SDIO->ICR = SDIO_ICR_CMDRENDC;
-
- SDIO->DCTRL |= SDIO_DCTRL_DTEN; // 开始发送数据
- while (len)
- {
- len -= 4;
- if (bufsize >= 4)
- {
- SDIO->FIFO = *(uint32_t *)data;
- data += 4;
- bufsize -= 4;
- }
- else if (bufsize > 0)
- {
- // 发送缓冲区最后1~3字节
- temp = 0; // 不足的位用0填充
- memcpy(&temp, data, bufsize);
- SDIO->FIFO = temp;
- bufsize = 0;
- }
- else
- SDIO->FIFO = 0; // 缓冲区已用完, 因此发送0
- while (SDIO->STA & SDIO_STA_TXFIFOF); // 如果FIFO已满则等待
- }
-
- while (SDIO->STA & SDIO_STA_TXACT); // 等待发送完毕
- SDIO->DCTRL &= ~SDIO_DCTRL_DTEN; // 数据传输完毕后DTEN应及时清零, 防止后续对DCTRL寄存器操作后误启动数据传输导致超时或CRC校验错误
-
- // 清除相关标志位
- SDIO->ICR = SDIO_ICR_DATAENDC;
- if (flags & CMD53_BLOCKMODE)
- SDIO->ICR = SDIO_ICR_DBCKENDC;
- }
- uint8_t WiFi_WritePort(const void *data, uint16_t size)
- {
- uint16_t block_num, block_size;
- block_size = WiFi_GetBlockSize();
-
- WiFi_Wait(0); // 发送CMD53前必须IOReady=1
- if (size >= 512 || size % block_size == 0)
- {
- // 采用Block模式传输
- block_num = size / block_size;
- if (size % block_size != 0)
- block_num++;
-
- WiFi_WriteData(1, io_addr, data, block_num, size, CMD53_BLOCKMODE);
- }
- else
- WiFi_WriteData(1, io_addr, data, size, size, 0);
- return SDIO->STA == 0;
- }
复制代码
在工程的所在文件夹创建一个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文件,内容如下:
- #define PACK_STRUCT_BEGIN __packed // struct前的__packed
复制代码 创建lwip/include/lwipopts.h文件,内容如下:
- #define NO_SYS 1 // 无操作系统
-
- #define LWIP_NETCONN 0
- #define LWIP_SOCKET 0
- #define LWIP_STATS 0
-
- #define MEM_ALIGNMENT 4 // STM32单片机是32位的单片机, 因此是4字节对齐的
-
- #define SYS_LIGHTWEIGHT_PROT 0 // 不进行临界区保护 (在中断中调用lwip函数时要小心)
复制代码 打开lwip/netif/ethernetif.c文件,按照下面的中文提示修改代码:
- /**
- * @file
- * Ethernet Interface Skeleton
- *
- */
- /*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
- /*
- * This file is a skeleton for developing Ethernet network interface
- * drivers for lwIP. Add code to the low_level functions and do a
- * search-and-replace for the word "ethernetif" to replace it with
- * something that better describes your network interface.
- */
- #include "lwip/opt.h"
- #if 1 // 允许编译器编译该文件
- #include "lwip/def.h"
- #include "lwip/mem.h"
- #include "lwip/pbuf.h"
- #include "lwip/stats.h"
- #include "lwip/snmp.h"
- #include "lwip/ethip6.h"
- #include "lwip/etharp.h"
- #include "netif/ppp/pppoe.h"
- /* Define those to better describe your network interface. */
- #define IFNAME0 'e'
- #define IFNAME1 'n'
- #include <string.h> // memcpy函数所在的头文件
- #include "WiFi.h" // WiFi模块驱动程序头文件
- void dump_data(uint8_t *data, uint16_t len);
- /**
- * Helper struct to hold private data used to operate your ethernet interface.
- * Keeping the ethernet address of the MAC in this struct is not necessary
- * as it is already kept in the struct netif.
- * But this is only an example, anyway...
- */
- struct ethernetif {
- struct eth_addr *ethaddr;
- /* Add whatever per-interface state that is needed here. */
- };
- /* Forward declarations. */
- // 这里必须去掉static
- /*static */void ethernetif_input(struct netif *netif);
- /**
- * In this function, the hardware should be initialized.
- * Called from ethernetif_init().
- *
- * @param netif the already initialized lwip network interface structure
- * for this ethernetif
- */
- static void
- low_level_init(struct netif *netif)
- {
- struct ethernetif *ethernetif = netif->state;
- /* set MAC hardware address length */
- netif->hwaddr_len = ETHARP_HWADDR_LEN;
- /* set MAC hardware address */
- WiFi_GetMACAddr(netif->hwaddr); // 获取网卡的默认MAC地址
- 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]);
- /* maximum transfer unit */
- netif->mtu = 1500;
- /* device capabilities */
- /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
- netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
- #if LWIP_IPV6 && LWIP_IPV6_MLD
- /*
- * For hardware/netifs that implement MAC filtering.
- * All-nodes link-local is handled by default, so we must let the hardware know
- * to allow multicast packets in.
- * Should set mld_mac_filter previously. */
- if (netif->mld_mac_filter != NULL) {
- ip6_addr_t ip6_allnodes_ll;
- ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
- netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER);
- }
- #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
- /* Do whatever else is needed to initialize interface. */
- }
- /**
- * This function should do the actual transmission of the packet. The packet is
- * contained in the pbuf that is passed to the function. This pbuf
- * might be chained.
- *
- * @param netif the lwip network interface structure for this ethernetif
- * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
- * @return ERR_OK if the packet could be sent
- * an err_t value if the packet couldn't be sent
- *
- * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
- * strange results. You might consider waiting for space in the DMA queue
- * to become available since the stack doesn't retry to send a packet
- * dropped because of memory failure (except for the TCP timers).
- */
- static err_t
- low_level_output(struct netif *netif, struct pbuf *p)
- {
- struct ethernetif *ethernetif = netif->state;
- struct pbuf *q;
-
- // 添加的变量
- uint8_t buffer[1792];
- WiFi_DataTx *packet = (WiFi_DataTx *)buffer;
- uint8_t *bufptr = packet->payload;
- //initiate transfer();
- #if ETH_PAD_SIZE
- pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
- #endif
- for (q = p; q != NULL; q = q->next) {
- /* Send the data from the pbuf to the interface, one pbuf at a
- time. The size of the data in each pbuf is kept in the ->len
- variable. */
- //send data from(q->payload, q->len);
- memcpy(bufptr, q->payload, q->len); // 复制数据包内容
- bufptr += q->len; // 指针前移
- }
- //signal that packet should be sent();
- WiFi_SendPacket(packet, bufptr - packet->payload); // 发送数据包
-
- // 打印数据包内容
- printf("[Send] size=%d\n", packet->tx_packet_length);
- dump_data(packet->payload, packet->tx_packet_length);
- MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
- if (((u8_t*)p->payload)[0] & 1) {
- /* broadcast or multicast packet*/
- MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
- } else {
- /* unicast packet */
- MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
- }
- /* increase ifoutdiscards or ifouterrors on error */
- #if ETH_PAD_SIZE
- pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
- #endif
- LINK_STATS_INC(link.xmit);
- return ERR_OK;
- }
- /**
- * Should allocate a pbuf and transfer the bytes of the incoming
- * packet from the interface into the pbuf.
- *
- * @param netif the lwip network interface structure for this ethernetif
- * @return a pbuf filled with the received packet (including MAC header)
- * NULL on memory error
- */
- static struct pbuf *
- low_level_input(struct netif *netif)
- {
- struct ethernetif *ethernetif = netif->state;
- struct pbuf *p, *q;
- u16_t len;
-
- // 添加的变量
- uint8_t buffer[1792]; // 由于WiFi模块本身不支持使用多个CMD53命令读取数据包, 所以必须建立一个缓冲区, 一次性读取完
- WiFi_DataRx *packet = (WiFi_DataRx *)buffer;
- uint8_t *bufptr = packet->payload;
- /* Obtain the size of the packet and put it into the "len"
- variable. */
- len = WiFi_ReceivePacket(buffer, sizeof(buffer)); // 读取整个数据包, 返回值包含头部大小
- if (len == 0)
- {
- // 若读取失败, 则不分配pbuf, 退出本函数
- p = NULL;
- goto after_alloc;
- }
- len = packet->rx_packet_length; // 获取数据包的大小
-
- // 打印数据包内容
- printf("[Recv] size=%d\n", len);
- dump_data(packet->payload, len);
- #if ETH_PAD_SIZE
- len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
- #endif
- /* We allocate a pbuf chain of pbufs from the pool. */
- p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
-
- after_alloc: // 添加此标记
- if (p != NULL) {
- #if ETH_PAD_SIZE
- pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
- #endif
- /* We iterate over the pbuf chain until we have read the entire
- * packet into the pbuf. */
- for (q = p; q != NULL; q = q->next) {
- /* Read enough bytes to fill this pbuf in the chain. The
- * available data in the pbuf is given by the q->len
- * variable.
- * This does not necessarily have to be a memcpy, you can also preallocate
- * pbufs for a DMA-enabled MAC and after receiving truncate it to the
- * actually received size. In this case, ensure the tot_len member of the
- * pbuf is the sum of the chained pbuf len members.
- */
- //read data into(q->payload, q->len);
- memcpy(q->payload, bufptr, q->len); // 复制数据包内容
- bufptr += q->len; // 指针前移
- }
- //acknowledge that packet has been read(); // 无需确认
- MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
- if (((u8_t*)p->payload)[0] & 1) {
- /* broadcast or multicast packet*/
- MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
- } else {
- /* unicast packet*/
- MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
- }
- #if ETH_PAD_SIZE
- pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
- #endif
- LINK_STATS_INC(link.recv);
- } else {
- //drop packet(); // 注释掉此行
- LINK_STATS_INC(link.memerr);
- LINK_STATS_INC(link.drop);
- MIB2_STATS_NETIF_INC(netif, ifindiscards);
- }
- return p;
- }
- /**
- * This function should be called when a packet is ready to be read
- * from the interface. It uses the function low_level_input() that
- * should handle the actual reception of bytes from the network
- * interface. Then the type of the received packet is determined and
- * the appropriate input function is called.
- *
- * @param netif the lwip network interface structure for this ethernetif
- */
- // 必须去掉static
- /*static */void
- ethernetif_input(struct netif *netif)
- {
- struct ethernetif *ethernetif;
- struct eth_hdr *ethhdr;
- struct pbuf *p;
- ethernetif = netif->state;
- /* move received packet into a new pbuf */
- p = low_level_input(netif);
- /* if no packet could be read, silently ignore this */
- if (p != NULL) {
- /* pass all packets to ethernet_input, which decides what packets it supports */
- if (netif->input(p, netif) != ERR_OK) {
- LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
- pbuf_free(p);
- p = NULL;
- }
- }
- }
- /**
- * Should be called at the beginning of the program to set up the
- * network interface. It calls the function low_level_init() to do the
- * actual setup of the hardware.
- *
- * This function should be passed as a parameter to netif_add().
- *
- * @param netif the lwip network interface structure for this ethernetif
- * @return ERR_OK if the loopif is initialized
- * ERR_MEM if private data couldn't be allocated
- * any other err_t on error
- */
- err_t
- ethernetif_init(struct netif *netif)
- {
- struct ethernetif *ethernetif;
- LWIP_ASSERT("netif != NULL", (netif != NULL));
- ethernetif = mem_malloc(sizeof(struct ethernetif));
- if (ethernetif == NULL) {
- LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
- return ERR_MEM;
- }
- #if LWIP_NETIF_HOSTNAME
- /* Initialize interface hostname */
- netif->hostname = "lwip";
- #endif /* LWIP_NETIF_HOSTNAME */
- /*
- * Initialize the snmp variables and counters inside the struct netif.
- * The last argument should be replaced with your link speed, in units
- * of bits per second.
- */
- MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
- netif->state = ethernetif;
- netif->name[0] = IFNAME0;
- netif->name[1] = IFNAME1;
- /* We directly use etharp_output() here to save a function call.
- * You can instead declare your own function an call etharp_output()
- * from it if you have to do some checks before sending (e.g. if link
- * is available...) */
- netif->output = etharp_output;
- #if LWIP_IPV6
- netif->output_ip6 = ethip6_output;
- #endif /* LWIP_IPV6 */
- netif->linkoutput = low_level_output;
- ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
- /* initialize the hardware */
- low_level_init(netif);
- return ERR_OK;
- }
- #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服务器。
|
评分
-
查看全部评分
|