AP 配网指南

更新时间:2022-11-24 09:20:24下载pdf

本文详细介绍使用综合 SDK 如何实现 AP 配网功能,我们将会实现通过 AP 配网方式来激活网关设备。

背景信息

AP 配网也称 热点配网。其工作原理是,设备处于热点模式,手机连接设备的热点,使得手机和设备处于同一局域网中,手机把令牌、路由器的 SSID 和密码等信息加密后在局域网内广播。

设备收到广播包后解析并解密,获取路由器的 SSID 和密码,切换到 Station 模式去连接路由器,连接成功后向云端发起激活请求,完成激活流程。

实现

SDK 已经实现 AP 配网的底层逻辑,定义了一套无线适配接口,应用只需要完成接口适配即可。

AP 配网的交互流程示意图:

AP 配网指南

接下来,我们一步步来完成 AP 配网的适配工作。

本示例仅供参考,要求开发者理解其实现逻辑。本示例代码适配的是 Realtek RTL8197F 平台,不同芯片或不同系统无线相关的操作可能都存在差异。为了方便演示,本示例代码不考虑性能,直接使用 Shell 命令操作。

  1. 在 SDK 初始化时指定无线配网方式为仅支持 AP 配网。

    // ...
    
    int main(int argc, char **argv)
    {
        // ...
    #if defined(GW_SUPPORT_WIRED_WIFI) && (GW_SUPPORT_WIRED_WIFI==1)
        TUYA_CALL_ERR_RETURN(tuya_iot_wired_wf_sdk_init(IOT_GW_NET_WIRED_WIFI, GWCM_OLD, WF_START_AP_ONLY, PID, USER_SW_VER, NULL, 0));
    #elif defined(WIFI_GW) && (WIFI_GW==1)
        TUYA_CALL_ERR_RETURN(tuya_iot_wf_sdk_init(GWCM_OLD, WF_START_AP_ONLY, PID, USER_SW_VER, NULL, 0));
    #else
        // 有线 SDK,不支持无线配网
        return OPRT_COM_ERROR;
    #endif
        // ...
    }
    
  2. 适配获取 MAC 地址接口,实现获取无线接口 MAC 地址。

    OPERATE_RET tuya_adapter_wifi_get_mac(CONST WF_IF_E wf, NW_MAC_S *mac)
    {
        CHAR_T buf[256] = {0};
        CHAR_T *pstart = NULL;
        FILE *fp = NULL;
    
        fp = popen("ifconfig " WLAN_DEV, "r");
        if (fp == NULL) {
            return OPRT_COM_ERROR;
        }
    
        while (fgets(buf, SIZEOF(buf), fp) != NULL) {
            pstart = strstr(buf, "HWaddr ");
            if (pstart != NULL) {
                INT_T x1, x2, x3, x4, x5, x6;
                sscanf(pstart + strlen("HWaddr "), "%x:%x:%x:%x:%x:%x", &x1, &x2, &x3, &x4, &x5, &x6);
                mac->mac[0] = x1 & 0xFF;
                mac->mac[1] = x2 & 0xFF;
                mac->mac[2] = x3 & 0xFF;
                mac->mac[3] = x4 & 0xFF;
                mac->mac[4] = x5 & 0xFF;
                mac->mac[5] = x6 & 0xFF;
                break;
            }
        }
    
        pclose(fp);
    
        PR_DEBUG("MAC Addr: %02X-%02X-%02X-%02X-%02X-%02X", mac->mac[0], mac->mac[1], mac->mac[2], mac->mac[3], mac->mac[4], mac->mac[5]);
    
        return OPRT_OK;
    }
    
  3. 适配设置无线模式接口,根据参数把无线设置到对应的模式。AP 配网过程,设备先工作在 AP 模式,待获取到路由器的 SSID 和密码后切换到 Station 模式连接路由器,SDK 使用该接口切换模式。

    OPERATE_RET tuya_adapter_wifi_set_work_mode(CONST WF_WK_MD_E mode)
    {
        switch (mode) {
            case WWM_STATION:
            {
                system("iwpriv " WLAN_DEV " set_mib opmode=0x8");
                break;
            }
            case WWM_SOFTAP:
            {
                system("iwpriv " WLAN_DEV " set_mib opmode=0x10");
                break;
            }
            default:
            {
                break;
            }
        }
    
        return OPRT_OK;
    }
    
  4. 适配开启 AP 接口,根据参数设置并开启 AP。当无线配网模式为 AP 配网时,设备未激活且还没有获取到路由器的 SSID 和密码,应用启动后 SDK 使用该接口启动 AP。

    OPERATE_RET tuya_adapter_wifi_ap_start(CONST WF_AP_CFG_IF_S *cfg)
    {
        CHAR_T cmd_buf[128] = {0};
    
        system("ifconfig " WLAN_DEV " down");
    
        system("iwpriv " WLAN_DEV " set_mib opmode=0x10");
        system("iwpriv " WLAN_DEV " set_mib band=11");
        system("iwpriv " WLAN_DEV " set_mib deny_legacy=0");
        system("iwpriv " WLAN_DEV " set_mib use_40M=1");
        system("iwpriv " WLAN_DEV " set_mib 802_1x=0");
        snprintf(cmd_buf, SIZEOF(cmd_buf), "iwpriv %s set_mib ssid=\"%s\"", WLAN_DEV, cfg->ssid);
        system(cmd_buf);
    
        if (cfg->p_len > 0) {
            system("iwpriv " WLAN_DEV " set_mib authtype=2");
            system("iwpriv " WLAN_DEV " set_mib psk_enable=3");
            system("iwpriv " WLAN_DEV " set_mib encmode=2");
            system("iwpriv " WLAN_DEV " set_mib wpa2_cipher=10");
            system("iwpriv " WLAN_DEV " set_mib wpa_cipher=10");
            snprintf(cmd_buf, SIZEOF(cmd_buf), "iwpriv %s set_mib passphrase=\"%s\"", WLAN_DEV, cfg->passwd);
            system(cmd_buf);
        } else {
            system("iwpriv " WLAN_DEV " set_mib authtype=0");
            system("iwpriv " WLAN_DEV " set_mib encmode=0");
        }
    
        /**
         * 开启 udhcpd 服务,给 Client 分配 IP 地址
         */ 
        system("ifconfig " WLAN_DEV " " AP_DEFAULT_IP);
        system("killall udhcpd");
        system("udhcpd /tmp/tuya/udhcpd.conf");
    
        return OPRT_OK;
    }
    
  5. 适配获取无线模式接口,返回无线接口的当前模式。

    OPERATE_RET tuya_adapter_wifi_get_work_mode(WF_WK_MD_E *mode)
    {
        CHAR_T buf[256] = {0};
        CHAR_T *pstart = NULL;
        CHAR_T tmp[16] = {0};
        FILE *fp = NULL;
    
        fp = popen("iwconfig " WLAN_DEV, "r");
        if (fp == NULL) {
            return OPRT_COM_ERROR;
        }
    
        while (fgets(buf, SIZEOF(buf), fp) != NULL) {
            pstart = strstr(buf, "Mode:");
            if (pstart != NULL) {
                sscanf(pstart + strlen("Mode:"), "%s ", tmp);
                break;
            }
        }
        pclose(fp);
    
        if (!strncasecmp(tmp, "Managed", strlen("Managed"))) {
            *mode = WWM_STATION;
        } else if (!strncasecmp(tmp, "Master", strlen("Master"))) {
            *mode = WWM_SOFTAP;
        }  else {
            *mode = WWM_UNKNOWN;
        }
    
        return OPRT_OK;
    }
    
  6. 适配关闭 AP 接口,在接口实现关闭 AP 功能。SDK 接收到路由器的 SSID 和密码后,使用该接口关闭 AP。

    OPERATE_RET tuya_adapter_wifi_ap_stop(VOID_T)
    {
        system("ifconfig " WLAN_DEV " down");
        system("killall udhcpd");
    
        return OPRT_OK;
    }
    
  7. 适配连接路由器接口,实现连接路由器功能。SDK 已经成功获取到路由器的 SSID 和密码,使用该接口连接路由器。

    OPERATE_RET tuya_adapter_wifi_station_connect(CONST SCHAR_T *ssid, CONST SCHAR_T *passwd)
    {
        CHAR_T cmd_buf[128] = {0};
    
        /**
         * 关闭 udhcpd 服务
         */
        system("killall udhcpd");
     
        system("ifconfig " WLAN_DEV " down");
    
        system("iwpriv " WLAN_DEV " set_mib opmode=0x8");
        system("iwpriv " WLAN_DEV " set_mib band=11");
        system("iwpriv " WLAN_DEV " set_mib deny_legacy=0");
        system("iwpriv " WLAN_DEV " set_mib use40M=1");
        system("iwpriv " WLAN_DEV " set_mib 802_1x=0");
        snprintf(cmd_buf, SIZEOF(cmd_buf), "iwpriv %s set_mib ssid=\"%s\"", WLAN_DEV, ssid);
        system(cmd_buf);
       
        if (!passwd || (strlen(passwd) == 0)) {
            system("iwpriv " WLAN_DEV " set_mib authtype=0");
            system("iwpriv " WLAN_DEV " set_mib encmode=0");
        } else {
            system("iwpriv " WLAN_DEV " set_mib authtype=2");
            system("iwpriv " WLAN_DEV " set_mib psk_enable=3");
            system("iwpriv " WLAN_DEV " set_mib encmode=2");
            system("iwpriv " WLAN_DEV " set_mib wpa2_cipher=10");
            system("iwpriv " WLAN_DEV " set_mib wpa_cipher=10");
            snprintf(cmd_buf, SIZEOF(cmd_buf), "iwpriv %s set_mib passphrase=\"%s\"", WLAN_DEV, passwd);
            system(cmd_buf);
        }
        
        system("ifconfig " WLAN_DEV " up");
    
        system("ps | grep 'udhcpc -i wlan0' | grep -v grep | awk '{print $1}' | xargs kill -9");    
        system("ps | grep 'udhcpc -b -i wlan0' | grep -v grep | awk '{print $1}' | xargs kill -9");
        system("busybox udhcpc -b -i wlan0 -A 3 -T 3 -s /tmp/tuya/8197wlan0_udhcpc.script&");
    
        return OPRT_OK;
    }
    
  8. 适配获取无线 IP 地址接口,实现获取无线接口的 IP 地址,用于局域网通讯。

    OPERATE_RET tuya_adapter_wifi_get_ip(CONST WF_IF_E wf, NW_IP_S *ip)
    {
        CHAR_T buf[256] = {0};
        CHAR_T *pstart = NULL;
        FILE *fp = NULL;
        
        fp = popen("ifconfig " WLAN_DEV, "r");
        if (fp == NULL) {
            return OPRT_COM_ERROR;
        }
    
        while (fgets(buf, SIZEOF(buf), fp) != NULL) {
            pstart = strstr(buf, "inet ");
            if (pstart != NULL) {
                break;
            }
        }
    
        pclose(fp);
    
        pstart = strstr(buf, "inet addr:");
        if (pstart == NULL) {    
            return OPRT_COM_ERROR;
        }
        sscanf(pstart + strlen("inet addr:"), "%s", ip->ip);
    
        if (wf == WF_STATION) {
            /**
             * 避免获取到的是默认 IP 地址
             */
            if (!strncmp(ip->ip, AP_DEFAULT_IP, SIZEOF(ip->ip))) {
                PR_TRACE("%s is default ip of AP", ip->ip);
                return OPRT_COM_ERROR;
            }
        }
    
        PR_TRACE("IP Addr: %s", ip->ip);
    
        return OPRT_OK;
    }
    
  9. 适配获取无线状态接口,实现获取 Station 的连接状态功能。连接路由器后,SDK 会定时获取无线的连接状态,用来判断网络的状态,以 WSS_GOT_IP 状态为判断标准。

    OPERATE_RET tuya_adapter_wifi_station_get_status(WF_STATION_STAT_E *stat)
    {
        NW_IP_S ip = {0};
    
        if (stat == NULL) {
            PR_ERR("invalid param");
            return OPRT_INVALID_PARM;
        }
    
        if (OPRT_OK == tuya_adapter_wifi_get_ip(WF_STATION, &ip)) {
            *stat = WSS_GOT_IP;
        } else {
            *stat = WSS_CONN_FAIL;
        }
    
        return OPRT_OK;
    }
    

