ソースを参照

Merge branch 'master' into add_machine_lcd

SummerGift 6 年 前
コミット
374789cb93

+ 9 - 0
docs/07-Network_Module/02-network.md

@@ -0,0 +1,9 @@
+## network – 网络配置
+
+此模块提供网络驱动程序和路由配置。特定硬件的网络驱动程序在此模块中可用,用于配置硬件网络接口。然后,配置接口提供的网络服务可以通过 `usocket` 模块使用。
+
+### 专用的网络类配置
+
+下面具体的类实现了抽象网卡的接口,并提供了一种控制各种网络接口的方法。
+
+- [class WLAN – control built-in WiFi interfaces](./03-network-WLAN.md)

+ 109 - 0
docs/07-Network_Module/03-network-WLAN.md

@@ -0,0 +1,109 @@
+## class WLAN – 控制内置的 WiFi 网络接口
+
+该类为 WiFi 网络处理器提供一个驱动程序。使用示例:
+
+```python
+import network
+# enable station interface and connect to WiFi access point
+nic = network.WLAN(network.STA_IF)
+nic.active(True)
+nic.connect('your-ssid', 'your-password')
+# now use sockets as usual
+```
+
+### 构造函数
+
+在 RT-Thread MicroPython 中 `WLAN` 对象的构造函数如下:
+
+#### class network.WLAN(interface_id)
+
+创建一个 WLAN 网络接口对象。支持的接口是 ` network.STA_IF`(STA 模式,可以连接到上游的 WiFi 热点上) 和 `network.AP_IF`(AP 模式,允许其他 WiFi 客户端连接到自身的热点)。下面方法的可用性取决于接口的类型。例如,只有STA 接口可以使用 `WLAN.connect()`  方法连接到 AP 热点上。
+
+### 方法
+
+#### **WLAN.active**([is_active])
+
+如果向该方法传入布尔数值,传入 True 则使能卡,传入 False 则禁止网卡。否则,如果不传入参数,则查询当前网卡的状态。
+
+#### **WLAN.connect**(ssid, password)
+使用指定的账号和密码链接指定的无线热点。
+
+#### **WLAN.disconnect**()
+从当前链接的无线网络中断开。
+
+#### **WLAN.scan**()
+
+扫描当前可以连接的无线网络。
+
+只能在 STA 模式下进行扫描,使用元组列表的形式返回 WiFi 接入点的相关信息。
+
+(ssid, bssid, channel, rssi, authmode, hidden)
+
+#### **WLAN.status**([param])
+
+返回当前无线连接的状态。
+
+当调用该方法时没有附带参数,就会返回值描述当前网络连接的状态。如果还没有从热点连接中获得 IP 地址,此时的状态为 `STATION_IDLE`。如果已经从连接的无线网络中获得 IP 地址,此时的状态为 `STAT_GOT_IP`。
+
+当调用该函数使用的参数为 `rssi` 时,则返回 `rssi` 的值,该函数目前只支持这一个参数。
+
+#### **WLAN.isconnected**()
+
+在 STA 模式时,如果已经连接到 WiFi 网络,并且获得了 IP 地址,则返回 True。如果处在 AP 模式,此时已经与客户端建立连接,则返回 True。其他情况下都返回 False。
+
+#### WLAN.ifconfig([(ip, subnet, gateway, dns)])
+
+获取或者设置网络接口的参数,IP 地址,子网掩码,网关,DNS 服务器。当调用该方法不附带参数时,该方法会返回一个包含四个元素的元组来描述上面的信息。想要设置上面的值,传入一个包含上述四个元素的元组,例如:
+
+```
+nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
+```
+
+#### **WLAN.config**('param')
+
+#### WLAN.config(param=value, ...)
+
+获取或者设置一般网络接口参数,这些方法允许处理标准的 ip 配置之外的其他参数,如 `WLAN. ifconfig()` 函数处理的参数。这些参数包括特定网络和特定硬件的参数。对于参数的设置,应该使用关键字的语法,可以一次性设置多个参数。
+
+当查询参数时,参数名称的引用应该为字符串,且每次只能查询一个参数。
+
+```python
+# Set WiFi access point name (formally known as ESSID) and WiFi password
+ap.config(essid='My_AP', password="88888888")
+# Query params one by one
+print(ap.config('essid'))
+print(ap.config('channel'))
+```
+下面是目前支持的参数:
+
+| Parameter | Description                       |
+| --------- | --------------------------------- |
+| mac       | MAC address (bytes)               |
+| essid     | WiFi access point name (string)   |
+| channel   | WiFi channel (integer)            |
+| hidden    | Whether ESSID is hidden (boolean) |
+| password  | Access password (string)          |
+
+
+### 示例
+
+STA 模式下:
+
+```python
+import network
+wlan = network.WLAN(network.STA_IF)
+wlan.scan()
+wlan.connect("rtthread","02188888888")
+wlan.isconnected()
+```
+
+AP 模式下:
+
+```python
+import network
+ap = network.WLAN(network.AP_IF)
+ap.config(essid="hello_rt-thread", password="88888888")
+ap.active(True)
+ap.config("essid")
+```
+

