/**
 * @file tkl_wifi.c
 * @brief this file was auto-generated by tuyaos v&v tools, developer can add implements between BEGIN and END
 *
 * @warning: changes between user 'BEGIN' and 'END' will be keeped when run tuyaos v&v tools
 *           changes in other place will be overwrited and lost
 *
 * @copyright Copyright 2020-2021 Tuya Inc. All Rights Reserved.
 *
 */

// --- BEGIN: user defines and implements ---
#include "tkl_wifi.h"
#include "tuya_error_code.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <pthread.h>

#define WLAN_DEV "wlan0"

WIFI_EVENT_CB wifi_status_cb;

static void *wifi_status_event_cb(void *arg)
{
    WF_EVENT_E wf_event;
    WF_STATION_STAT_E stat = 0;
    WF_STATION_STAT_E last_stat = 0;
    int last_state = -1;

    pthread_detach(pthread_self());

    while (1) {
        tkl_wifi_station_get_status(&stat);
        if (stat != WSS_CONN_SUCCESS && stat != WSS_GOT_IP) {
            wf_event = WFE_DISCONNECTED;
        }
        if (stat == WSS_CONN_FAIL) {
            wf_event = WFE_CONNECT_FAILED;
        } else if (stat == WSS_GOT_IP || stat == WSS_CONN_SUCCESS) {
            wf_event = WFE_CONNECTED;
            if (last_stat != stat) {
                last_stat = stat;
                last_state = wf_event;
                wifi_status_cb(wf_event, NULL);
                sleep(1);
                continue;
            }
        }

        if (last_state == wf_event) {
            sleep(1);
            continue;
        }

        last_state = wf_event;
        wifi_status_cb(wf_event, NULL);
        sleep(1);
    }
}

static void exec_cmd(char *pCmd)
{
    printf("Exec Cmd:%s \r\n", pCmd);
    system(pCmd);
}

static int s_curr_channel = 1;

#pragma pack(1)
/*
http://www.radiotap.org/
*/
typedef struct {
    /**
     * @it_version: radiotap version, always 0
     */
    uint8_t it_version;

    /**
     * @it_pad: padding (or alignment)
     */
    uint8_t it_pad;

    /**
     * @it_len: overall radiotap header length
     */
    uint16_t it_len;

    /**
     * @it_present: (first) present word
     */
    uint32_t it_present;
} ieee80211_radiotap_header;
#pragma pack()

static volatile SNIFFER_CALLBACK s_pSnifferCall = NULL;
static volatile BOOL_T s_enable_sniffer = FALSE;

static void *func_Sniffer(void *pReserved)
{
    printf("Sniffer Thread Create\r\n");

    int sock = socket(PF_PACKET, SOCK_RAW, htons(0x03)); // ETH_P_ALL
    if (sock < 0) {
        printf("Sniffer Socket Alloc Fails %d \r\n", sock);
        perror("Sniffer Socket Alloc");
        return (void *)0;
    }

    { /* Force binding to wlan0, can be considered to remove */
        struct ifreq ifr;
        memset(&ifr, 0x00, sizeof(ifr));
        strncpy(ifr.ifr_name, WLAN_DEV, sizeof(ifr.ifr_name) - 1);
        setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifr, sizeof(ifr));
    }

#define MAX_REV_BUFFER 512
    uint8_t rev_buffer[MAX_REV_BUFFER];

    int skipLen = 26; /* Radiotap default length is 26 */

    while ((s_pSnifferCall != NULL) && (TRUE == s_enable_sniffer)) {
        int rev_num = recvfrom(sock, rev_buffer, MAX_REV_BUFFER, 0, NULL, NULL);
        ieee80211_radiotap_header *pHeader = (ieee80211_radiotap_header *)rev_buffer;
        skipLen = pHeader->it_len;

#ifdef WIFI_CHIP_7601
        skipLen = 144;
#endif
        if (skipLen >= MAX_REV_BUFFER) { /* Package is lost directly when its length greater than maximum*/
            continue;
        }

        if (0) {
            printf("skipLen:%d ", skipLen);
            int index = 0;
            for (index = 0; index < 180; index++) {
                printf("%02X-", rev_buffer[index]);
            }
            printf("\r\n");
        }
        if (rev_num > skipLen) {
            s_pSnifferCall(rev_buffer + skipLen, rev_num - skipLen, 2);
        }
    }

    s_pSnifferCall = NULL;

    close(sock);

    printf("Sniffer Proc Finish\r\n");
    return (void *)0;
}

