AP Pairing Guide

Last Updated on : 2022-11-24 09:20:24download

This topic describes how to perform access point (AP) pairing by using the integrated gateway SDK. In the following example, a gateway is paired in AP mode

Background information

Access point (AP) mode: also called hotspot mode. The working principle is to put a device in hotspot mode and connect a mobile phone to the device hotspot, so that the mobile phone and the device run on the same local area network (LAN). The mobile phone encrypts the token, router SSID and password, and other information, and then broadcasts the information over the LAN.

After receiving the broadcast packet, the device parses and decrypts it, obtains the SSID and password of the router, and then switches to the Station mode to connect to the router. After the connection is successful, the device sends an activation request to the cloud. Then, the device is activated in the cloud and the pairing process is finished.

Implementation

The SDK has implemented the underlying logic of AP pairing and defined a set of wireless adaptation interfaces. The application only needs to complete the interface adaptation.

The following figure shows the interaction process of AP pairing:

AP Pairing Guide

To pair a gateway in AP mode, perform the following steps:

This sample is only for reference, helping you understand its implementation logic. This sample code is adapted to the Realtek RTL8197F platform. Note that the wireless-related operations of different chips or systems might be different. For the convenience of demonstration, this sample code does not consider performance and uses Shell commands.

  1. During the initialization of the SDK, the wireless pairing mode is set to support AP pairing only.

    // ...
    
    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
        // Wired SDK. Wireless pairing is not supported.
        return OPRT_COM_ERROR;
    #endif
        // ...
    }
    
  2. Adapt to the following interface to get the MAC address of the wireless network interface.

    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. Adapt to the following interface to set the wireless mode. In the AP pairing process, the device first works in AP mode. After the SSID and password of the router are obtained, the device switches to the Station mode to connect to the router. The SDK uses this interface to switch modes.

    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. Adapt to the following interface to set and enable AP. In AP mode, the device is not activated and has not obtained the SSID and password of the router. After the application starts, the SDK uses this interface to start the 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");
        }
    
        /**
         *  Start the udhcpd service and assign an IP address to the client.
         */ 
        system("ifconfig " WLAN_DEV " " AP_DEFAULT_IP);
        system("killall udhcpd");
        system("udhcpd /tmp/tuya/udhcpd.conf");
    
        return OPRT_OK;
    }
    
  5. Adapt to the following interface to get the current wireless mode.

    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. Adapt to the following interface to disable the AP feature. After the SDK receives the SSID and password of the router, the SDK uses this interface to disable the AP feature.

    OPERATE_RET tuya_adapter_wifi_ap_stop(VOID_T)
    {
        system("ifconfig " WLAN_DEV " down");
        system("killall udhcpd");
    
        return OPRT_OK;
    }
    
  7. Adapt to the following interface to connect to the router. After the SDK has obtained the SSID and password of the router, the SDK uses this interface to connect to the router.

    OPERATE_RET tuya_adapter_wifi_station_connect(CONST SCHAR_T *ssid, CONST SCHAR_T *passwd)
    {
        CHAR_T cmd_buf[128] = {0};
    
        /**
         * Disable the udhcpd service
         */
        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. Adapt to the following interface to get the IP address of the wireless network interface. The IP address will be used for LAN communications.

    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) {
            /**
             * Avoid the default IP address to be returned
             */
            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. Adapt to the following interface to get the Station connection status. After connecting to the router, the SDK will regularly get the wireless connection status, and check the network status of the network based on the WSS_GOT_IP status.

    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;
    }
    

Things to note

During application development, pay attention to the following issues related to wireless pairing adaptation.

Interface implementation

All adaptation interfaces are not allowed to be blocked, and the processing time of tasks cannot be too lengthy. Otherwise, problems such as pairing timeout will occur. We recommend that tasks that last more than 10 seconds be processed asynchronously.

Return value

If the return value of a wireless pairing adaptation interface, except the interface for getting the IP address, is not 0, the wireless pairing will be terminated. Therefore, try to ensure that the return value is 0 during adaptation.

Wireless status

After the SDK gets the SSID and password, the SDK first checks whether the device is connected to the upper-level router. If the answer is no, the SDK calls tuya_adapter_wifi_station_connect to notify the application to connect to the upper-level router. To check whether the device is connected to the upper-level router, the SDK calls tuya_adapter_wifi_station_get_status to get the wireless status. The WSS_GOT_IP status indicates that the device has been connected to the upper-level router.

Before switching to the Station mode, the wireless interface might have a default IP address. It is difficult to check whether the wireless interface has obtained an IP address, so the WSS_GOT_IP status is returned. Actually, it is the default IP address of the wireless interface, rather than the one assigned by the router. As a result, the pairing will time out.

In addition, the SDK periodically calls tuya_adapter_wifi_station_get_status to query the wireless status. The interface must respond quickly, preferably within one second.