+ 24 - 0
port/genhdr/qstrdefs.generated.h

@@ -697,6 +697,30 @@ QDEF(MP_QSTR_ffimod, (const byte*)"\xca\x06" "ffimod")
 QDEF(MP_QSTR_ffifunc, (const byte*)"\x92\x07" "ffifunc")
 QDEF(MP_QSTR_fficallback, (const byte*)"\xc5\x0b" "fficallback")
 QDEF(MP_QSTR_ffivar, (const byte*)"\x49\x06" "ffivar")
+QDEF(MP_QSTR_network, (const byte*)"\x5b\x07" "network")
+QDEF(MP_QSTR_isconnected, (const byte*)"\x80\x0b" "isconnected")
+QDEF(MP_QSTR_WLAN, (const byte*)"\x11\x04" "WLAN")
+QDEF(MP_QSTR_disconnect, (const byte*)"\xa5\x0a" "disconnect")
+QDEF(MP_QSTR_active, (const byte*)"\x69\x06" "active")
+QDEF(MP_QSTR_STA_IF, (const byte*)"\xb3\x06" "STA_IF")
+QDEF(MP_QSTR_AP_IF, (const byte*)"\x04\x05" "AP_IF")
+QDEF(MP_QSTR_bssid, (const byte*)"\x4a\x05" "bssid")
+QDEF(MP_QSTR_status, (const byte*)"\x71\x06" "status")
+QDEF(MP_QSTR_rssi, (const byte*)"\x7e\x04" "rssi")
+QDEF(MP_QSTR_config, (const byte*)"\x4f\x06" "config")
+QDEF(MP_QSTR_ifconfig, (const byte*)"\xe0\x08" "ifconfig")
+QDEF(MP_QSTR_mac, (const byte*)"\xaa\x03" "mac")
+QDEF(MP_QSTR_essid, (const byte*)"\x4d\x05" "essid")
+QDEF(MP_QSTR_hidden, (const byte*)"\xef\x06" "hidden")
+QDEF(MP_QSTR_authmode, (const byte*)"\xce\x08" "authmode")
+QDEF(MP_QSTR_channel, (const byte*)"\x26\x07" "channel")
+QDEF(MP_QSTR_dhcp_hostname, (const byte*)"\xa2\x0d" "dhcp_hostname")
+QDEF(MP_QSTR_STAT_GOT_IP, (const byte*)"\xb2\x0b" "STAT_GOT_IP")
+QDEF(MP_QSTR_STAT_CONNECT_FAIL, (const byte*)"\x0b\x11" "STAT_CONNECT_FAIL")
+QDEF(MP_QSTR_STAT_NO_AP_FOUND, (const byte*)"\xee\x10" "STAT_NO_AP_FOUND")
+QDEF(MP_QSTR_STAT_WRONG_PASSWORD, (const byte*)"\x0b\x13" "STAT_WRONG_PASSWORD")
+QDEF(MP_QSTR_STAT_CONNECTING, (const byte*)"\xf6\x0f" "STAT_CONNECTING")
+QDEF(MP_QSTR_STAT_IDLE, (const byte*)"\x0c\x09" "STAT_IDLE")
 QDEF(MP_QSTR_command, (const byte*)"\x02\x07" "command")
 QDEF(MP_QSTR_contrast, (const byte*)"\x07\x08" "contrast")
 QDEF(MP_QSTR_light, (const byte*)"\xfb\x05" "light")

+ 8 - 45
port/modnetwork.c

@@ -30,57 +30,20 @@
 
 #include "py/objlist.h"
 #include "py/runtime.h"
+#include "py/mphal.h"
+#include "lib/netutils/netutils.h"
 #include "modnetwork.h"
 
 #if MICROPY_PY_NETWORK
 
