void ICACHE_FLASH_ATTR
    mesh_en_cb()
{
    INFO("--------------\r\n");
    INFO("MESH ENABLE CB in wifi connect\r\n");
    INFO("-------------\r\n");
    if(MESH_ONLINE_AVAIL == espconn_mesh_get_status()){
        INFO("MESH ONLINE, CONNECT TO SERVER...\r\n");
        user_esp_platform_connect_ap_cb();
    }else{
        INFO("MESH NOT ONLINE: %d, DO NOT CONNECT SERVER...\r\n",espconn_mesh_get_status());
    }

}
/******************************************************************************
 * FunctionName : esptouch_SuccessCb
 * Description  : esp-touch success callback
*******************************************************************************/
void ICACHE_FLASH_ATTR
    esptouch_SuccessCb(void* data)
{
    wifi_set_opmode(STATIONAP_MODE);
    
    os_timer_disarm(&esptouch_tout_t);//disable check timeout 
    #if LIGHT_DEVICE
    light_hint_stop(HINT_WHITE);
    #endif
    SC_INFO("ESP-TOUCH SUCCESS \r\n");
    
    SC_INFO("ENABLE LIGHT ACTION(ESP-NOW)");
    SC_INFO("debug: channel:%d\r\n",wifi_get_channel());
#if ESP_MESH_SUPPORT
    if(MESH_DISABLE == espconn_mesh_get_status()){
        //user_MeshStart();
        //mesh_enable_task();
    }
    user_esp_platform_connect_ap_cb();
    //user_MeshStart();
#else
    user_esp_platform_connect_ap_cb();
#endif
#if ESP_NOW_SUPPORT
    light_EspnowInit();
#endif
    SC_INFO("CONNECTED TO AP...ENABLE MESH AND RUN PLATFORM CODE ...WAIT...\r\n");

}
/******************************************************************************
 * FunctionName : mesh_InitStatusCheck
 * Description  : Only used in mesh init, to check the current status of mesh initialization,
                  and handle different situation accordingly
*******************************************************************************/
void ICACHE_FLASH_ATTR
mesh_InitStatusCheck()
{
    os_timer_disarm(&mesh_check_t);
    sint8 mesh_status = espconn_mesh_get_status();
    MESH_INFO("--------------\r\n");
    MESH_INFO("mesh status: %d ; %d\r\n",mesh_status,system_get_free_heap_size());
    MESH_INFO("--------------\r\n");
    
    if(mesh_status == MESH_DISABLE){
        MESH_INFO("MESH DISABLE , RUN FAIL CB ,retry:%d \r\n",LightMeshProc.init_retry);
        if(LightMeshProc.init_retry<MESH_INIT_RETRY_LIMIT 
			#if MESH_INIT_TIMEOUT_SET
			&& (mesh_GetStartMs()<MESH_INIT_TIME_LIMIT)
			#endif
			){
            LightMeshProc.init_retry+=1;
            espconn_mesh_enable(mesh_EnableCb, MESH_ONLINE);
            MESH_INFO("MESH RETRY : %d \r\n",LightMeshProc.init_retry);
        }else{
            mesh_StopCheckTimer();
            MESH_INFO("MESH INIT RETRY FAIL...\r\n");
            if(LightMeshProc.mesh_fail_cb){
                LightMeshProc.mesh_fail_cb(NULL);
            }
            LightMeshProc.init_retry = 0;
            return;
        }
    }
    else if(mesh_status==MESH_NET_CONN){
        MESH_INFO("MESH WIFI CONNECTED\r\n");
        mesh_StopCheckTimer();
    }
    os_timer_arm(&mesh_check_t,MESH_STATUS_CHECK_MS,0);
}
void ICACHE_FLASH_ATTR get_wifi2_mesh_common_status(const int8_t cid,
	const GetWifi2MeshCommonStatus *data) {
		os_bzero(&gw2mcsr.header, sizeof(gw2mcsr.header));

		gw2mcsr.header = data->header;
		gw2mcsr.header.length = sizeof(GetWifi2MeshCommonStatusReturn);

		gw2mcsr.status = espconn_mesh_get_status();
		gw2mcsr.is_root_node = espconn_mesh_is_root();
		gw2mcsr.is_root_candidate = espconn_mesh_is_root_candidate();
		gw2mcsr.connected_nodes = espconn_mesh_get_sub_dev_count();

		com_send(&gw2mcsr, sizeof(GetWifi2MeshCommonStatusReturn), cid);
}
void ICACHE_FLASH_ATTR
    WIFI_ConnectCb(uint8_t status)
{
#if 0
    if(0){//(wifiReconFlg && (ap_cache_if==false)){
        INFO("------------------\r\n");
        INFO("001\r\n");
        wifiReconFlg = false;
        INFO("WIFI RECONN FLG: %d \r\n",wifiReconFlg);
        INFO("DO AP CACHE\r\n");
        os_timer_disarm(&ap_cache_t);
        os_timer_setfn(&ap_cache_t,APCache_TimeoutCb,NULL);
        os_timer_arm(&ap_cache_t,AP_CACHE_TOUT_MS,0);
        APCache_Connect();  
        return;
    }
#endif
    
    if(status == STATION_GOT_IP){
        #if ESP_TOUCH_SUPPORT
        esptouch_setAckFlag(true);
        #endif
        //os_timer_disarm(&ap_cache_t);
        INFO("WIFI CONNECTED , RUN ESP PLATFORM...\r\n");
        #if ESP_MESH_SUPPORT
            if(MESH_DISABLE == espconn_mesh_get_status() ){
                _LINE_DESP();
                INFO("CONNECTED TO ROUTER, ENABLE MESH\r\n");
                _LINE_DESP();
                espconn_mesh_enable(mesh_en_cb,MESH_ONLINE);//debug
            }
        #else
            user_esp_platform_connect_ap_cb();
        #endif
    }else{
        if(status != STATION_CONNECTING){
            INFO("---------------------\r\n");
            INFO("STATION STATUS: %d \r\n",status);
			INFO("MESH ENABLE.\r\n");
            INFO("---------------------\r\n");
            //APCache_Connect();
            wifiReconFlg = false;
			wifi_SetReconnProcessAck();
			wifi_RestartMeshScan(2000);
        }

    }
}
/******************************************************************************
 * FunctionName : mesh_SuccessCb
 * Description  : callback func when mesh init finished successfully
                  In this demo , we run the platform code after mesh initialization
*******************************************************************************/
void ICACHE_FLASH_ATTR
mesh_SuccessCb(void* arg)
{
    _LINE_DESP();
    MESH_INFO("mesh log: mesh success!\r\n");
    MESH_INFO("CONNECTED, DO RUN ESP PLATFORM...\r\n");
    MESH_INFO("mesh status: %d\r\n",espconn_mesh_get_status());
    _LINE_DESP();
    
    //show light status at the first time mesh enables
    #if ESP_DEBUG_MODE
    	struct ip_info sta_ip;
		wifi_get_ip_info(STATION_IF,&sta_ip);
		if( espconn_mesh_local_addr(&sta_ip.ip)){
			MESH_INFO("THIS IS A MESH SUB NODE..\r\n");
			uint32 mlevel = sta_ip.ip.addr&0xff;
			light_ShowDevLevel(mlevel);//debug
		}else{
			MESH_INFO("THIS IS A MESH ROOT..\r\n");
			light_ShowDevLevel(1);//debug
		}
	#else
    if(mesh_init_flag){
        struct ip_info sta_ip;
        wifi_get_ip_info(STATION_IF,&sta_ip);
        if( espconn_mesh_local_addr(&sta_ip.ip)){
            MESH_INFO("THIS IS A MESH SUB NODE..\r\n");
            uint32 mlevel = sta_ip.ip.addr&0xff;
            light_ShowDevLevel(mlevel);//debug
        }else{
            MESH_INFO("THIS IS A MESH ROOT..\r\n");
            light_ShowDevLevel(1);//debug
        }
        mesh_init_flag = false;
    }else{
    
    }
	#endif
    
    #if ESP_NOW_SUPPORT
        //init ESP-NOW ,so that light can be controlled by ESP-NOW SWITCHER.
        light_EspnowInit();
    #endif
    WIFI_StartCheckIp();//debug
    //run esp-platform procedure,register to server.
    user_esp_platform_connect_ap_cb();//debug
    return;
}
/******************************************************************************
 * FunctionName : mesh_ReconCheck
 * Description  : in case that some router would record the DNS info.
                  If we got the IP addr from DNS , and still can't connect to esp-server
                  Call this check func to try enable and connect again every 20s
*******************************************************************************/
void ICACHE_FLASH_ATTR
mesh_ReconCheck()
{
    MESH_INFO("---------\r\n");
    MESH_INFO("mesh_ReconCheck\r\n");
    MESH_INFO("---------\r\n");
    os_timer_disarm(&mesh_user_t);
    sint8 mesh_status = espconn_mesh_get_status();
    MESH_INFO("MESH STATUS CHECK: %d \r\n",mesh_status);
    
    if(mesh_status == MESH_ONLINE_AVAIL){
        MESH_INFO("MESH ONLINE AVAIL\r\n");
        //user_esp_platform_sent_data();
        user_esp_platform_connect_ap_cb();
    }else{
        espconn_mesh_enable(mesh_EnableCb, MESH_ONLINE);
        os_timer_setfn(&mesh_user_t,mesh_ReconCheck,NULL);
        os_timer_arm(&mesh_user_t,20000,1);    
    }
}
static void ICACHE_FLASH_ATTR WIFI_CheckIp(void *arg)
{
    os_timer_disarm(&WiFiLinker);
    #if ESP_MESH_SUPPORT
        if(MESH_DISABLE != espconn_mesh_get_status()){
            /*MESH layer would handle wifi status exception at first*/
            //os_timer_setfn(&WiFiLinker, (os_timer_func_t *)WIFI_CheckIp, NULL);
            os_timer_arm(&WiFiLinker, 1000, 0);
            return;
        }else{
            if(wifi_GetReconnProcessAck() == false) wifiReconFlg = true;
            INFO("wifiReconFlg : %d \r\n",wifiReconFlg);
			INFO("wifiReconAck:  %d \r\n",wifi_GetReconnProcessAck());
            INFO("MESH STATUS : %d \r\n",espconn_mesh_get_status());
            INFO("WIFI STATUS : CUR:%d ; LAST:%d\r\n",wifiStatus,lastWifiStatus);
            INFO("----------------\r\n");
        }
    #endif
    
    struct ip_info ipConfig;
    wifi_get_ip_info(STATION_IF, &ipConfig);
    wifiStatus = wifi_station_get_connect_status();
    if (wifiStatus == STATION_GOT_IP && ipConfig.ip.addr != 0)
    {
		wifi_ClrReconnProcessAck();
        INFO("wifiReconAck SET : %d \r\n",wifi_GetReconnProcessAck());
        os_timer_arm(&WiFiLinker, 2000, 0);
    }
    else
    {
        if(wifi_station_get_connect_status() == STATION_WRONG_PASSWORD)
        {
            INFO("----------------\r\n");
            INFO("STATION_WRONG_PASSWORD\r\n");
            //wifi_station_connect();
        }
        else if(wifi_station_get_connect_status() == STATION_NO_AP_FOUND)
        {
            INFO("----------------\r\n");
            INFO("STATION_NO_AP_FOUND\r\n");
            //wifi_station_connect();
        }
        else if(wifi_station_get_connect_status() == STATION_CONNECT_FAIL)
        {
            INFO("----------------\r\n");
            INFO("STATION_CONNECT_FAIL\r\n");
            //wifi_station_connect();
        }
        else if(wifi_station_get_connect_status() == STATION_CONNECTING)
        {
            INFO("----------------\r\n");
            INFO("STATION_CONNECTING\r\n");
            //wifi_station_connect();
        }
        else if(wifi_station_get_connect_status() == STATION_IDLE)
        {
            INFO("----------------\r\n");
            INFO("STATION_IDLE\r\n");
            //INFO("TEST STATION STATUS: %d \r\n",wifi_station_get_connect_status());
        }else{
            INFO("STATUS ERROR\r\n");
        }
        //os_timer_setfn(&WiFiLinker, (os_timer_func_t *)WIFI_CheckIp, NULL);
        os_timer_arm(&WiFiLinker, 1000, 0);
    }
    if((wifiStatus != lastWifiStatus) || wifiReconFlg){
        lastWifiStatus = wifiStatus;
        if(wifiCb){
            wifiCb(wifiStatus);
        }else{
            WIFI_ConnectCb(wifiStatus);
        }
    }
}