Selaa lähdekoodia

Merge pull request #1 from lymzzyh/master

first Commit
aozima 7 vuotta sitten
vanhempi
sitoutus
d9e868b166
5 muutettua tiedostoa jossa 1252 lisäystä ja 1 poistoa
  1. 56 1
      README.md
  2. 87 0
      SConscript
  3. 69 0
      example/rw007_stm32_port.c
  4. 260 0
      inc/spi_wifi_rw007.h
  5. 780 0
      src/spi_wifi_rw007.c

+ 56 - 1
README.md

@@ -1,2 +1,57 @@
 # rw007
-RW007 (SPI Wi-Fi module) driver for RT-Thread
+
+## 1. 简介
+
+**RW007**是由上海睿赛德电子科技有限公司开发基于Cortex-M4 WIFI SOC的SPI/UART 高速wifi模块。该仓库为**rw007**的SPI驱动
+
+**RW007**硬件设计简单,SPI模式下用户只需要预留1组SPI信号,一个中断输入,一个IO输出即可,包含电源和地总共8个引脚。
+
+### 1.1. 文件结构
+
+| 文件夹 | 说明 |
+| ---- | ---- |
+| src  | 核心驱动源码,主要实现通信逻辑 |
+| inc  | 头文件目录 |
+| example | 平台移植示例 |
+
+### 1.2 许可证
+
+at_device package 遵循 Apache 2.0 许可,详见 `LICENSE` 文件。
+
+### 1.3 依赖
+
+- RT-Thread 3.0+
+- RT-Thread LWIP 组件
+- RT-Thread SPI 驱动框架
+- RT-Thread PIN 驱动框架(示例平台代码依赖)
+
+### 1.4 配置宏说明
+
+自动配置时相关配置宏将在env中被配置 手动配置参考如下
+
+类型说明
+
+- bool: 定义生效 未定义 不生效
+- string: 字符串
+- int: 数值
+
+|宏|类型|功能|
+|--|--|--|
+|PKG_USING_RW007|bool|开启rw007驱动,使用该软件包则需要定义该宏|
+|RW007_USING_STM32_DRIVERS|bool|使能STM32平台移植示例|
+|RW007_USING_IMXRT_DRIVERS|bool|使能IMXRT平台移植示例|
+|RW007_SPI_BUS_NAME|string|example中使用的SPI总线设备名称|
+|RW007_CS_PIN|int|example中使用的SPI 片选引脚在pin驱动中的序号|
+|RW007_BOOT0_PIN|int|example中使用的BOOT0引脚在pin驱动中的序号(与SPI的CLK是同一引脚复用)|
+|RW007_BOOT1_PIN|int|example中使用的BOOT1引脚在pin驱动中的序号(与SPI的CS是同一引脚复用)|
+|RW007_INT_BUSY_PIN|int|example中使用的INT/BUSY引脚在pin驱动中的序号|
+|RW007_RST_PIN|int|example中使用的RST引脚在pin驱动中的序号|
+
+## 2. 注意事项
+
+由于存在引脚复用情况,所以bsp的SPI的驱动需要引脚配置在Config时进行。
+
+## 4. 联系方式
+
+- 维护:RT-Thread 开发团队
+- 主页:https://github.com/RT-Thread-packages/rw007

+ 87 - 0
SConscript

@@ -0,0 +1,87 @@
+#-*- encoding: utf-8 -*-
+#---------------------------------------------------------------------------------
+# @File:   Sconscript for package 
+# @Author: liu2guang
+# @Date:   2018-09-19 18:07:00(v0.1.0) 
+# 
+# @LICENSE: GPLv3: https://github.com/rtpkgs/buildpkg/blob/master/LICENSE.
+#
+#---------------------------------------------------------------------------------
+import os
+from building import * 
+Import('RTT_ROOT')
+Import('rtconfig')
+
+#---------------------------------------------------------------------------------
+# Package configuration
+#---------------------------------------------------------------------------------
+PKGNAME = "rw007"
+VERSION = "v0.0.1"
+DEPENDS = ["PKG_USING_RW007"]
+
+#---------------------------------------------------------------------------------
+# Compile the configuration 
+#
+# SOURCES: Need to compile c and c++ source, auto search when SOURCES is empty
+# 
+# LOCAL_CPPPATH: Local file path (.h/.c/.cpp)
+# LOCAL_CCFLAGS: Local compilation parameter 
+# LOCAL_ASFLAGS: Local assembly parameters
+# 
+# CPPPATH: Global file path (.h/.c/.cpp), auto search when LOCAL_CPPPATH/CPPPATH 
+#          is empty # no pass!!!
+# CCFLAGS: Global compilation parameter 
+# ASFLAGS: Global assembly parameters
+#
+# CPPDEFINES: Global macro definition
+# LOCAL_CPPDEFINES: Local macro definition 
+# 
+# LIBS: Specify the static library that need to be linked
+# LIBPATH: Specify the search directory for the library file (.lib/.a)
+#
+# LINKFLAGS: Link options
+#---------------------------------------------------------------------------------
+SOURCES          = ["src/spi_wifi_rw007.c"] 
+
+if GetDepend(['RW007_USING_STM32_DRIVERS']):
+    SOURCES     += ["example/rw007_stm32_port.c"]
+
+LOCAL_CPPPATH    = [] 
+LOCAL_CCFLAGS    = "" 
+LOCAL_ASFLAGS    = ""
+
+CPPPATH          = [GetCurrentDir(), os.path.join(GetCurrentDir(), 'inc')] 
+CCFLAGS          = "" 
+ASFLAGS          = ""
+
+CPPDEFINES       = []
+LOCAL_CPPDEFINES = []
+
+LIBS             = [] 
+LIBPATH          = [] 
+
+LINKFLAGS        = "" 
+
+SOURCES_IGNORE   = []
+CPPPATH_IGNORE   = []
+
+#---------------------------------------------------------------------------------
+# Main target
+#---------------------------------------------------------------------------------
+objs = DefineGroup(name = PKGNAME, src = SOURCES, depend = DEPENDS, 
+                   CPPPATH          = CPPPATH, 
+                   CCFLAGS          = CCFLAGS, 
+                   ASFLAGS          = ASFLAGS, 
+                   LOCAL_CPPPATH    = LOCAL_CPPPATH, 
+                   LOCAL_CCFLAGS    = LOCAL_CCFLAGS, 
+                   LOCAL_ASFLAGS    = LOCAL_ASFLAGS, 
+                   CPPDEFINES       = CPPDEFINES, 
+                   LOCAL_CPPDEFINES = LOCAL_CPPDEFINES, 
+                   LIBS             = LIBS, 
+                   LIBPATH          = LIBPATH,
+                   LINKFLAGS        = LINKFLAGS)  
+
+Return("objs") 
+#---------------------------------------------------------------------------------
+# End
+#---------------------------------------------------------------------------------