-/// \module network - network configuration
-///
-/// This module provides network drivers and routing configuration.
-
-void mod_network_init(void) {
-    mp_obj_list_init(&MP_STATE_PORT(mod_network_nic_list), 0);
-}
-
-void mod_network_register_nic(mp_obj_t nic) {
-    for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) {
-        if (MP_STATE_PORT(mod_network_nic_list).items[i] == nic) {
-            // nic already registered
-            return;
-        }
-    }
-    // nic not registered so add to list
-    mp_obj_list_append(&MP_STATE_PORT(mod_network_nic_list), nic);
-}
-
-mp_obj_t mod_network_find_nic(const uint8_t *ip) {
-    // find a NIC that is suited to given IP address
-    for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) {
-        mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i];
-        // TODO check IP suitability here
-        //mod_network_nic_type_t *nic_type = (mod_network_nic_type_t*)mp_obj_get_type(nic);
-        return nic;
-    }
-
-    nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "no available NIC"));
-}
-
-STATIC mp_obj_t network_route(void) {
-    return &MP_STATE_PORT(mod_network_nic_list);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_0(network_route_obj, network_route);
-
 STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
-
-    #if MICROPY_PY_WIZNET5K
-    { MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) },
-    #endif
-    #if MICROPY_PY_CC3K
-    { MP_ROM_QSTR(MP_QSTR_CC3K), MP_ROM_PTR(&mod_network_nic_type_cc3k) },
-    #endif
-
-    { MP_ROM_QSTR(MP_QSTR_route), MP_ROM_PTR(&network_route_obj) },
+    
+#if defined(MICROPY_PY_WLAN)
+    { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) },
+    { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(STATION_IF)},
+    { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(SOFTAP_IF)},
+#endif
 };
 
 STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table);

+ 7 - 54
port/modnetwork.h

@@ -23,61 +23,14 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#ifndef MICROPY_INCLUDED_STMHAL_MODNETWORK_H
-#define MICROPY_INCLUDED_STMHAL_MODNETWORK_H
+#ifndef MICROPY_INCLUDED_MODNETWORK_H
+#define MICROPY_INCLUDED_MODNETWORK_H
 
-#define MOD_NETWORK_IPADDR_BUF_SIZE (4)
+#define STATION_IF   0
+#define SOFTAP_IF    1
 
-#define MOD_NETWORK_AF_INET (2)
-#define MOD_NETWORK_AF_INET6 (10)
+#define MODNETWORK_INCLUDE_CONSTANTS (1)
 
-#define MOD_NETWORK_SOCK_STREAM (1)
-#define MOD_NETWORK_SOCK_DGRAM (2)
-#define MOD_NETWORK_SOCK_RAW (3)
+MP_DECLARE_CONST_FUN_OBJ_KW(get_wlan_obj);
 
-struct _mod_network_socket_obj_t;
-
-typedef struct _mod_network_nic_type_t {
-    mp_obj_type_t base;
-
-    // API for non-socket operations
-    int (*gethostbyname)(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *ip_out);
-
-    // API for socket operations; return -1 on error
-    int (*socket)(struct _mod_network_socket_obj_t *socket, int *_errno);
-    void (*close)(struct _mod_network_socket_obj_t *socket);
-    int (*bind)(struct _mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno);
-    int (*listen)(struct _mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno);
-    int (*accept)(struct _mod_network_socket_obj_t *socket, struct _mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno);
-    int (*connect)(struct _mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno);
-    mp_uint_t (*send)(struct _mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno);
-    mp_uint_t (*recv)(struct _mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno);
-    mp_uint_t (*sendto)(struct _mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno);
-    mp_uint_t (*recvfrom)(struct _mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno);
-    int (*setsockopt)(struct _mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno);
-    int (*settimeout)(struct _mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno);
-    int (*ioctl)(struct _mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno);
-} mod_network_nic_type_t;
-
-typedef struct _mod_network_socket_obj_t {
-    mp_obj_base_t base;
-    mp_obj_t nic;
-    mod_network_nic_type_t *nic_type;
-    union {
-        struct {
-            uint8_t domain;
-            uint8_t type;
-            int8_t fileno;
-        } u_param;
-        mp_uint_t u_state;
-    };
-} mod_network_socket_obj_t;
-
-extern const mod_network_nic_type_t mod_network_nic_type_wiznet5k;
-extern const mod_network_nic_type_t mod_network_nic_type_cc3k;
-
-void mod_network_init(void);
-void mod_network_register_nic(mp_obj_t nic);
-mp_obj_t mod_network_find_nic(const uint8_t *ip);
-
-#endif // MICROPY_INCLUDED_STMHAL_MODNETWORK_H
+#endif // MICROPY_INCLUDED_MODNETWORK_H