static pthread_t sniffer_thId; // ID of capture thread
static BOOL_T sniffer_set_done = FALSE;

static OPERATE_RET hwl_get_local_ip_info(char *interface, OUT NW_IP_S *ip)
{
    char tmp[256];

    memset(tmp, 0, sizeof(tmp));
    snprintf(tmp, sizeof(tmp), "ifconfig %s", interface);
    FILE *pp = popen(tmp, "r");
    if (pp == NULL) {
        return OPRT_COM_ERROR;
    }

    memset(tmp, 0, sizeof(tmp));
    while (fgets(tmp, sizeof(tmp), pp) != NULL) {
        char *pIPStart = strstr(tmp, "inet addr:");
        if (pIPStart != NULL) { /* It's all a line containing IP GW mask that jumps out directly  */
            break;
        }
    }

    {
        /* finding ip  */
        char *pIPStart = strstr(tmp, "inet addr:");
        if (pIPStart != NULL) {
            sscanf(pIPStart + strlen("inet addr:"), "%15s", ip->ip);
        }
    }

    {
        /* finding gw  */
        char *pGWStart = strstr(tmp, "broadcast ");
        if (pGWStart != NULL) {
            sscanf(pGWStart + strlen("broadcast "), "%s", ip->gw);
        }
    }

    {
        /* finding mask */
        char *pMASKStart = strstr(tmp, "netmask ");
        if (pMASKStart != NULL) {
            sscanf(pMASKStart + strlen("netmask "), "%s", ip->mask);
        }
    }

    pclose(pp);

    return OPRT_OK;
}

// if ethernet is used , replace ethernet name
#define NET_DEV "eth0"
// --- END: user defines and implements ---

/**
 * @brief set wifi station work status changed callback
 *
 * @param[in]      cb        the wifi station work status changed callback
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_init(WIFI_EVENT_CB cb)
{
    // --- BEGIN: user implements ---
    int iret = 0;
    pthread_t thread;
    wifi_status_cb = cb;

    iret = pthread_create(&thread, NULL, wifi_status_event_cb, NULL);
    if (iret) {
        printf("create status_cs thread failed");
        return -1;
    }

    return 0;
    // --- END: user implements ---
}

/**
 * @brief scan current environment and obtain the ap
 *        infos in current environment
 *
 * @param[in]       ssid        the specific ssid
 * @param[out]      ap_ary      current ap info array
 * @param[out]      num         the num of ar_ary
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 *
 * @note if ssid == NULL means scan all ap, otherwise means scan the specific ssid
 */