+ 69 - 0
example/rw007_stm32_port.c

@@ -0,0 +1,69 @@
+#include <rtthread.h>
+
+#ifdef RW007_USING_STM32_DRIVERS
+#include <rtdevice.h>
+#include <drv_spi.h>
+#include <board.h>
+#include <spi_wifi_rw007.h>
+
+#define RW007_AT_MODE   3
+#define RW007_SPI_MODE  1
+
+extern void spi_wifi_isr(int vector);
+
+static void set_rw007_mode(int mode)
+{
+    /* Configure IO */
+    rt_pin_mode(RW007_RST_PIN, PIN_MODE_OUTPUT);
+    rt_pin_mode(RW007_INT_BUSY_PIN, PIN_MODE_INPUT_PULLDOWN);
+    rt_pin_mode(RW007_BOOT0_PIN, PIN_MODE_OUTPUT);
+    rt_pin_mode(RW007_BOOT1_PIN, PIN_MODE_OUTPUT);
+    
+    /* Reset rw007 and config mode */
+    rt_pin_write(RW007_RST_PIN, PIN_LOW);
+    rt_pin_write(RW007_BOOT0_PIN, mode & 0x01 ? PIN_HIGH : PIN_LOW);
+    rt_pin_write(RW007_BOOT1_PIN, mode & 0x02 ? PIN_HIGH : PIN_LOW);
+    rt_thread_delay(rt_tick_from_millisecond(100));
+    rt_pin_write(RW007_RST_PIN, PIN_HIGH);
+
+    /* Wait rw007 ready(exit busy stat) */
+    while(!rt_pin_read(RW007_INT_BUSY_PIN))
+    {
+    }
+    rt_thread_delay(rt_tick_from_millisecond(100));
+}
+
+int wifi_spi_device_init(void)
+{
+    set_rw007_mode(RW007_SPI_MODE);
+    stm32_spi_bus_attach_device(RW007_CS_PIN, RW007_SPI_BUS_NAME, "wspi");
+    rt_hw_wifi_init("wspi",MODE_STATION);
+}
+INIT_APP_EXPORT(wifi_spi_device_init);
+    
+static void int_wifi_irq(void * p)
+{
+    ((void)p);
+    if(rt_pin_read(RW007_INT_BUSY_PIN))
+    {
+        spi_wifi_isr(0);
+    }
+}
+
+void spi_wifi_hw_init(void)
+{
+    rt_pin_attach_irq(RW007_INT_BUSY_PIN, PIN_IRQ_MODE_FALLING, int_wifi_irq, 0);
+    rt_pin_irq_enable(RW007_INT_BUSY_PIN, RT_TRUE);
+}
+
+rt_bool_t spi_wifi_is_busy(void)
+{
+    return !rt_pin_read(RW007_INT_BUSY_PIN);
+}
+
+void spi_wifi_int_cmd(rt_bool_t cmd)
+{
+    rt_pin_irq_enable(RW007_INT_BUSY_PIN, cmd);
+}
+
+#endif /* RW007_USING_STM32_DRIVERS */

+ 260 - 0
inc/spi_wifi_rw007.h