注意事项

在无线配网的适配中有些需要注意的地方,以下描述了无线配网适配的常见开发问题,开发应用时要重点关注。

接口实现

所有的适配接口都不允许阻塞,处理任务的时间也不允许过长,否则会出现配网超时等问题。耗时大于 10 秒的任务,建议使用异步方式来处理。

接口返回值

除了获取 IP 地址接口,其他无线配网相关的适配接口返回值为非 0,无线配网都会被终止,所以适配接口尽量保证返回值为 0。

无线状态

SDK 获取到 SSID 和密码后,先判断设备是否已经连接到上级路由器,未连接上级路由器则调用 tuya_adapter_wifi_station_connect 接口通知应用连接上级路由器。判断是否已经连接到上级路由器的机制是,调用 tuya_adapter_wifi_station_get_status 接口获取无线状态,状态为 WSS_GOT_IP 表示已连接到上级路由器。

在切换到 Station 模式之前,无线接口可能有默认 IP 地址,往往会导致在获取无线状态时无判断无线接口已经获取到了 IP 地址,所以返回 WSS_GOT_IP 状态,而实际这是无线接口的默认 IP 地址,而不是路由器分配了 IP 地址,会出现配网超时等现象。

另外,SDK 会定时调用 tuya_adapter_wifi_station_get_status 接口查询无线状态,要求该接口必须快速响应,尽量不超过 1 秒。