OPERATE_RET tkl_wifi_scan_ap(const int8_t *ssid, AP_IF_S **ap_ary, uint32_t *num)
{
    // --- BEGIN: user implements ---
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief release the memory malloced in <tkl_wifi_ap_scan>
 *        if needed. tuyaos will call this function when the
 *        ap info is no use.
 *
 * @param[in]       ap          the ap info
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_release_ap(AP_IF_S *ap)
{
    // --- BEGIN: user implements ---
    // Static variables, no need to free
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief start a soft ap
 *
 * @param[in]       cfg         the soft ap config
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_start_ap(const WF_AP_CFG_IF_S *cfg)
{
    // --- BEGIN: user implements ---
    if (NULL == cfg) {
        return OPRT_INVALID_PARM;
    }

    printf("Start AP SSID:%s \r\n", cfg->ssid);
    // Reserved
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief stop a soft ap
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_stop_ap(void)
{
    // --- BEGIN: user implements ---
    printf("Stop AP \r\n");
    // Reserved
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief set wifi interface work channel
 *
 * @param[in]       chan        the channel to set
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_set_cur_channel(const uint8_t chan)
{
    // --- BEGIN: user implements ---
    char tmpCmd[100] = {0};
    snprintf(tmpCmd, 100, "iwconfig %s channel %d", WLAN_DEV, chan);
    exec_cmd(tmpCmd);
    s_curr_channel = chan;

    printf("WIFI Set Channel:%d \r\n", chan);

#ifdef WIFI_CHIP_7601
    tuya_linux_wf_wk_mode_set(WWM_SNIFFER);
#endif

    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief get wifi interface work channel
 *
 * @param[out]      chan        the channel wifi works
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_get_cur_channel(uint8_t *chan)
{
    // --- BEGIN: user implements ---
    if (NULL == chan) {
        return OPRT_INVALID_PARM;
    }

    FILE *pp = popen("iwlist " WLAN_DEV " channel", "r");

    if (pp == NULL) {
        return OPRT_COM_ERROR;
    }

    char tmp[128] = {0};
    memset(tmp, 0, sizeof(tmp));
    while (fgets(tmp, sizeof(tmp), pp) != NULL) {
        char *pIPStart = strstr(tmp, " (Channel ");
        if (pIPStart != NULL) {
            break;
        }
    }

    /* find the channel	*/
    char *pCHANNELStart = strstr(tmp, " (Channel ");
    if (pCHANNELStart != NULL) {
        int x = 0;
        sscanf(pCHANNELStart + strlen(" (Channel "), "%d", &x);
        *chan = x;
    } else {
        *chan = s_curr_channel;
    }

    pclose(pp);

    printf("WIFI Get Curr Channel:%d \r\n", *chan);

    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief enable / disable wifi sniffer mode.
 *        if wifi sniffer mode is enabled, wifi recv from
 *        packages from the air, and user shoud send these
 *        packages to tuya-sdk with callback <cb>.
 *
 * @param[in]       en          enable or disable
 * @param[in]       cb          notify callback
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_set_sniffer(const BOOL_T en, const SNIFFER_CALLBACK cb)
{
    // --- BEGIN: user implements ---
    if (en == s_enable_sniffer) {
        printf("Already in status %d\r\n", en);
        return OPRT_OK;
    }
    s_enable_sniffer = en;
    if (en == TRUE) {
        // IPC_APP_Notify_LED_Sound_Status_CB(IPC_START_WIFI_CFG);

        printf("Enable Sniffer\r\n");

        s_pSnifferCall = cb;
        pthread_create(&sniffer_thId, NULL, func_Sniffer, NULL);

        printf("Enable Qrcode \r\n");
    } else {
        printf("Disable Sniffer\r\n");
        pthread_join(sniffer_thId, NULL);

        printf("Disable Qrcode\r\n");

        sniffer_set_done = TRUE;
    }

    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief get wifi ip info.when wifi works in
 *        ap+station mode, wifi has two ips.
 *
 * @param[in]       wf          wifi function type
 * @param[out]      ip          the ip addr info
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_get_ip(const WF_IF_E wf, NW_IP_S *ip)
{
    // --- BEGIN: user implements ---
    if (NULL == ip) {
        return OPRT_INVALID_PARM;
    }

    if (wf == WF_AP) { /* Simple Processing in AP Mode */
        memcpy(ip->ip, "192.168.0.1", strlen("192.168.0.1"));
        memcpy(ip->gw, "192.168.0.1", strlen("192.168.0.1"));
        memcpy(ip->mask, "255.255.255.0", strlen("255.255.255.0"));
    }

    if (wf == WF_STATION) {
        // get the ip of ethernet
        hwl_get_local_ip_info(NET_DEV, ip);

        NW_IP_S tmp;
        memset(&tmp, 0, sizeof(NW_IP_S));
        // get the ip of wifi
        hwl_get_local_ip_info(WLAN_DEV, &tmp);
        if (strlen(tmp.ip)) {
            // replace ip
            memcpy(ip, &tmp, sizeof(NW_IP_S));
        }
    }

    printf("WIFI[%d] Get IP:%s\r\n", wf, ip->ip);
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief set wifi mac info.when wifi works in
 *        ap+station mode, wifi has two macs.
 *
 * @param[in]       wf          wifi function type
 * @param[in]       mac         the mac info
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_set_mac(const WF_IF_E wf, const NW_MAC_S *mac)
{
    // --- BEGIN: user implements ---
    if (NULL == mac) {
        return OPRT_INVALID_PARM;
    }
    printf("WIFI Set MAC\r\n");
    // reserved
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief get wifi mac info.when wifi works in
 *        ap+station mode, wifi has two macs.
 *
 * @param[in]       wf          wifi function type
 * @param[out]      mac         the mac info
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_get_mac(const WF_IF_E wf, NW_MAC_S *mac)
{
    // --- BEGIN: user implements ---
    if (NULL == mac) {
        return OPRT_INVALID_PARM;
    }

#ifdef __HuaweiLite__
    // todo
    // Implementing MAC acquisition of liteos system
#else
    FILE *pp = popen("ifconfig " WLAN_DEV, "r");
    if (pp == NULL) {
        return OPRT_COM_ERROR;
    }

    char tmp[256];
    memset(tmp, 0, sizeof(tmp));
    while (fgets(tmp, sizeof(tmp), pp) != NULL) {
        char *pMACStart = strstr(tmp, "ether ");
        if (pMACStart != NULL) {
            int x1, x2, x3, x4, x5, x6;
            sscanf(pMACStart + strlen("ether "), "%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(pp);
#endif

    printf("WIFI Get MAC %02X-%02X-%02X-%02X-%02X-%02X\r\n", mac->mac[0], mac->mac[1], mac->mac[2], mac->mac[3],
           mac->mac[4], mac->mac[5]);

    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief set wifi work mode
 *
 * @param[in]       mode        wifi work mode
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_set_work_mode(const WF_WK_MD_E mode)
{
    // --- BEGIN: user implements ---
    char tmpCmd[100] = {0};

    snprintf(tmpCmd, 100, "ifconfig %s up", WLAN_DEV);
    exec_cmd(tmpCmd);

    switch (mode) {
    case WWM_POWERDOWN: {
        // Linux system does not care about low power
        break;
    }
    case WWM_SNIFFER: {
#ifndef WIFI_CHIP_7601
        snprintf(tmpCmd, 100, "ifconfig %s down", WLAN_DEV);
        exec_cmd(tmpCmd);
#endif
        snprintf(tmpCmd, 100, "iwconfig %s mode Monitor", WLAN_DEV);
        exec_cmd(tmpCmd);
#ifndef WIFI_CHIP_7601
        snprintf(tmpCmd, 100, "ifconfig %s up", WLAN_DEV);
        exec_cmd(tmpCmd);
#endif
        break;
    }
    case WWM_STATION: {
#ifndef WIFI_CHIP_7601
        snprintf(tmpCmd, 100, "ifconfig %s down", WLAN_DEV);
        exec_cmd(tmpCmd);
#endif
        snprintf(tmpCmd, 100, "iwconfig %s mode Managed", WLAN_DEV);
        exec_cmd(tmpCmd);
#ifndef WIFI_CHIP_7601
        snprintf(tmpCmd, 100, "ifconfig %s up", WLAN_DEV);
        exec_cmd(tmpCmd);
#endif
        break;
    }
    case WWM_SOFTAP: {
#ifndef WIFI_CHIP_7601
        snprintf(tmpCmd, 100, "ifconfig %s down", WLAN_DEV);
        exec_cmd(tmpCmd);
#endif
        snprintf(tmpCmd, 100, "iwconfig %s mode Master", WLAN_DEV);
        exec_cmd(tmpCmd);
#ifndef WIFI_CHIP_7601
        snprintf(tmpCmd, 100, "ifconfig %s up", WLAN_DEV);
        exec_cmd(tmpCmd);
#endif
        break;
    }
    case WWM_STATIONAP: { // reserved
        break;
    }
    default: {
        break;
    }
    }
    printf("WIFI Set Mode %d\r\n", mode);

    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief get wifi work mode
 *
 * @param[out]      mode        wifi work mode
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_get_work_mode(WF_WK_MD_E *mode)
{
    // --- BEGIN: user implements ---
    if (NULL == mode) {
        return OPRT_INVALID_PARM;
    }

#ifdef __HuaweiLite__
    // todo liteos system
    // Implementation of mode acquisition
    char scan_mode[10] = {0};
#else
    FILE *pp = popen("iwconfig " WLAN_DEV, "r");
    if (pp == NULL) {
        printf("WIFI Get Mode Fail. Force Set Station \r\n");
        *mode = WWM_STATION;
        return OPRT_OK;
    }

    char scan_mode[10] = {0};
    char tmp[256] = {0};
    while (fgets(tmp, sizeof(tmp), pp) != NULL) {
        char *pModeStart = strstr(tmp, "Mode:");
        if (pModeStart != NULL) {
            int x1, x2, x3, x4, x5, x6;
            sscanf(pModeStart + strlen("Mode:"), "%s ", scan_mode);
            break;
        }
    }
    pclose(pp);
#endif

    *mode = WWM_STATION;
    if (strncasecmp(scan_mode, "Managed", strlen("Managed")) == 0) {
        *mode = WWM_STATION;
    }

    if (strncasecmp(scan_mode, "Master", strlen("Master")) == 0) {
        *mode = WWM_SOFTAP;
    }

    if (strncasecmp(scan_mode, "Monitor", strlen("Monitor")) == 0) {
        *mode = WWM_SNIFFER;
    }
    //    printf("WIFI Get Mode [%s] %d\r\n", scan_mode, *mode);

    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief : get ap info for fast connect
 * @param[out]      fast_ap_info
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_get_connected_ap_info(FAST_WF_CONNECTED_AP_INFO_T **fast_ap_info)
{
    // --- BEGIN: user implements ---
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief get wifi bssid
 *
 * @param[out]      mac         uplink mac
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_get_bssid(uint8_t *mac)
{
    // --- BEGIN: user implements ---
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief set wifi country code
 *
 * @param[in]       ccode  country code
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_set_country_code(const COUNTRY_CODE_E ccode)
{
    // --- BEGIN: user implements ---
    printf("Set Country Code:%d \r\n", ccode);

    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief do wifi calibration
 *
 * @note called when test wifi
 *
 * @return true on success. faile on failure
 */
OPERATE_RET tkl_wifi_set_rf_calibrated(void)
{
    // --- BEGIN: user implements ---
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief set wifi lowpower mode
 *
 * @param[in]       enable      enbale lowpower mode
 * @param[in]       dtim     the wifi dtim
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_set_lp_mode(const BOOL_T enable, const uint8_t dtim)
{
    // --- BEGIN: user implements ---
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief : fast connect
 * @param[in]      fast_ap_info
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_station_fast_connect(const FAST_WF_CONNECTED_AP_INFO_T *fast_ap_info)
{
    // --- BEGIN: user implements ---
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief connect wifi with ssid and passwd
 *
 * @param[in]       ssid
 * @param[in]       passwd
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_station_connect(const int8_t *ssid, const int8_t *passwd)
{
    // --- BEGIN: user implements ---
    return 0;
    if (sniffer_set_done) {
        sniffer_set_done = FALSE;
        // IPC_APP_Notify_LED_Sound_Status_CB(IPC_REV_WIFI_CFG);
        usleep(1000 * 1000);
    }

    // IPC_APP_Notify_LED_Sound_Status_CB(IPC_CONNECTING_WIFI);

    if (NULL == ssid) {
        // get bind info from ethernet network
        printf("get bind info ...\n");
    } else {
        // get bind info from ap / wifi-smart / qrcode
        printf("get wifi info ...\n");
    }

    // TODO
    // Add a blocking operation for the wifi connection here.

    sleep(2);

    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief disconnect wifi from connect ap
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_station_disconnect(void)
{
    // --- BEGIN: user implements ---
    printf("STA Disconn AP\r\n");
    // Reserved

    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief get wifi connect rssi
 *
 * @param[out]      rssi        the return rssi
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_station_get_conn_ap_rssi(int8_t *rssi)
{
    // --- BEGIN: user implements ---
    if (NULL == rssi) {
        return OPRT_INVALID_PARM;
    }
    *rssi = 0;

#ifdef __HuaweiLite__
    // todo
    // liteos system
    // Implementation of RSSI acquisition
#else
    FILE *pp = popen("iwconfig " WLAN_DEV, "r");
    if (pp == NULL) {
        return OPRT_COM_ERROR;
    }

    char tmp[128] = {0};
    while (fgets(tmp, sizeof(tmp), pp) != NULL) {
        /* find signal  */
        char *pSIGNALStart = strstr(tmp, "Quality=");
        if (pSIGNALStart != NULL) {
            int x = 0;
            int y = 0;
            sscanf(pSIGNALStart + strlen("Quality="), "%d/%d", &x, &y);
            *rssi = x * 100 / (y + 1);
            break;
        }
    }
    pclose(pp);
#endif
    printf("Get Conn AP RSSI:%d\r\n", *rssi);

    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief get wifi station work status
 *
 * @param[out]      stat        the wifi station work status
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_station_get_status(WF_STATION_STAT_E *stat)
{
    // --- BEGIN: user implements ---
    if (NULL == stat) {
        return OPRT_INVALID_PARM;
    }
    *stat = WSS_GOT_IP; // Be sure to return in real time
    // Reserved
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief send wifi management
 *
 * @param[in]       buf         pointer to buffer
 * @param[in]       len         length of buffer
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_send_mgnt(const uint8_t *buf, const uint32_t len)
{
    // --- BEGIN: user implements ---
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief register receive wifi management callback
 *
 * @param[in]       enable
 * @param[in]       recv_cb     receive callback
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_register_recv_mgnt_callback(const BOOL_T enable, const WIFI_REV_MGNT_CB recv_cb)
{
    // --- BEGIN: user implements ---
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief wifi ioctl
 *
 * @param[in]       cmd     refer to WF_IOCTL_CMD_E
 * @param[in]       args    args associated with the command
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tkl_wifi_ioctl(WF_IOCTL_CMD_E cmd, void *args)
{
    // --- BEGIN: user implements ---
    return OPRT_OK;
    // --- END: user implements ---
}