@@ -0,0 +1,260 @@
+/*
+ * COPYRIGHT (C) 2018, Real-Thread Information Technology Ltd
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2014-07-31     aozima       the first version
+ * 2014-09-18     aozima       update command & response.
+ */
+
+#ifndef SPI_WIFI_H_INCLUDED
+#define SPI_WIFI_H_INCLUDED
+
+#include <stdint.h>
+#include "lwipopts.h"
+#include <lwip/icmp.h>
+#include <netif/etharp.h>
+#include <netif/ethernetif.h>
+
+// little-endian
+struct spi_cmd_request
+{
+    uint32_t flag;
+    uint32_t M2S_len; // master to slave data len.
+    uint32_t magic1;
+    uint32_t magic2;
+};
+
+#define CMD_MAGIC1 (0x67452301)
+#define CMD_MAGIC2 (0xEFCDAB89)
+
+#define CMD_FLAG_MRDY (0x01)
+
+// little-endian
+struct spi_response
+{
+    uint32_t flag;
+    uint32_t S2M_len; // slave to master data len.
+    uint32_t magic1;
+    uint32_t magic2;
+};
+
+#define RESP_FLAG_SRDY (0x01)
+#define RESP_MAGIC1 (0x98BADCFE)
+#define RESP_MAGIC2 (0x10325476)
+
+/* spi slave configure. */
+#define SPI_MAX_DATA_LEN 1520
+#define SPI_TX_POOL_SIZE 2
+#define SPI_RX_POOL_SIZE 2
+
+typedef enum
+{
+    data_type_eth_data = 0,
+    data_type_cmd,
+    data_type_resp,
+    data_type_status,
+} app_data_type_typedef;
+
+struct spi_data_packet
+{
+    uint32_t data_len;
+    uint32_t data_type;
+    char buffer[SPI_MAX_DATA_LEN];
+};
+
+/********************************* RW007 **************************************/
+
+/* option */
+#define RW007_CMD_TIMEOUT (RT_TICK_PER_SECOND * 3)
+#define SSID_NAME_LENGTH_MAX (32)
+#define PASSWORD_LENGTH_MAX (64)
+
+typedef enum
+{
+    MODE_STATION = 0,
+    MODE_SOFTAP = 1,
+} wifi_mode_t;
+
+typedef struct _rw007_ap_info
+{
+    char ssid[SSID_NAME_LENGTH_MAX];
+    uint8_t bssid[8];       // 6byte + 2byte PAD.
+    int rssi;               /* Receive Signal Strength Indication in dBm. */
+    uint32_t max_data_rate; /* Maximum data rate in kilobits/s */
+    uint32_t security;      /* Security type  */
+    uint32_t channel;       /* Radio channel that the AP beacon was received on   */
+} rw007_ap_info;
+
+typedef struct _rw007_cmd_init
+{
+    uint32_t mode;
+} rw007_cmd_init;
+
+typedef struct _rw007_resp_init
+{
+    uint8_t mac[8];   // 6byte + 2byte PAD.
+    uint8_t sn[24];   // serial.
+    char version[16]; // firmware version.
+} rw007_resp_init;
+
+typedef struct _rw007_cmd_easy_join
+{
+    char ssid[SSID_NAME_LENGTH_MAX];
+    char passwd[PASSWORD_LENGTH_MAX];
+} rw007_cmd_easy_join;
+
+typedef struct _rw007_cmd_join
+{
+    uint8_t bssid[8]; // 6byte + 2byte PAD.
+    char passwd[PASSWORD_LENGTH_MAX];
+} rw007_cmd_join;
+
+typedef struct _rw007_cmd_rssi
+{
+    uint8_t bssid[8]; // 6byte + 2byte PAD.
+} rw007_cmd_rssi;
+
+typedef struct _rw007_cmd_softap
+{
+    char ssid[SSID_NAME_LENGTH_MAX];
+    char passwd[PASSWORD_LENGTH_MAX];
+
+    uint32_t security; /* Security type. */
+    uint32_t channel;  /* Radio channel that the AP beacon was received on   */
+} rw007_cmd_softap;
+
+typedef struct _rw007_resp_join
+{
+    rw007_ap_info ap_info;
+} rw007_resp_join;
+
+struct rw007_cmd
+{
+    uint32_t cmd;
+    uint32_t len;
+
+    /** command body */
+    union {
+        rw007_cmd_init init;
+        rw007_cmd_easy_join easy_join;
+        rw007_cmd_join join;
+        rw007_cmd_rssi rssi;
+        rw007_cmd_softap softap;
+    } params;
+};
+
+struct rw007_resp
+{
+    uint32_t cmd;
+    uint32_t len;
+
+    int32_t result; // result for CMD.
+
+    /** resp Body */
+    union {
+        rw007_resp_init init;
+        rw007_ap_info ap_info;
+    } resp;
+};
+
+/* tools */
+#define node_entry(node, type, member) ((type *)((char *)(node) - (unsigned long)(&((type *)0)->member)))
+#define member_offset(type, member) ((unsigned long)(&((type *)0)->member))
+
+#define MAX_ADDR_LEN (6) 
+#define MAX_SPI_PACKET_SIZE (member_offset(struct spi_data_packet, buffer) + SPI_MAX_DATA_LEN)
+#define MAX_SPI_BUFFER_SIZE (sizeof(struct spi_response) + MAX_SPI_PACKET_SIZE)
+
+struct rw007_wifi
+{
+    /* inherit from ethernet device */
+    struct eth_device parent;
+
+    struct rt_spi_device *rt_spi_device;
+
+    /* interface address info. */
+    rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address   */
+    rt_uint8_t active;
+
+    struct rt_mempool spi_tx_mp;
+    struct rt_mempool spi_rx_mp;
+
+    struct rt_mailbox spi_tx_mb;
+    struct rt_mailbox eth_rx_mb;
+
+    int spi_tx_mb_pool[SPI_TX_POOL_SIZE + 1];
+    int eth_rx_mb_pool[SPI_RX_POOL_SIZE + 1];
+
+    int rw007_cmd_mb_pool[3];
+    struct rt_mailbox rw007_cmd_mb;
+    uint32_t last_cmd;
+
+    ALIGN(4)
+    rt_uint8_t spi_tx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_TX_POOL_SIZE];
+    ALIGN(4)
+    rt_uint8_t spi_rx_mempool[(sizeof(struct spi_data_packet) + 4) * SPI_RX_POOL_SIZE];
+
+    ALIGN(4)
+    uint8_t spi_hw_rx_buffer[MAX_SPI_BUFFER_SIZE];
+
+    /* status for RW007 */
+    rw007_ap_info ap_info;  /* AP info for conn. */
+    rw007_ap_info *ap_scan; /* AP list for SCAN. */
+    uint32_t ap_scan_count;
+};
+
+#define RW007_CMD_INIT 128
+#define RW007_CMD_SCAN 129
+#define RW007_CMD_JOIN 130
+#define RW007_CMD_EASY_JOIN 131
+#define RW007_CMD_RSSI 132
+#define RW007_CMD_SOFTAP 133
+
+/** cond !ADDTHIS*/
+#define SHARED_ENABLED 0x00008000
+#define WPA_SECURITY 0x00200000
+#define WPA2_SECURITY 0x00400000
+#define WPS_ENABLED 0x10000000
+#define WEP_ENABLED 0x0001
+#define TKIP_ENABLED 0x0002
+#define AES_ENABLED 0x0004
+#define WSEC_SWFLAG 0x0008
+/** endcond */
+/**
+ * Enumeration of Wi-Fi security modes
+ */
+typedef enum
+{
+    SECURITY_OPEN = 0,                                                      /**< Open security                           */
+    SECURITY_WEP_PSK = WEP_ENABLED,                                         /**< WEP Security with open authentication   */
+    SECURITY_WEP_SHARED = (WEP_ENABLED | SHARED_ENABLED),                   /**< WEP Security with shared authentication */
+    SECURITY_WPA_TKIP_PSK = (WPA_SECURITY | TKIP_ENABLED),                  /**< WPA Security with TKIP                  */
+    SECURITY_WPA_AES_PSK = (WPA_SECURITY | AES_ENABLED),                    /**< WPA Security with AES                   */
+    SECURITY_WPA2_AES_PSK = (WPA2_SECURITY | AES_ENABLED),                  /**< WPA2 Security with AES                  */
+    SECURITY_WPA2_TKIP_PSK = (WPA2_SECURITY | TKIP_ENABLED),                /**< WPA2 Security with TKIP                 */
+    SECURITY_WPA2_MIXED_PSK = (WPA2_SECURITY | AES_ENABLED | TKIP_ENABLED), /**< WPA2 Security with AES & TKIP           */
+
+    SECURITY_WPS_OPEN = WPS_ENABLED,                   /**< WPS with open security                  */
+    SECURITY_WPS_SECURE = (WPS_ENABLED | AES_ENABLED), /**< WPS with AES security                   */
+
+    SECURITY_UNKNOWN = -1, /**< May be returned by scan function if security is unknown. Do not pass this to the join function! */
+
+    SECURITY_FORCE_32_BIT = 0x7fffffff /**< Exists only to force wiced_security_t type to 32 bits */
+} security_t;
+
+/* porting */
+extern void spi_wifi_hw_init(void);
+extern void spi_wifi_int_cmd(rt_bool_t cmd);
+extern rt_bool_t spi_wifi_is_busy(void);
+
+/* export API. */
+extern rt_err_t rt_hw_wifi_init(const char *spi_device_name, wifi_mode_t mode);
+extern int32_t rw007_rssi(void);
+extern rt_err_t rw007_join(const char *SSID, const char *passwd);
+extern rt_err_t rw007_softap(const char *SSID, const char *passwd, uint32_t security, uint32_t channel);
+
+
+#endif // SPI_WIFI_H_INCLUDED