附录

main.c

#include <unistd.h>

#include "uni_log.h"
#include "base_os_adapter.h"
#include "tuya_iot_base_api.h"
#include "tuya_iot_com_api.h"

#include "tuya_iot_sdk_api.h"
#include "tuya_iot_sdk_defs.h"

#if defined(TY_BT_MOD) && (TY_BT_MOD == 1)
#include "tuya_os_adapt_bt.h"
#endif

#define PID       "fljmamufiym5fktz"                  // 替换成自己的产品 ID
#define UUID      "tuya461dbc63aeeb991f"              // 替换成自己的 UUID
#define AUTHKEY   "c8X4PR4wx1gMFaQlaZu5dfgVvVRwB8Ug"  // 替换成自己的 AUTHKEY

STATIC VOID __gw_reset_cb(GW_RESET_TYPE_E type)
{
    PR_DEBUG("gw reset callback, type: %d", type);

    if (GW_RESET_DATA_FACTORY != type) {
        exit(0);
    }

    return;
}

STATIC VOID __gw_upgrade_cb(CONST FW_UG_S *fw)
{
    PR_DEBUG("gw upgrade callback");

    if (fw == NULL) {
        PR_ERR("invalid param");
        return;
    }

    PR_DEBUG("        tp: %d", fw->tp);
    PR_DEBUG("    fw_url: %s", fw->fw_url);
    PR_DEBUG("    sw_ver: %s", fw->sw_ver);
    PR_DEBUG("   fw_hmac: %s", fw->fw_hmac);
    PR_DEBUG(" file_size: %u", fw->file_size);

    return;
}