Appendix

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" // Replaced with your own product ID
#define UUID "tuya461dbc63aeeb991f" // Replaced with your own UUID
#define AUTHKEY "c8X4PR4wx1gMFaQlaZu5dfgVvVRwB8Ug" // Replace with your own 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
    // Wired SDK. Wireless pairing is not supported.
    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"

/**
 * Get wireless IP address
 */
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;

    /**
     * A system error message is returned
     */
    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) {
        /**
         * Avoid getting the default IP address
         */
        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;
}

/**
 * Get the wireless MAC address
 */
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;

    /**
     * A system error message is returned
     */
    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;
}

/**
 * Set the wireless mode
 */
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;
}

/**
 * Get the wireless mode
 */
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;

    /**
     * A system error message is returned
     */
    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;
}

/**
 * Enable the AP mode
 */
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");
    }

    /**
     * Enable the udhcpd service
     */
    system("ifconfig " WLAN_DEV " " AP_DEFAULT_IP);
    system("killall udhcpd");
    system("udhcpd /tmp/tuya/udhcpd.conf");

    return OPRT_OK;
}

/**
 * Disable the AP mode
 */
OPERATE_RET tuya_adapter_wifi_ap_stop(VOID_T)
{
    system("ifconfig " WLAN_DEV " down");
    system("killall udhcpd");

    return OPRT_OK;
}

/**
 * Connect Station to the router
 */
OPERATE_RET tuya_adapter_wifi_station_connect(CONST SCHAR_T *ssid, CONST SCHAR_T *passwd)
{
    CHAR_T cmd_buf[128] = {0};

    /**
     * Disable the udhcpd service
     */
    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;
}

/**
 * Disconnect the 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;
}

/**
 * Get the Station connection status
 */
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;
}

/**
 * Get the wireless signal strength
 */
OPERATE_RET tuya_adapter_wifi_station_get_conn_ap_rssi(SCHAR_T *rssi)
{
    *rssi = 99;

    return OPRT_OK;
}

/* Wi-Fi Easy Connect (EZ) pairing */
OPERATE_RET tuya_adapter_wifi_all_ap_scan(AP_IF_S **aps, UINT_T *num)
{
    return OPRT_OK;
}

/* EZ pairing */
OPERATE_RET tuya_adapter_wifi_release_ap(AP_IF_S *ap)
{
    return OPRT_OK;
}

/* EZ pairing */
OPERATE_RET tuya_adapter_wifi_set_cur_channel(CONST UCHAR_T channel)
{
    return OPRT_OK;
}

/* EZ pairing */
OPERATE_RET tuya_adapter_wifi_get_cur_channel(UCHAR_T *chan)
{
    return OPRT_OK;
}

/* EZ pairing */
OPERATE_RET tuya_adapter_wifi_sniffer_set(CONST BOOL_T en, CONST SNIFFER_CALLBACK cb)
{
    return OPRT_OK;
}

/* There is no need to implement this interface currently.*/ OPERATE_RET tuya_adapter_wifi_assign_ap_scan(CONST SCHAR_T *ssid, AP_IF_S **ap)
{
    return OPRT_OK;
}

/* There is no need to implement this interface currently.*/
OPERATE_RET tuya_adapter_wifi_set_mac(CONST WF_IF_E wf, CONST NW_MAC_S *mac)
{
    return OPRT_OK;
}

/* There is no need to implement this interface currently.*/
OPERATE_RET tuya_adapter_wifi_get_bssid(UCHAR_T *mac)
{
    return OPRT_OK;
}

/* There is no need to implement this interface currently.*/
OPERATE_RET tuya_adapter_wifi_set_country_code(CONST COUNTRY_CODE_E code)
{
    return OPRT_OK;
}

/* There is no need to implement this interface currently.*/
OPERATE_RET tuya_adapter_wifi_send_mgnt(CONST UCHAR_T *buf, CONST UINT_T len)
{
    return OPRT_OK;
}

/* There is no need to implement this interface currently.*/
OPERATE_RET tuya_adapter_wifi_register_recv_mgnt_callback(CONST BOOL_T enable, CONST WIFI_REV_MGNT_CB recv_cb)
{
    return OPRT_OK;
}

/* There is no need to implement this interface currently.*/
OPERATE_RET tuya_adapter_wifi_set_lp_mode(CONST BOOL_T en, CONST UCHAR_T dtim)
{
    return OPRT_OK;
}

/* There is no need to implement this interface currently.*/
OPERATE_RET tuya_adapter_wifi_get_connected_ap_info_v2(FAST_WF_CONNECTED_AP_INFO_V2_S **fast_ap_info)
{
    return OPRT_COM_ERROR;
}

/* There is no need to implement this interface currently.*/
OPERATE_RET tuya_adapter_wifi_fast_station_connect_v2(CONST FAST_WF_CONNECTED_AP_INFO_V2_S *fast_ap_info)
{
    return OPRT_COM_ERROR;
}

/* There is no need to implement this interface currently.*/
BOOL_T tuya_adapter_wifi_rf_calibrated(VOID_T)
{
    return FALSE;
}