+ 780 - 0
src/spi_wifi_rw007.c

@@ -0,0 +1,780 @@
+/*
+ * COPYRIGHT (C) 2018, Real-Thread Information Technology Ltd
+ * 
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2014-07-31     aozima       the first version
+ * 2014-09-18     aozima       update command & response.
+ * 2017-07-28     armink       fix auto reconnect feature
+ * 2018-12-24     zyh          porting rw007 from rw009
+ */
+
+#include <drivers/spi.h>
+#include <rtthread.h>
+
+#include "lwipopts.h"
+#include <lwip/icmp.h>
+#include <netif/etharp.h>
+#include <netif/ethernetif.h>
+
+#ifndef RW007_LOG_LEVEL
+#define RW007_LOG_LEVEL DBG_LOG
+#endif
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME "[RW007]"
+#define DBG_LEVEL RW007_LOG_LEVEL
+#define DBG_COLOR
+#include <rtdbg.h>
+
+/********************************* RW007 **************************************/
+#include "spi_wifi_rw007.h"
+
+static struct rw007_wifi rw007_wifi_device;
+static struct rt_event spi_wifi_data_event;
+
+static void resp_handler(struct rw007_wifi *wifi_device, struct rw007_resp *resp)
+{
+    struct rw007_resp *resp_return = RT_NULL;
+
+    switch (resp->cmd)
+    {
+    case RW007_CMD_INIT:
+        rt_kprintf("[RW007] rw007 init done\n");
+        resp_return = (struct rw007_resp *)rt_malloc(member_offset(struct rw007_resp, resp) + sizeof(rw007_resp_init)); //TODO:
+        if (resp_return == RT_NULL)
+            break;
+        memcpy(resp_return, resp, member_offset(struct rw007_resp, resp) + sizeof(rw007_resp_init));
+
+        rt_kprintf("[RW007] sn:%-*.*s\n", sizeof(resp->resp.init.sn), sizeof(resp->resp.init.sn), resp->resp.init.sn);
+        rt_kprintf("[RW007] version:%-*.*s\n", sizeof(resp->resp.init.version), sizeof(resp->resp.init.version), resp->resp.init.version);
+
+        rt_memcpy(wifi_device->dev_addr, resp->resp.init.mac, 6);
+        break;
+
+    case RW007_CMD_SCAN:
+        if (resp->len == sizeof(rw007_ap_info))
+        {
+            rw007_ap_info *ap_scan = rt_realloc(wifi_device->ap_scan, sizeof(rw007_ap_info) * (wifi_device->ap_scan_count + 1));
+            if (ap_scan != RT_NULL)
+            {
+                memcpy(&ap_scan[wifi_device->ap_scan_count], &resp->resp.ap_info, sizeof(rw007_ap_info));
+
+#if defined(DBG_ENABLE)
+                {
+                    rw007_ap_info *ap_info = &resp->resp.ap_info;
+
+                    LOG_D("SCAN SSID:%-32.32s", ap_info->ssid);
+                    LOG_D("SCAN BSSID:%02X-%02X-%02X-%02X-%02X-%02X",
+                          ap_info->bssid[0],
+                          ap_info->bssid[1],
+                          ap_info->bssid[2],
+                          ap_info->bssid[3],
+                          ap_info->bssid[4],
+                          ap_info->bssid[5]);
+                    LOG_D("SCAN rssi:%ddBm", ap_info->rssi);
+                    LOG_D("SCAN rate:%dMbps", ap_info->max_data_rate / 1000);
+                    LOG_D("SCAN channel:%d", ap_info->channel);
+                    LOG_D("SCAN security:%08X", ap_info->security);
+                }
+#endif
+                wifi_device->ap_scan_count++;
+                wifi_device->ap_scan = ap_scan;
+            }
+
+            return; /* wait for next ap */
+        }
+        break;
+    case RW007_CMD_JOIN:
+    case RW007_CMD_EASY_JOIN:
+        LOG_D("resp_handler RW007_CMD_EASY_JOIN");
+        resp_return = (struct rw007_resp *)rt_malloc(member_offset(struct rw007_resp, resp) + sizeof(rw007_resp_join)); //TODO:
+        if (resp_return == RT_NULL)
+            break;
+        memcpy(resp_return, resp, member_offset(struct rw007_resp, resp) + sizeof(rw007_resp_join));
+
+        if (resp->result == 0)
+        {
+            memcpy(&wifi_device->ap_info, &resp_return->resp.ap_info, sizeof(rw007_resp_join));
+            wifi_device->active = 1;
+            eth_device_linkchange(&wifi_device->parent, RT_TRUE);
+        }
+        else
+        {
+            wifi_device->active = 1;
+            eth_device_linkchange(&wifi_device->parent, RT_FALSE);
+            LOG_I("RW007_CMD_EASY_JOIN result: %d", resp->result);
+        }
+        {
+            rw007_ap_info *ap_info = &resp->resp.ap_info;
+            wifi_device->ap_info = *ap_info;
+#if defined(DBG_ENABLE)
+            
+
+            if(ap_info->channel == 0)
+            {
+                rt_kprintf("[RW007] WIFI Connect failed!\n");
+            }
+            else
+            {
+                rt_kprintf("[RW007] WIFI Connected!\n");
+                LOG_D("JOIN SSID:%-32.32s", ap_info->ssid);
+                LOG_D("JOIN BSSID:%02X-%02X-%02X-%02X-%02X-%02X",
+                    ap_info->bssid[0],
+                    ap_info->bssid[1],
+                    ap_info->bssid[2],
+                    ap_info->bssid[3],
+                    ap_info->bssid[4],
+                    ap_info->bssid[5]);
+                LOG_D("JOIN rssi:%ddBm", ap_info->rssi);
+                LOG_D("JOIN rate:%dMbps", ap_info->max_data_rate / 1000);
+                LOG_D("JOIN channel:%d", ap_info->channel);
+                LOG_D("JOIN security:%08X", ap_info->security);
+                
+            }
+#endif
+        }
+        break;
+
+    case RW007_CMD_RSSI:
+        {
+            wifi_device->ap_info.rssi = *((int *)&resp->resp);
+            rt_kprintf("[RW007] current RSSI: %ddBm\n", wifi_device->ap_info.rssi);
+        }
+        break;
+
+    case RW007_CMD_SOFTAP:
+    {
+        if (resp->result == 0)
+        {
+            wifi_device->active = 1;
+            eth_device_linkchange(&wifi_device->parent, RT_TRUE);
+        }
+        else
+        {
+            LOG_I("RW007_CMD_EASY_JOIN result: %d", resp->result);
+        }
+    }
+    break;
+
+    default:
+        LOG_W("unknow resp_handler %d", resp->cmd);
+        break;
+    }
+
+    if (resp->cmd == wifi_device->last_cmd)
+    {
+        rt_mb_send(&wifi_device->rw007_cmd_mb, (rt_uint32_t)resp_return);
+        return;
+    }
+    else
+    {
+        rt_free(resp_return);
+    }
+}
+
+static rt_err_t rw007_cmd(struct rw007_wifi *wifi_device, uint32_t cmd, void *args)
+{
+    rt_err_t result = RT_EOK;
+    rt_int32_t timeout = RW007_CMD_TIMEOUT;
+
+    struct spi_data_packet *data_packet;
+    struct rw007_cmd *wifi_cmd = RT_NULL;
+    struct rw007_resp *resp = RT_NULL;
+
+    wifi_device->last_cmd = cmd;
+
+    data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
+    wifi_cmd = (struct rw007_cmd *)data_packet->buffer;
+
+    wifi_cmd->cmd = cmd;
+    wifi_cmd->len = 0;
+
+    if (cmd == RW007_CMD_INIT)
+    {
+        wifi_cmd->len = sizeof(rw007_cmd_init);
+    }
+    else if (cmd == RW007_CMD_SCAN)
+    {
+        wifi_cmd->len = 0;
+        timeout += RT_TICK_PER_SECOND * 10;
+
+        if (wifi_device->ap_scan)
+        {
+            rt_free(wifi_device->ap_scan);
+            wifi_device->ap_scan = RT_NULL;
+            wifi_device->ap_scan_count = 0;
+        }
+    }
+    else if (cmd == RW007_CMD_JOIN)
+    {
+        wifi_cmd->len = sizeof(rw007_cmd_join);
+    }
+    else if (cmd == RW007_CMD_EASY_JOIN)
+    {
+        wifi_cmd->len = sizeof(rw007_cmd_easy_join);
+        timeout += RT_TICK_PER_SECOND * 5;
+    }
+    else if (cmd == RW007_CMD_RSSI)
+    {
+        wifi_cmd->len = sizeof(rw007_cmd_rssi);
+    }
+    else if (cmd == RW007_CMD_SOFTAP)
+    {
+        wifi_cmd->len = sizeof(rw007_cmd_softap);
+    }
+    else
+    {
+        LOG_E("unkown RW007 CMD %d", cmd);
+        result = -RT_ENOSYS;
+        rt_mp_free(data_packet);
+        data_packet = RT_NULL;
+    }
+
+    if (data_packet == RT_NULL)
+    {
+        goto _exit;
+    }
+
+    if (wifi_cmd->len)
+        memcpy(&wifi_cmd->params, args, wifi_cmd->len);
+
+    data_packet->data_type = data_type_cmd;
+    data_packet->data_len = member_offset(struct rw007_cmd, params) + wifi_cmd->len;
+
+    rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
+    rt_event_send(&spi_wifi_data_event, 1);
+
+    result = rt_mb_recv(&wifi_device->rw007_cmd_mb,
+                        (rt_ubase_t *)&resp,
+                        timeout);
+
+    if (result != RT_EOK)
+    {
+        LOG_E("CMD %d error, result %d", cmd, result);
+    }
+
+    if (resp != RT_NULL)
+        result = resp->result;
+
+_exit:
+    wifi_device->last_cmd = 0;
+    if (resp)
+    {
+        rt_free(resp);
+    }
+    return result;
+}
+
+static rt_err_t spi_wifi_transfer(struct rw007_wifi *dev)
+{
+    struct pbuf *p = RT_NULL;
+    struct spi_cmd_request cmd;
+    struct spi_response resp;
+
+    rt_err_t result;
+    const struct spi_data_packet *data_packet = RT_NULL;
+
+    struct rw007_wifi *wifi_device = (struct rw007_wifi *)dev;
+    struct rt_spi_device *rt_spi_device = wifi_device->rt_spi_device;
+
+    /* Disable INT Pin interrupt */
+    spi_wifi_int_cmd(0);
+
+    while (spi_wifi_is_busy())
+    {
+        /* wait for idel */
+    }
+
+    /* Clear cmd */
+    memset(&cmd, 0, sizeof(struct spi_cmd_request));
+
+    /* Set magic word */
+    cmd.magic1 = CMD_MAGIC1;
+    cmd.magic2 = CMD_MAGIC2;
+
+    /* Set master ready flag bit */
+    cmd.flag |= CMD_FLAG_MRDY;
+
+    /* Try get data to send to rw007 */
+    result = rt_mb_recv(&wifi_device->spi_tx_mb,
+                        (rt_ubase_t *)&data_packet,
+                        0);
+    /* Set length for master to slave when data ready*/
+    if ((result == RT_EOK) && (data_packet != RT_NULL) && (data_packet->data_len > 0))
+    {
+        cmd.M2S_len = data_packet->data_len + member_offset(struct spi_data_packet, buffer);
+    }
+
+    /* Stage 1: Send command to rw007 */
+    rt_spi_send(rt_spi_device, &cmd, sizeof(cmd));
+    while (spi_wifi_is_busy())
+    {
+        /* wait for idel */
+    }
+
+    /* Stage 2: Receive response from rw007 and transmit data */
+    {
+        struct rt_spi_message message;
+        uint32_t max_data_len = 0;
+
+        /* Setup message */
+        message.send_buf = RT_NULL;
+        message.recv_buf = &resp;
+        message.length = sizeof(resp);
+        message.cs_take = 1;
+        message.cs_release = 0;
+
+        /* Start a SPI transmit */
+        rt_spi_take_bus(rt_spi_device);
+
+        /* Receive response from rw007 */
+        rt_spi_device->bus->ops->xfer(rt_spi_device, &message);
+
+        /* Check response's magic word */
+        if ((resp.magic1 != RESP_MAGIC1) || (resp.magic2 != RESP_MAGIC2))
+        {
+            goto _bad_resp_magic;
+        }
+
+        /* Check rw007's data ready flag */
+        if (resp.flag & RESP_FLAG_SRDY)
+        {
+            max_data_len = cmd.M2S_len;
+        }
+
+        if (resp.S2M_len)
+        {
+            if (resp.S2M_len > MAX_SPI_PACKET_SIZE)
+            {
+                /* Drop error data */
+                resp.S2M_len = 0;
+            }
+
+            if (resp.S2M_len > max_data_len)
+                max_data_len = resp.S2M_len;
+        }
+
+    _bad_resp_magic:
+        /* Setup message */
+        message.send_buf = data_packet;
+        message.recv_buf = wifi_device->spi_hw_rx_buffer;
+        message.length = RT_ALIGN(max_data_len, 4);/* align clk to word */
+        message.cs_take = 0;
+        message.cs_release = 1;
+
+        /* Transmit data */
+        rt_spi_device->bus->ops->xfer(rt_spi_device, &message);
+
+        /* End a SPI transmit */
+        rt_spi_release_bus(rt_spi_device);
+
+        /* Free send data space */
+        if (cmd.M2S_len)
+        {
+            rt_mp_free((void *)data_packet);
+            data_packet = RT_NULL;
+        }
+
+        /* Parse recevied data */
+        if ((resp.S2M_len) && (resp.S2M_len <= MAX_SPI_PACKET_SIZE))
+        {
+            data_packet = (struct spi_data_packet *)wifi_device->spi_hw_rx_buffer;
+            if (data_packet->data_type == data_type_eth_data)
+            {
+
+                if (wifi_device->active)
+                {
+                    p = pbuf_alloc(PBUF_LINK, data_packet->data_len, PBUF_RAM);
+                    pbuf_take(p, (rt_uint8_t *)data_packet->buffer, data_packet->data_len);
+
+                    rt_mb_send(&wifi_device->eth_rx_mb, (rt_uint32_t)p);
+                    eth_device_ready((struct eth_device *)dev);
+                }
+            }
+            else if (data_packet->data_type == data_type_resp)
+            {
+                resp_handler(dev, (struct rw007_resp *)data_packet->buffer);
+            }
+        }
+    }
+    /* Enable INT Pin interrupt */
+    spi_wifi_int_cmd(1);
+
+    if ((cmd.M2S_len == 0) && (resp.S2M_len == 0))
+    {
+        return -RT_ERROR;
+    }
+
+    return RT_EOK;
+}
+
+/********************************* RT-Thread Ethernet interface begin **************************************/
+static rt_err_t rw007_wifi_init(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+static rt_err_t rw007_wifi_open(rt_device_t dev, rt_uint16_t oflag)
+{
+    return RT_EOK;
+}
+
+static rt_err_t rw007_wifi_close(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+static rt_size_t rw007_wifi_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+    rt_set_errno(-RT_ENOSYS);
+    return 0;
+}
+
+static rt_size_t rw007_wifi_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+    rt_set_errno(-RT_ENOSYS);
+    return 0;
+}
+
+static rt_err_t rw007_wifi_control(rt_device_t dev, int cmd, void *args)
+{
+    struct rw007_wifi *wifi_device = (struct rw007_wifi *)dev;
+    rt_err_t result = RT_EOK;
+
+    if (cmd == NIOCTL_GADDR)
+    {
+        memcpy(args, wifi_device->dev_addr, 6);
+    }
+    else
+    {
+        result = rw007_cmd(wifi_device, cmd, args);
+    }
+
+    return result;
+}
+
+/* transmit packet. */
+rt_err_t rw007_wifi_tx(rt_device_t dev, struct pbuf *p)
+{
+    rt_err_t result = RT_EOK;
+    struct spi_data_packet *data_packet;
+    struct rw007_wifi *wifi_device = (struct rw007_wifi *)dev;
+
+    if (!wifi_device->active)
+    {
+        return RT_EOK;
+    }
+
+    /* get free tx buffer */
+    data_packet = (struct spi_data_packet *)rt_mp_alloc(&wifi_device->spi_tx_mp, RT_WAITING_FOREVER);
+    if (data_packet != RT_NULL)
+    {
+        data_packet->data_type = data_type_eth_data;
+        data_packet->data_len = p->tot_len;
+
+        pbuf_copy_partial(p, data_packet->buffer, data_packet->data_len, 0);
+
+        rt_mb_send(&wifi_device->spi_tx_mb, (rt_uint32_t)data_packet);
+        rt_event_send(&spi_wifi_data_event, 1);
+    }
+    else
+        return -RT_ERROR;
+
+    /* Return SUCCESS */
+    return result;
+}
+
+/* reception packet. */
+struct pbuf *rw007_wifi_rx(rt_device_t dev)
+{
+    struct pbuf *p = RT_NULL;
+    struct rw007_wifi *wifi_device = (struct rw007_wifi *)dev;
+
+    if (rt_mb_recv(&wifi_device->eth_rx_mb, (rt_ubase_t *)&p, 0) != RT_EOK)
+    {
+        return RT_NULL;
+    }
+
+    return p;
+}
+/********************************* RT-Thread Ethernet interface end **************************************/
+
+static void spi_wifi_data_thread_entry(void *parameter)
+{
+    rt_uint32_t e;
+    rt_err_t result;
+
+    while (1)
+    {
+        /* receive first event */
+        if (rt_event_recv(&spi_wifi_data_event,
+                          1,
+                          RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
+                          RT_WAITING_FOREVER,
+                          &e) != RT_EOK)
+        {
+            continue;
+        }
+
+        result = spi_wifi_transfer(&rw007_wifi_device);
+
+        if (result == RT_EOK)
+        {
+            rt_event_send(&spi_wifi_data_event, 1);
+        }
+    }
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops rw007_ops =
+    {
+        rw007_wifi_init,
+        rw007_wifi_open,
+        rw007_wifi_close,
+        rw007_wifi_read,
+        rw007_wifi_write,
+        rw007_wifi_control};
+#endif
+
+rt_err_t rt_hw_wifi_init(const char *spi_device_name, wifi_mode_t mode)
+{
+    /* align and struct size check. */
+    RT_ASSERT((SPI_MAX_DATA_LEN & 0x03) == 0);
+    RT_ASSERT(sizeof(struct rw007_resp) <= SPI_MAX_DATA_LEN);
+
+    memset(&rw007_wifi_device, 0, sizeof(struct rw007_wifi));
+
+    rw007_wifi_device.rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
+
+    if (rw007_wifi_device.rt_spi_device == RT_NULL)
+    {
+        LOG_E("spi device %s not found!\r", spi_device_name);
+        return -RT_ENOSYS;
+    }
+
+    /* config spi */
+    {
+        struct rt_spi_configuration cfg;
+        cfg.data_width = 8;
+        cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0. */
+        cfg.max_hz = 15 * 1000000;             /* 15M 007 max 30M */
+        rt_spi_configure(rw007_wifi_device.rt_spi_device, &cfg);
+    }
+
+#ifdef RT_USING_DEVICE_OPS
+    rw007_wifi_device.parent.parent.ops = &rw007_ops;
+#else
+    rw007_wifi_device.parent.parent.init = rw007_wifi_init;
+    rw007_wifi_device.parent.parent.open = rw007_wifi_open;
+    rw007_wifi_device.parent.parent.close = rw007_wifi_close;
+    rw007_wifi_device.parent.parent.read = rw007_wifi_read;
+    rw007_wifi_device.parent.parent.write = rw007_wifi_write;
+    rw007_wifi_device.parent.parent.control = rw007_wifi_control;
+#endif
+    rw007_wifi_device.parent.parent.user_data = RT_NULL;
+
+    rw007_wifi_device.parent.eth_rx = rw007_wifi_rx;
+    rw007_wifi_device.parent.eth_tx = rw007_wifi_tx;
+
+    rt_mp_init(&rw007_wifi_device.spi_tx_mp,
+               "spi_tx",
+               &rw007_wifi_device.spi_tx_mempool[0],
+               sizeof(rw007_wifi_device.spi_tx_mempool),
+               sizeof(struct spi_data_packet));
+
+    rt_mp_init(&rw007_wifi_device.spi_rx_mp,
+               "spi_rx",
+               &rw007_wifi_device.spi_rx_mempool[0],
+               sizeof(rw007_wifi_device.spi_rx_mempool),
+               sizeof(struct spi_data_packet));
+
+    rt_mb_init(&rw007_wifi_device.spi_tx_mb,
+               "spi_tx",
+               &rw007_wifi_device.spi_tx_mb_pool[0],
+               SPI_TX_POOL_SIZE,
+               RT_IPC_FLAG_PRIO);
+
+    rt_mb_init(&rw007_wifi_device.eth_rx_mb,
+               "eth_rx",
+               &rw007_wifi_device.eth_rx_mb_pool[0],
+               SPI_TX_POOL_SIZE,
+               RT_IPC_FLAG_PRIO);
+
+    rt_mb_init(&rw007_wifi_device.rw007_cmd_mb,
+               "wifi_cmd",
+               &rw007_wifi_device.rw007_cmd_mb_pool[0],
+               sizeof(rw007_wifi_device.rw007_cmd_mb_pool) / 4,
+               RT_IPC_FLAG_PRIO);
+    rt_event_init(&spi_wifi_data_event, "wifi", RT_IPC_FLAG_FIFO);
+
+    spi_wifi_hw_init();
+
+    {
+        rt_thread_t tid;
+
+        tid = rt_thread_create("wifi",
+                               spi_wifi_data_thread_entry,
+                               RT_NULL,
+                               2048,
+                               RT_THREAD_PRIORITY_MAX - 2,
+                               20);
+
+        if (tid != RT_NULL)
+            rt_thread_startup(tid);
+    }
+
+    /* init: get mac address */
+    {
+        rw007_cmd_init init;
+        init.mode = mode;
+        LOG_D("wifi_control init");
+        rw007_wifi_control((rt_device_t)&rw007_wifi_device,
+                           RW007_CMD_INIT,
+                           (void *)&init); // 0: firmware, 1: STA, 2:AP
+    }
+
+    /* register eth device */
+    eth_device_init(&(rw007_wifi_device.parent), "w0");
+    eth_device_linkchange(&rw007_wifi_device.parent, RT_FALSE);
+
+    return RT_EOK;
+}
+
+void spi_wifi_isr(int vector)
+{
+    /* enter interrupt */
+    rt_interrupt_enter();
+
+    rt_event_send(&spi_wifi_data_event, 1);
+
+    /* leave interrupt */
+    rt_interrupt_leave();
+}
+
+/********************************* RW007 tools **************************************/
+rt_err_t rw007_join(const char *SSID, const char *passwd)
+{
+    rt_err_t result;
+    rt_device_t wifi_device;
+    rw007_cmd_easy_join easy_join;
+
+    wifi_device = rt_device_find("w0");
+    if (wifi_device == RT_NULL)
+        return -RT_ENOSYS;
+
+    strncpy(easy_join.ssid, SSID, sizeof(easy_join.ssid));
+    strncpy(easy_join.passwd, passwd, sizeof(easy_join.passwd));
+
+    result = rt_device_control(wifi_device,
+                               RW007_CMD_EASY_JOIN,
+                               (void *)&easy_join);
+
+    return result;
+}
+
+rt_err_t rw007_softap(const char *SSID, const char *passwd, uint32_t security, uint32_t channel)
+{
+    rt_err_t result;
+    rt_device_t wifi_device;
+    rw007_cmd_softap softap;
+
+    wifi_device = rt_device_find("w0");
+    if (wifi_device == RT_NULL)
+        return -RT_ENOSYS;
+
+    strncpy(softap.ssid, SSID, sizeof(softap.ssid));
+    strncpy(softap.passwd, passwd, sizeof(softap.passwd));
+
+    softap.security = security;
+    softap.channel = channel;
+    result = rt_device_control(wifi_device,
+                               RW007_CMD_SOFTAP,
+                               (void *)&softap);
+
+    return result;
+}
+
+int32_t rw007_rssi(void)
+{
+    rt_err_t result;
+    struct rw007_wifi *wifi_device;
+    rw007_cmd_rssi rssi_cmd;
+
+    wifi_device = (struct rw007_wifi *)rt_device_find("w0");
+
+    if (wifi_device == RT_NULL)
+        return 0;
+
+    if (wifi_device->active == 0)
+        return 0;
+
+    rt_memcpy(rssi_cmd.bssid, wifi_device->dev_addr, 6);
+
+    // SCAN
+    result = rt_device_control((rt_device_t)wifi_device,
+                               RW007_CMD_RSSI,
+                               &rssi_cmd);
+
+    if (result == RT_EOK)
+    {
+        rt_kprintf("rssi: %d\n", wifi_device->ap_info.rssi);
+        return wifi_device->ap_info.rssi;
+    }
+    else
+    {
+        rt_kprintf("rssi: error\n");
+    }
+
+    return (-1);
+}
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+
+static rt_err_t rw007_scan(void)
+{
+    rt_err_t result;
+    struct rw007_wifi *wifi_device;
+
+    wifi_device = (struct rw007_wifi *)rt_device_find("w0");
+
+    rt_kprintf("being scan \n");
+    result = rt_device_control((rt_device_t)wifi_device,
+                               RW007_CMD_SCAN,
+                               RT_NULL);
+
+    rt_kprintf("scan result:%d", result);
+
+    if (result == RT_EOK)
+    {
+        uint32_t i;
+        rw007_ap_info *ap_info;
+
+        for (i = 0; i < wifi_device->ap_scan_count; i++)
+        {
+            ap_info = &wifi_device->ap_scan[i];
+            rt_kprintf("AP #%02d SSID: %-32.32s\n", i, ap_info->ssid);
+        }
+    }
+
+    return result;
+}
+
+static int wifi_join(int argc, char *args[])
+{
+    if (argc != 3)
+        return -1;
+    return rw007_join(args[1], args[2]);
+}
+
+FINSH_FUNCTION_EXPORT(rw007_scan, SACN and list AP.);
+FINSH_FUNCTION_EXPORT(rw007_join, RW007 join to AP.);
+FINSH_FUNCTION_EXPORT(rw007_rssi, get RW007 current AP rssi.);
+
+MSH_CMD_EXPORT(wifi_join, wifi_join);
+MSH_CMD_EXPORT(rw007_rssi, rw007_rssi);
+MSH_CMD_EXPORT(rw007_scan, rw007_scan);
+#endif