STATIC VOID __gw_active_stat_cb(GW_STATUS_E status)
{
    PR_DEBUG("gw active stat callback, status: %d", status);

    return;
}

STATIC VOID __gw_reboot_cb(VOID)
{
    PR_DEBUG("gw reboot callback");

    exit(0);

    return;
}

STATIC VOID __nw_stat_cb(IN CONST SDK_NW_STAT_T stat)
{
    PR_DEBUG("network stat: %d", stat);

    return;
}

STATIC VOID __wired_stat_cb(IN CONST SDK_WIRED_NW_STAT_T stat)
{
    PR_DEBUG("wired stat: %d", stat);

    return;
}

int main(int argc, char **argv)
{
    OPERATE_RET rt = OPRT_OK;
    GW_PROD_INFO_S prod_info = {0};

    /* gw base callback */
    TY_GW_INFRA_CBS_S gw_cbs = {
        .gw_reset_cb       = __gw_reset_cb,
        .gw_upgrade_cb     = __gw_upgrade_cb,
        .gw_active_stat_cb = __gw_active_stat_cb,
        .gw_reboot_cb      = __gw_reboot_cb,
    };

#if defined(TY_BT_MOD) && (TY_BT_MOD == 1)
    tuya_os_adapt_reg_bt_intf();
#endif

    /* initiate os-layer service*/
    tuya_os_intf_init();

    /* initiate iot-layer service */
    TUYA_CALL_ERR_RETURN(tuya_iot_init("./"));

    /* set the logging level to debug */
    SET_PR_DEBUG_LEVEL(TY_LOG_LEVEL_DEBUG);

    PR_DEBUG("SDK INFO: %s", tuya_iot_get_sdk_info());

    /* set uuid and authkey */
    prod_info.uuid     = UUID;
    prod_info.auth_key = AUTHKEY;
    TUYA_CALL_ERR_RETURN(tuya_iot_set_gw_prod_info(&prod_info));

    /* pre-initiate sdk service */
    TUYA_CALL_ERR_RETURN(tuya_iot_sdk_pre_init(TRUE));  

    /* initiate application service, more service in here */
    TUYA_CALL_ERR_RETURN(tuya_user_svc_init(&gw_cbs));

    /* initiate sdk service */
#if defined(GW_SUPPORT_WIRED_WIFI) && (GW_SUPPORT_WIRED_WIFI==1)
    TUYA_CALL_ERR_RETURN(tuya_iot_wired_wf_sdk_init(IOT_GW_NET_WIRED_WIFI, GWCM_OLD, WF_START_AP_ONLY, PID, USER_SW_VER, NULL, 0));
#elif defined(WIFI_GW) && (WIFI_GW==1)
    TUYA_CALL_ERR_RETURN(tuya_iot_wf_sdk_init(GWCM_OLD, WF_START_AP_ONLY, PID, USER_SW_VER, NULL, 0));
#else
    // 有线 SDK,不支持无线配网
    return OPRT_COM_ERROR;
#endif

    /* register net stat notification callback */
    TUYA_CALL_ERR_RETURN(tuya_iot_sdk_reg_netstat_cb(__nw_stat_cb, __wired_stat_cb, NULL));

    /* start application service, more service in here */
    TUYA_CALL_ERR_RETURN(tuya_user_svc_start(NULL));

    while (1) {
        sleep(10);
    }

    return 0;
}