+ 16 - 0
port/mpconfigport.h

@@ -235,6 +235,14 @@
 #define MICROPY_SSL_MBEDTLS         (1)
 #endif
 
+#ifdef MICROPYTHON_USING_NETWORK
+#define MICROPY_PY_NETWORK          (1)
+#endif
+
+#ifdef MICROPYTHON_USING_WLAN
+#define MICROPY_PY_WLAN             (1)
+#endif
+
 #if MICROPY_PY_THREAD
 #define MICROPY_EVENT_POLL_HOOK \
     do { \
@@ -323,6 +331,7 @@ extern const struct _mp_obj_module_t mp_module_usocket;
 extern const struct _mp_obj_module_t mp_module_io;
 extern const struct _mp_obj_fun_builtin_fixed_t machine_soft_reset_obj;
 extern const struct _mp_obj_module_t mp_module_ffi;
+extern const struct _mp_obj_module_t mp_module_network;
 
 #if MICROPY_PY_RTTHREAD
 #define RTTHREAD_PORT_BUILTIN_MODULES { MP_ROM_QSTR(MP_QSTR_rtthread), MP_ROM_PTR(&mp_module_rtthread) },
@@ -441,6 +450,12 @@ extern const struct _mp_obj_module_t mp_module_ffi;
 #define MODFFI_PORT_BUILTIN_MODULES
 #endif
 
+#if MICROPY_PY_NETWORK
+#define MODNETWORK_PORT_BUILTIN_MODULES                    { MP_ROM_QSTR(MP_QSTR_network), MP_ROM_PTR(&mp_module_network) },
+#else
+#define MODNETWORK_PORT_BUILTIN_MODULES
+#endif
+
 // extra built in names to add to the global namespace
 #define MICROPY_PORT_BUILTINS \
     { MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&machine_soft_reset_obj) }, \
@@ -455,6 +470,7 @@ extern const struct _mp_obj_module_t mp_module_ffi;
     SOCKET_PORT_BUILTIN_MODULES \
     MODUTIME_PORT_BUILTIN_MODULES \
     MODFFI_PORT_BUILTIN_MODULES \
+    MODNETWORK_PORT_BUILTIN_MODULES \
 
 #define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \
     MODUTIME_PORT_BUILTIN_MODULE_WEAK_LINKS \

+ 575 - 0
port/network_wlan.c