hal_wifi.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "uni_log.h"
#include "tuya_os_adapt_wifi.h"

#define WLAN_DEV       "wlan0"
#define AP_DEFAULT_IP  "192.168.133.1"

/**
 * 获取无线 IP 地址接口
 */
OPERATE_RET tuya_adapter_wifi_get_ip(CONST WF_IF_E wf, NW_IP_S *ip)
{
    CHAR_T buf[256] = {0};
    CHAR_T *pstart = NULL;
    FILE *fp = NULL;
    
    /**
     * 系统性错误,返回错误
     */
    fp = popen("ifconfig " WLAN_DEV, "r");
    if (fp == NULL) {
        return OPRT_COM_ERROR;
    }

    while (fgets(buf, SIZEOF(buf), fp) != NULL) {
        pstart = strstr(buf, "inet ");
        if (pstart != NULL) {
            break;
        }
    }

    pclose(fp);

    pstart = strstr(buf, "inet addr:");
    if (pstart == NULL) {    
        return OPRT_COM_ERROR;
    }
    sscanf(pstart + strlen("inet addr:"), "%s", ip->ip);

    if (wf == WF_STATION) {
        /**
         * 避免获取到的是默认的 IP 地址
         */
        if (!strncmp(ip->ip, AP_DEFAULT_IP, SIZEOF(ip->ip))) {
            PR_TRACE("%s is default ip of AP", ip->ip);
            return OPRT_COM_ERROR;
        }
    }

    PR_TRACE("IP Addr: %s", ip->ip);

    return OPRT_OK;
}

/**
 * 获取无线 MAC 地址接口
 */
OPERATE_RET tuya_adapter_wifi_get_mac(CONST WF_IF_E wf, NW_MAC_S *mac)
{
    CHAR_T buf[256] = {0};
    CHAR_T *pstart = NULL;
    FILE *fp = NULL;

    /**
     * 系统性错误,返回错误
     */
    fp = popen("ifconfig " WLAN_DEV, "r");
    if (fp == NULL) {
        return OPRT_COM_ERROR;
    }

    while (fgets(buf, SIZEOF(buf), fp) != NULL) {
        pstart = strstr(buf, "HWaddr ");
        if (pstart != NULL) {
            INT_T x1, x2, x3, x4, x5, x6;
            sscanf(pstart + strlen("HWaddr "), "%x:%x:%x:%x:%x:%x", &x1, &x2, &x3, &x4, &x5, &x6);
            mac->mac[0] = x1 & 0xFF;
            mac->mac[1] = x2 & 0xFF;
            mac->mac[2] = x3 & 0xFF;
            mac->mac[3] = x4 & 0xFF;
            mac->mac[4] = x5 & 0xFF;
            mac->mac[5] = x6 & 0xFF;
            break;
        }
    }

    pclose(fp);

    PR_DEBUG("MAC Addr: %02X-%02X-%02X-%02X-%02X-%02X", mac->mac[0], mac->mac[1], mac->mac[2], mac->mac[3], mac->mac[4], mac->mac[5]);

    return OPRT_OK;
}

/**
 * 设置无线模式
 */
OPERATE_RET tuya_adapter_wifi_set_work_mode(CONST WF_WK_MD_E mode)
{
    switch (mode) {
        case WWM_STATION:
        {
            system("iwpriv " WLAN_DEV " set_mib opmode=0x8");
            break;
        }
        case WWM_SOFTAP:
        {
            system("iwpriv " WLAN_DEV " set_mib opmode=0x10");
            break;
        }
        default:
        {
            break;
        }
    }

    return OPRT_OK;
}

/**
 * 获取无线模式
 */
OPERATE_RET tuya_adapter_wifi_get_work_mode(WF_WK_MD_E *mode)
{
    CHAR_T buf[256] = {0};
    CHAR_T *pstart = NULL;
    CHAR_T tmp[16] = {0};
    FILE *fp = NULL;

    /**
     * 系统性错误,返回错误
     */
    fp = popen("iwconfig " WLAN_DEV, "r");
    if (fp == NULL) {
        return OPRT_COM_ERROR;
    }

    while (fgets(buf, SIZEOF(buf), fp) != NULL) {
        pstart = strstr(buf, "Mode:");
        if (pstart != NULL) {
            sscanf(pstart + strlen("Mode:"), "%s ", tmp);
            break;
        }
    }
    pclose(fp);

    if (!strncasecmp(tmp, "Managed", strlen("Managed"))) {
        *mode = WWM_STATION;
    } else if (!strncasecmp(tmp, "Master", strlen("Master"))) {
        *mode = WWM_SOFTAP;
    }  else {
        *mode = WWM_UNKNOWN;
    }

    return OPRT_OK;
}

/**
 * 开启 AP 接口
 */