@@ -0,0 +1,575 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 SummerGift <SummerGift@qq.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "lib/netutils/netutils.h"
+
+#if MICROPY_PY_WLAN
+#include <rtthread.h>
+#include <wlan_mgnt.h>
+#include <wlan_cfg.h>
+#include <wlan_prot.h>
+#include <arpa/inet.h>
+#include <netdev.h>     
+#include "modnetwork.h"
+
+extern struct netdev *netdev_default;
+
+typedef struct _wlan_if_obj_t {
+    mp_obj_base_t base;
+    int if_id;
+} wlan_if_obj_t;
+
+enum {
+    STATION_IDLE = 0,
+    STATION_CONNECTING,
+    STATION_WRONG_PASSWORD,
+    STATION_NO_AP_FOUND,
+    STATION_CONNECT_FAIL,
+    STATION_GOT_IP,
+};
+
+const mp_obj_type_t wlan_if_type;
+STATIC struct rt_wlan_info _ap_info;
+STATIC char _ap_password[RT_WLAN_PASSWORD_MAX_LENGTH];
+
+STATIC void error_check(bool status, const char *msg) {
+    if (!status) {
+        nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, msg));
+    }
+}
+
+STATIC const wlan_if_obj_t wlan_objs[] = {
+    {{&wlan_if_type}, STATION_IF},
+    {{&wlan_if_type}, SOFTAP_IF},
+};
+
+STATIC void require_if(mp_obj_t wlan_if, int if_no) {
+    wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if);
+    if (self->if_id != if_no) {
+        error_check(false, if_no == STATION_IF ? "STA required" : "AP required");
+    }
+}
+
+STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) {
+    int idx = 0;
+    if (n_args > 0) {
+        idx = mp_obj_get_int(args[0]);
+        if (idx < 0 || idx >= sizeof(wlan_objs)) {
+            mp_raise_ValueError(NULL);
+        }
+    }
+    return MP_OBJ_FROM_PTR(&wlan_objs[idx]);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan);
+
+STATIC mp_obj_t wlan_active(size_t n_args, const mp_obj_t *args) {
+
+    wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+    if (n_args > 1) {
+
+        if (self->if_id == STATION_IF)
+        {
+            if (mp_obj_get_int(args[1]) == RT_TRUE)
+            {
+                error_check(netdev_set_up(netdev_default) == RT_EOK, "Cannot active wlan device");
+            }
+            else
+            {
+                error_check(netdev_set_down(netdev_default) == RT_EOK, "Cannot disable wlan device");
+            }
+        }
+        else
+        {
+            if (mp_obj_get_int(args[1]) == RT_TRUE)
+            {
+                error_check(rt_wlan_start_ap((char *)&_ap_info.ssid.val, _ap_password) == RT_EOK, "Cannot start AP");
+            }
+            else
+            {
+                error_check(rt_wlan_ap_stop() == RT_EOK, "Cannot stop AP");
+            }
+        }
+
+        return mp_const_none;
+    }
+
+    if (self->if_id == STATION_IF)
+    {
+        return mp_obj_new_bool(rt_wlan_get_mode("wlan0") == RT_WLAN_STATION);
+    }
+    else
+    {
+        return mp_obj_new_bool(rt_wlan_get_mode("wlan1") == RT_WLAN_AP);
+    }
+    
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_active_obj, 1, 2, wlan_active);
+
+STATIC mp_obj_t wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+    enum { ARG_ssid, ARG_password, ARG_bssid };
+    static const mp_arg_t allowed_args[] = {
+        { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+        { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+        { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+    };
+
+    // parse args
+    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+    require_if(pos_args[0], STATION_IF);
+    
+    const char *ssid = RT_NULL;
+    const char *key = RT_NULL;
+    size_t len;
+    const char *p;
+
+    // set parameters based on given args
+    if (args[ARG_ssid].u_obj != mp_const_none) {
+        p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len);
+        ssid = p;
+    }
+
+    if (args[ARG_password].u_obj != mp_const_none) {
+        p = mp_obj_str_get_data(args[ARG_password].u_obj, &len);
+        key = p;
+    }
+
+    error_check(rt_wlan_connect(ssid, key) == RT_EOK, "Cannot connect to AP");
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_connect_obj, 1, wlan_connect);
+
+STATIC mp_obj_t wlan_disconnect(mp_obj_t self_in) {
+    require_if(self_in, STATION_IF);
+    error_check(rt_wlan_disconnect() == RT_EOK, "Cannot disconnect from AP");
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_disconnect_obj, wlan_disconnect);
+
+STATIC mp_obj_t wlan_status(size_t n_args, const mp_obj_t *args) {
+    wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    if (n_args == 1) {
+        // Get link status
+        if (self->if_id == STATION_IF) {
+            
+            if(rt_wlan_is_ready() == RT_EOK)
+            {
+                return MP_OBJ_NEW_SMALL_INT(STATION_GOT_IP);
+            }
+            else
+            {
+                return MP_OBJ_NEW_SMALL_INT(STATION_IDLE);
+            }
+        }
+        return MP_OBJ_NEW_SMALL_INT(-1);
+    } else {
+        // Get specific status parameter
+        switch (mp_obj_str_get_qstr(args[1])) {
+            case MP_QSTR_rssi:
+                if (self->if_id == STATION_IF) {
+                    return MP_OBJ_NEW_SMALL_INT(rt_wlan_get_rssi());
+                }
+        }
+        mp_raise_ValueError("unknown status param");
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_status_obj, 1, 2, wlan_status);
+
+STATIC mp_obj_t *wlan_scan_list = NULL;
+
+void wlan_station_scan(void)
+{
+    if (wlan_scan_list == NULL) {
+        // called unexpectedly
+        return;
+    }
+    
+    struct rt_wlan_scan_result *scan_result = RT_NULL;
+
+    /* scan ap info */
+    scan_result = rt_wlan_scan_sync();
+    if (scan_result)
+    {
+        int index, num;
+        char *security;
+
+        num = scan_result->num;
+        for (index = 0; index < num; index ++)
+        {
+            switch (scan_result->info[index].security)
+            {
+            case SECURITY_OPEN:
+                security = "OPEN";
+                break;
+            case SECURITY_WEP_PSK:
+                security = "WEP_PSK";
+                break;
+            case SECURITY_WEP_SHARED:
+                security = "WEP_SHARED";
+                break;
+            case SECURITY_WPA_TKIP_PSK:
+                security = "WPA_TKIP_PSK";
+                break;
+            case SECURITY_WPA_AES_PSK:
+                security = "WPA_AES_PSK";
+                break;
+            case SECURITY_WPA2_AES_PSK:
+                security = "WPA2_AES_PSK";
+                break;
+            case SECURITY_WPA2_TKIP_PSK:
+                security = "WPA2_TKIP_PSK";
+                break;
+            case SECURITY_WPA2_MIXED_PSK:
+                security = "WPA2_MIXED_PSK";
+                break;
+            case SECURITY_WPS_OPEN:
+                security = "WPS_OPEN";
+                break;
+            case SECURITY_WPS_SECURE:
+                security = "WPS_SECURE";
+                break;
+            default:
+                security = "UNKNOWN";
+                break;
+            }
+
+            mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL);
+            t->items[0] = mp_obj_new_bytes(&scan_result->info[index].ssid.val[0], strlen((char *)(&scan_result->info[index].ssid.val[0])));
+            t->items[1] = mp_obj_new_bytes(&scan_result->info[index].bssid[0], strlen((char *)(&scan_result->info[index].bssid[0])));
+            t->items[2] = MP_OBJ_NEW_SMALL_INT(scan_result->info[index].channel);
+            t->items[3] = MP_OBJ_NEW_SMALL_INT(scan_result->info[index].rssi);
+            t->items[4] = mp_obj_new_bytes((const byte *)security, strlen(security));
+            t->items[5] = MP_OBJ_NEW_SMALL_INT(scan_result->info[index].hidden);
+            
+            mp_obj_list_append(*wlan_scan_list, MP_OBJ_FROM_PTR(t));
+
+        }
+        rt_wlan_scan_result_clean();
+    }
+    else
+    {
+        rt_kprintf("wifi scan result is null\n");
+        *wlan_scan_list = MP_OBJ_NULL;
+    }
+}
+
+STATIC mp_obj_t wlan_scan(mp_obj_t self_in) {
+    require_if(self_in, STATION_IF);
+
+    mp_obj_t list = mp_obj_new_list(0, NULL);
+    wlan_scan_list = &list;
+    wlan_station_scan();
+
+    if (list == MP_OBJ_NULL) {
+        nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "scan failed"));
+    }
+    return list;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_scan_obj, wlan_scan);
+
+/// \method isconnected()
+/// Return True if connected to an AP and an IP address has been assigned,
+/// false otherwise.
+STATIC mp_obj_t wlan_isconnected(mp_obj_t self_in) {
+    wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    if (self->if_id == STATION_IF) {
+        if (rt_wlan_is_connected() == RT_TRUE) {
+            return mp_const_true;
+        }
+    } else {
+        if (rt_wlan_ap_get_sta_num() > 0) {
+            return mp_const_true;
+        }
+    }
+    return mp_const_false;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wlan_isconnected_obj, wlan_isconnected);
+
+STATIC mp_obj_t wlan_ifconfig(size_t n_args, const mp_obj_t *args) {
+    wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    
+    struct netdev *netdev = netdev_default;
+    if (netdev == RT_NULL)
+    {
+        rt_kprintf("not find wlan interface device.\n");
+        return MP_OBJ_NEW_SMALL_INT(-1);
+    }
+
+    if (n_args == 1) {
+        // get
+        mp_obj_t tuple[4] = {
+            mp_obj_new_str((const char *)inet_ntoa(netdev->ip_addr), strlen((char *)(inet_ntoa(netdev->ip_addr)))),
+            mp_obj_new_str((const char *)inet_ntoa(netdev->netmask), strlen((char *)(inet_ntoa(netdev->netmask)))),
+            mp_obj_new_str((const char *)inet_ntoa(netdev->gw), strlen((char *)(inet_ntoa(netdev->gw)))),
+            mp_obj_new_str((const char *)inet_ntoa(netdev->dns_servers), strlen((char *)(inet_ntoa(netdev->dns_servers)))),
+        };
+        return mp_obj_new_tuple(4, tuple);
+    } 
+    else 
+    {
+        // set
+        mp_obj_t *items;
+        bool restart_dhcp_server = false;
+
+        uint8_t ip_addr[4];
+        uint8_t netmask[4];
+        uint8_t gw[4];
+        uint8_t dns_server[4];
+        
+        mp_obj_get_array_fixed_n(args[1], 4, &items);
+
+        netutils_parse_ipv4_addr(items[0], (uint8_t *)ip_addr,    NETUTILS_BIG);
+        netutils_parse_ipv4_addr(items[1], (uint8_t *)netmask,    NETUTILS_BIG);
+        netutils_parse_ipv4_addr(items[2], (uint8_t *)gw     ,    NETUTILS_BIG);
+        netutils_parse_ipv4_addr(items[3], (uint8_t *)dns_server, NETUTILS_BIG);
+
+        // To set a static IP we have to disable DHCP first
+        if (self->if_id == STATION_IF) {
+            if(netdev_dhcp_enabled(netdev, 0) == RT_EOK)
+            {
+                if (netdev_set_ipaddr(netdev, (const ip_addr_t *)ip_addr) != RT_EOK)
+                {
+                    nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "netdev_set_ipaddr() failed"));         
+                }
+            }
+            else
+            {
+                nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "netdev_dhcp_enabled() failed"));  
+            }
+        }
+        else 
+        {
+            // TODO modify IP netmask gw under AP mode
+            netdev_set_dns_server(netdev, 0, (const ip_addr_t *)dns_server);
+            return mp_const_none;
+        }
+
+        netdev_set_netmask(netdev, (const ip_addr_t *)netmask);
+        netdev_set_gw(netdev, (const ip_addr_t *)gw);
+        netdev_set_dns_server(netdev, 0, (const ip_addr_t *)dns_server);
+    }
+    
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_ifconfig_obj, 1, 2, wlan_ifconfig);
+
+STATIC mp_obj_t wlan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+    if (n_args != 1 && kwargs->used != 0) {
+        mp_raise_TypeError("either pos or kw args are allowed");
+    }
+
+    wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+    struct rt_wlan_info cfg = {0};
+
+    if (self->if_id == STATION_IF) {
+        error_check(rt_wlan_get_info(&cfg) == RT_EOK, "can't get STA config");
+    } else {
+        error_check(rt_wlan_ap_get_info(&cfg) == RT_EOK, "can't get AP config");
+    }
+
+    int req_if = -1;
+
+    if (kwargs->used != 0) {
+
+        for (mp_uint_t i = 0; i < kwargs->alloc; i++) {
+            if (mp_map_slot_is_filled(kwargs, i)) {
+                #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
+                switch ((uintptr_t)kwargs->table[i].key) {
+                    case QS(MP_QSTR_mac): {
+                        mp_buffer_info_t bufinfo;
+                        mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ);
+                        if (bufinfo.len != 6) {
+                            mp_raise_ValueError("invalid buffer length");
+                        }
+                        error_check(rt_wlan_set_mac((rt_uint8_t *)bufinfo.buf) == RT_EOK, "can't set MAC");
+
+                        break;
+                    }
+                    case QS(MP_QSTR_essid): { 
+                        req_if = SOFTAP_IF;
+                        size_t len;
+                        const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
+                        len = MIN(len, sizeof(_ap_info.ssid.val));
+                        memcpy(_ap_info.ssid.val, s, len);
+                        _ap_info.ssid.len = len;
+                        break;
+                    }
+                    case QS(MP_QSTR_hidden): {
+                        req_if = SOFTAP_IF;
+                        _ap_info.hidden = mp_obj_is_true(kwargs->table[i].value);
+                        break;
+                    }
+//                    case QS(MP_QSTR_authmode): {
+//                        req_if = SOFTAP_IF;
+//                        cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value);
+//                        break;
+//                    }
+                    case QS(MP_QSTR_password): {
+                        req_if = SOFTAP_IF;
+                        size_t len;
+                        const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
+                        len = MIN(len, sizeof(_ap_password) - 1);
+                        memcpy(_ap_password, s, len);
+                        _ap_password[len] = 0;
+                        break;
+                    }
+                    case QS(MP_QSTR_channel): {
+                        req_if = SOFTAP_IF;
+                        _ap_info.channel = mp_obj_get_int(kwargs->table[i].value);
+                        break;
+                    }
+//                    case QS(MP_QSTR_dhcp_hostname): {
+//                        req_if = STATION_IF;
+//                        if (self->if_id == STATION_IF) {
+//                            const char *s = mp_obj_str_get_str(kwargs->table[i].value);
+//                            wifi_station_set_hostname((char*)s);
+//                        }
+//                        break;
+//                    }
+                    default:
+                        goto unknown;
+                }
+                #undef QS
+            }
+        }
+
+        // We post-check interface requirements to save on code size
+        if (req_if >= 0) {
+            require_if(args[0], req_if);
+        }
+
+        return mp_const_none;
+    }
+
+    // Get config
+    if (n_args != 2) {
+        mp_raise_TypeError("can query only one param");
+    }
+
+    mp_obj_t val;
+
+    qstr key = mp_obj_str_get_qstr(args[1]);
+    switch (key) {
+        case MP_QSTR_mac: {
+            uint8_t mac[6];
+            error_check(rt_wlan_get_mac(mac) == RT_EOK, "can't get mac config");
+            return mp_obj_new_bytes(mac, sizeof(mac));
+        }
+        case MP_QSTR_essid:
+            if (self->if_id == STATION_IF) {
+                val = mp_obj_new_str((char*)cfg.ssid.val, strlen((char*)cfg.ssid.val));
+            } else {
+                val = mp_obj_new_str((char*)_ap_info.ssid.val, _ap_info.ssid.len);
+            }
+            break;
+        case MP_QSTR_hidden:
+            req_if = SOFTAP_IF;
+            val = mp_obj_new_bool(cfg.hidden);
+            break;
+//        case MP_QSTR_authmode:
+//            req_if = SOFTAP_IF;
+//            val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode);
+//            break;
+        case MP_QSTR_channel:
+            req_if = SOFTAP_IF;
+            val = MP_OBJ_NEW_SMALL_INT(cfg.channel);
+            break;
+//        case MP_QSTR_dhcp_hostname: {
+//            req_if = STATION_IF;
+//            char* s = wifi_station_get_hostname();
+//            if (s == NULL) {
+//                val = MP_OBJ_NEW_QSTR(MP_QSTR_);
+//            } else {
+//                val = mp_obj_new_str(s, strlen(s));
+//            }
+//            break;
+//        }
+        default:
+            goto unknown;
+    }
+
+    // We post-check interface requirements to save on code size
+    if (req_if >= 0) {
+        require_if(args[0], req_if);
+    }
+
+    return val;
+
+unknown:
+    mp_raise_ValueError("unknown config param");
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_config_obj, 1, wlan_config);
+
+STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = {
+    { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&wlan_active_obj) },
+    { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&wlan_connect_obj) },
+    { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&wlan_disconnect_obj) },
+    { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&wlan_status_obj) },
+    { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&wlan_scan_obj) },
+    { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&wlan_isconnected_obj) },
+    { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&wlan_config_obj) },
+    { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&wlan_ifconfig_obj) },
+    
+#if MODNETWORK_INCLUDE_CONSTANTS
+    { MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(STATION_IDLE)},
+    { MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(STATION_CONNECTING)},
+    { MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(STATION_WRONG_PASSWORD)},
+    { MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(STATION_NO_AP_FOUND)},
+    { MP_ROM_QSTR(MP_QSTR_STAT_CONNECT_FAIL), MP_ROM_INT(STATION_CONNECT_FAIL)},
+    { MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(STATION_GOT_IP)},
+
+//    { MP_ROM_QSTR(MP_QSTR_MODE_11B), MP_ROM_INT(PHY_MODE_11B) },
+//    { MP_ROM_QSTR(MP_QSTR_MODE_11G), MP_ROM_INT(PHY_MODE_11G) },
+//    { MP_ROM_QSTR(MP_QSTR_MODE_11N), MP_ROM_INT(PHY_MODE_11N) },
+
+//    { MP_ROM_QSTR(MP_QSTR_AUTH_OPEN), MP_ROM_INT(AUTH_OPEN) },
+//    { MP_ROM_QSTR(MP_QSTR_AUTH_WEP), MP_ROM_INT(AUTH_WEP) },
+//    { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_PSK), MP_ROM_INT(AUTH_WPA_PSK) },
+//    { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(AUTH_WPA2_PSK) },
+//    { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(AUTH_WPA_WPA2_PSK) },
+#endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table);
+
+const mp_obj_type_t wlan_if_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_WLAN,
+    .locals_dict = (mp_obj_dict_t*)&wlan_if_locals_dict,
+};
+
+#endif