OPERATE_RET tuya_adapter_wifi_ap_start(CONST WF_AP_CFG_IF_S *cfg)
{
    CHAR_T cmd_buf[128] = {0};

    system("ifconfig " WLAN_DEV " down");

    system("iwpriv " WLAN_DEV " set_mib opmode=0x10");
    system("iwpriv " WLAN_DEV " set_mib band=11");
    system("iwpriv " WLAN_DEV " set_mib deny_legacy=0");
    system("iwpriv " WLAN_DEV " set_mib use_40M=1");
    system("iwpriv " WLAN_DEV " set_mib 802_1x=0");
    snprintf(cmd_buf, SIZEOF(cmd_buf), "iwpriv %s set_mib ssid=\"%s\"", WLAN_DEV, cfg->ssid);
    system(cmd_buf);

    if (cfg->p_len > 0) {
        system("iwpriv " WLAN_DEV " set_mib authtype=2");
        system("iwpriv " WLAN_DEV " set_mib psk_enable=3");
        system("iwpriv " WLAN_DEV " set_mib encmode=2");
        system("iwpriv " WLAN_DEV " set_mib wpa2_cipher=10");
        system("iwpriv " WLAN_DEV " set_mib wpa_cipher=10");
        snprintf(cmd_buf, SIZEOF(cmd_buf), "iwpriv %s set_mib passphrase=\"%s\"", WLAN_DEV, cfg->passwd);
        system(cmd_buf);
    } else {
        system("iwpriv " WLAN_DEV " set_mib authtype=0");
        system("iwpriv " WLAN_DEV " set_mib encmode=0");
    }

    /**
     * 开启 udhcpd 服务
     */ 
    system("ifconfig " WLAN_DEV " " AP_DEFAULT_IP);
    system("killall udhcpd");
    system("udhcpd /tmp/tuya/udhcpd.conf");

    return OPRT_OK;
}

/**
 * 关闭 AP 接口
 */
OPERATE_RET tuya_adapter_wifi_ap_stop(VOID_T)
{
    system("ifconfig " WLAN_DEV " down");
    system("killall udhcpd");

    return OPRT_OK;
}

/**
 * Station 连接路由器接口
 */
OPERATE_RET tuya_adapter_wifi_station_connect(CONST SCHAR_T *ssid, CONST SCHAR_T *passwd)
{
    CHAR_T cmd_buf[128] = {0};

    /**
     * 关闭 udhcpd 服务
     */
    system("killall udhcpd");
 
    system("ifconfig " WLAN_DEV " down");

    system("iwpriv " WLAN_DEV " set_mib opmode=0x8");
    system("iwpriv " WLAN_DEV " set_mib band=11");
    system("iwpriv " WLAN_DEV " set_mib deny_legacy=0");
    system("iwpriv " WLAN_DEV " set_mib use40M=1");
    system("iwpriv " WLAN_DEV " set_mib 802_1x=0");
    snprintf(cmd_buf, SIZEOF(cmd_buf), "iwpriv %s set_mib ssid=\"%s\"", WLAN_DEV, ssid);
    system(cmd_buf);
   
    if (!passwd || (strlen(passwd) == 0)) {
        system("iwpriv " WLAN_DEV " set_mib authtype=0");
        system("iwpriv " WLAN_DEV " set_mib encmode=0");
    } else {
        system("iwpriv " WLAN_DEV " set_mib authtype=2");
        system("iwpriv " WLAN_DEV " set_mib psk_enable=3");
        system("iwpriv " WLAN_DEV " set_mib encmode=2");
        system("iwpriv " WLAN_DEV " set_mib wpa2_cipher=10");
        system("iwpriv " WLAN_DEV " set_mib wpa_cipher=10");
        snprintf(cmd_buf, SIZEOF(cmd_buf), "iwpriv %s set_mib passphrase=\"%s\"", WLAN_DEV, passwd);
        system(cmd_buf);
    }
    
    system("ifconfig " WLAN_DEV " up");

    system("ps | grep 'udhcpc -i wlan0' | grep -v grep | awk '{print $1}' | xargs kill -9");    
    system("ps | grep 'udhcpc -b -i wlan0' | grep -v grep | awk '{print $1}' | xargs kill -9");
    system("busybox udhcpc -b -i wlan0 -A 3 -T 3 -s /tmp/tuya/8197wlan0_udhcpc.script&");

    return OPRT_OK;
}

/**
 * 断开 Station 连接接口
 */
OPERATE_RET tuya_adapter_wifi_station_disconnect(VOID_T)
{
    system("ifconfig " WLAN_DEV " 0.0.0.0");
    system("ps | grep 'udhcpc -i wlan0' | grep -v grep | awk '{print $1}' | xargs kill -9");    
    system("ps | grep 'udhcpc -b -i wlan0' | grep -v grep | awk '{print $1}' | xargs kill -9");

    return OPRT_OK;
}

/**
 * 获取 Station 连接状态接口
 */
OPERATE_RET tuya_adapter_wifi_station_get_status(WF_STATION_STAT_E *stat)
{
    NW_IP_S ip = {0};

    if (stat == NULL) {
        PR_ERR("invalid param");
        return OPRT_INVALID_PARM;
    }

    if (OPRT_OK == tuya_adapter_wifi_get_ip(WF_STATION, &ip)) {
        *stat = WSS_GOT_IP;
    } else {
        *stat = WSS_CONN_FAIL;
    }

    return OPRT_OK;
}

/**
 * 获取无线信号强度
 */
OPERATE_RET tuya_adapter_wifi_station_get_conn_ap_rssi(SCHAR_T *rssi)
{
    *rssi = 99;

    return OPRT_OK;
}

/* EZ 配网接口 */
OPERATE_RET tuya_adapter_wifi_all_ap_scan(AP_IF_S **aps, UINT_T *num)
{
    return OPRT_OK;
}

/* EZ 配网接口 */
OPERATE_RET tuya_adapter_wifi_release_ap(AP_IF_S *ap)
{
    return OPRT_OK;
}

/* EZ 配网接口 */
OPERATE_RET tuya_adapter_wifi_set_cur_channel(CONST UCHAR_T channel)
{
    return OPRT_OK;
}

/* EZ 配网接口 */
OPERATE_RET tuya_adapter_wifi_get_cur_channel(UCHAR_T *chan)
{
    return OPRT_OK;
}

/* EZ 配网接口 */
OPERATE_RET tuya_adapter_wifi_sniffer_set(CONST BOOL_T en, CONST SNIFFER_CALLBACK cb)
{
    return OPRT_OK;
}

/* 无需实现 */
OPERATE_RET tuya_adapter_wifi_assign_ap_scan(CONST SCHAR_T *ssid, AP_IF_S **ap)
{
    return OPRT_OK;
}

/* 无需实现 */
OPERATE_RET tuya_adapter_wifi_set_mac(CONST WF_IF_E wf, CONST NW_MAC_S *mac)
{
    return OPRT_OK;
}

/* 无需实现 */
OPERATE_RET tuya_adapter_wifi_get_bssid(UCHAR_T *mac)
{
    return OPRT_OK;
}

/* 无需实现 */
OPERATE_RET tuya_adapter_wifi_set_country_code(CONST COUNTRY_CODE_E code)
{
    return OPRT_OK;
}

/* 无需实现 */
OPERATE_RET tuya_adapter_wifi_send_mgnt(CONST UCHAR_T *buf, CONST UINT_T len)
{
    return OPRT_OK;
}

/* 无需实现 */
OPERATE_RET tuya_adapter_wifi_register_recv_mgnt_callback(CONST BOOL_T enable, CONST WIFI_REV_MGNT_CB recv_cb)
{
    return OPRT_OK;
}

/* 无需实现 */
OPERATE_RET tuya_adapter_wifi_set_lp_mode(CONST BOOL_T en, CONST UCHAR_T dtim)
{
    return OPRT_OK;
}

/* 无需实现 */
OPERATE_RET tuya_adapter_wifi_get_connected_ap_info_v2(FAST_WF_CONNECTED_AP_INFO_V2_S **fast_ap_info)
{
    return OPRT_COM_ERROR;
}

/* 无需实现 */
OPERATE_RET tuya_adapter_wifi_fast_station_connect_v2(CONST FAST_WF_CONNECTED_AP_INFO_V2_S *fast_ap_info)
{
    return OPRT_COM_ERROR;
}

/* 无需实现 */
BOOL_T tuya_adapter_wifi_rf_calibrated(VOID_T)
{
    return FALSE;
}