]> granicus.if.org Git - esp-idf/commitdiff
tcpip_adapter/lwip: optimize wifi/ip event
authorLiu Zhi Fu <liuzhifu@espressif.com>
Wed, 19 Jul 2017 01:15:11 +0000 (09:15 +0800)
committerLiu Zhi Fu <liuzhifu@espressif.com>
Mon, 21 Aug 2017 06:36:44 +0000 (14:36 +0800)
components/esp32/event_default_handlers.c
components/esp32/include/esp_event.h
components/esp32/lib
components/lwip/core/ipv4/dhcp.c
components/tcpip_adapter/Kconfig [new file with mode: 0644]
components/tcpip_adapter/include/tcpip_adapter.h
components/tcpip_adapter/tcpip_adapter_lwip.c

index 75ef164651f28477c0a663035e1fa1cf720c11c5..8f1f2e93695aa84c6abd4300ce31b66618ca5a17 100644 (file)
@@ -55,6 +55,7 @@ static esp_err_t system_event_sta_stop_handle_default(system_event_t *event);
 static esp_err_t system_event_sta_connected_handle_default(system_event_t *event);
 static esp_err_t system_event_sta_disconnected_handle_default(system_event_t *event);
 static esp_err_t system_event_sta_got_ip_default(system_event_t *event);
+static esp_err_t system_event_sta_lost_ip_default(system_event_t *event);
 
 static esp_err_t system_event_eth_start_handle_default(system_event_t *event);
 static esp_err_t system_event_eth_stop_handle_default(system_event_t *event);
@@ -135,6 +136,12 @@ static esp_err_t system_event_sta_got_ip_default(system_event_t *event)
     return ESP_OK;
 }
 
+static esp_err_t system_event_sta_lost_ip_default(system_event_t *event)
+{
+    ESP_LOGI(TAG, "station ip lost");
+    return ESP_OK;
+}
+
 esp_err_t system_event_ap_start_handle_default(system_event_t *event)
 {
     tcpip_adapter_ip_info_t ap_ip;
@@ -191,17 +198,26 @@ esp_err_t system_event_sta_connected_handle_default(system_event_t *event)
         tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA);
     } else if (status == TCPIP_ADAPTER_DHCP_STOPPED) {
         tcpip_adapter_ip_info_t sta_ip;
+        tcpip_adapter_ip_info_t sta_old_ip;
 
         tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &sta_ip);
+        tcpip_adapter_get_old_ip_info(TCPIP_ADAPTER_IF_STA, &sta_old_ip);
 
         if (!(ip4_addr_isany_val(sta_ip.ip) || ip4_addr_isany_val(sta_ip.netmask) || ip4_addr_isany_val(sta_ip.gw))) {
             system_event_t evt;
 
-            //notify event
             evt.event_id = SYSTEM_EVENT_STA_GOT_IP;
+            evt.event_info.got_ip.ip_changed = false;
+
+            if (memcmp(&sta_ip, &sta_old_ip, sizeof(sta_ip))) {
+                evt.event_info.got_ip.ip_changed = true;
+            }
+
             memcpy(&evt.event_info.got_ip.ip_info, &sta_ip, sizeof(tcpip_adapter_ip_info_t));
+            tcpip_adapter_set_old_ip_info(TCPIP_ADAPTER_IF_STA, &sta_ip);
 
             esp_event_send(&evt);
+            ESP_LOGD(TAG, "static ip: ip changed=%d", evt.event_info.got_ip.ip_changed);
         } else {
             ESP_LOGE(TAG, "invalid static ip");
         }
@@ -261,12 +277,16 @@ static esp_err_t esp_system_event_debug(system_event_t *event)
     }
     case SYSTEM_EVENT_STA_GOT_IP: {
         system_event_sta_got_ip_t *got_ip = &event->event_info.got_ip;
-        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_GOTIP, ip:" IPSTR ", mask:" IPSTR ", gw:" IPSTR,
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_GOT_IP, ip:" IPSTR ", mask:" IPSTR ", gw:" IPSTR,
             IP2STR(&got_ip->ip_info.ip),
             IP2STR(&got_ip->ip_info.netmask),
             IP2STR(&got_ip->ip_info.gw));
         break;
     }
+    case SYSTEM_EVENT_STA_LOST_IP: {
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_LOST_IP");
+        break;
+    }
     case SYSTEM_EVENT_STA_WPS_ER_SUCCESS: {
         ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_SUCCESS");
         break;
@@ -381,6 +401,7 @@ void esp_event_set_default_wifi_handlers()
      default_event_handlers[SYSTEM_EVENT_STA_CONNECTED]    = system_event_sta_connected_handle_default;
      default_event_handlers[SYSTEM_EVENT_STA_DISCONNECTED] = system_event_sta_disconnected_handle_default;
      default_event_handlers[SYSTEM_EVENT_STA_GOT_IP]       = system_event_sta_got_ip_default;
+     default_event_handlers[SYSTEM_EVENT_STA_LOST_IP]      = system_event_sta_lost_ip_default;
      default_event_handlers[SYSTEM_EVENT_AP_START]         = system_event_ap_start_handle_default;
      default_event_handlers[SYSTEM_EVENT_AP_STOP]          = system_event_ap_stop_handle_default;
 
index 5cb60dba63c7f294a28837af6a059b8b12d87c43..ccffdb8186e3cb2a02889dc1c33fa34edc7bf251 100644 (file)
@@ -35,6 +35,7 @@ typedef enum {
     SYSTEM_EVENT_STA_DISCONNECTED,         /**< ESP32 station disconnected from AP */
     SYSTEM_EVENT_STA_AUTHMODE_CHANGE,      /**< the auth mode of AP connected by ESP32 station changed */
     SYSTEM_EVENT_STA_GOT_IP,               /**< ESP32 station got IP from connected AP */
+    SYSTEM_EVENT_STA_LOST_IP,              /**< ESP32 station lost IP and the IP is reset to 0 */
     SYSTEM_EVENT_STA_WPS_ER_SUCCESS,       /**< ESP32 station wps succeeds in enrollee mode */
     SYSTEM_EVENT_STA_WPS_ER_FAILED,        /**< ESP32 station wps fails in enrollee mode */
     SYSTEM_EVENT_STA_WPS_ER_TIMEOUT,       /**< ESP32 station wps timeout in enrollee mode */
@@ -86,6 +87,7 @@ typedef struct {
 
 typedef struct {
     tcpip_adapter_ip_info_t ip_info;
+    bool ip_changed;
 } system_event_sta_got_ip_t;
 
 typedef struct {
@@ -116,7 +118,7 @@ typedef union {
     system_event_sta_disconnected_t            disconnected;       /**< ESP32 station disconnected to AP */
     system_event_sta_scan_done_t               scan_done;          /**< ESP32 station scan (APs) done */
     system_event_sta_authmode_change_t         auth_change;        /**< the auth mode of AP ESP32 station connected to changed */
-    system_event_sta_got_ip_t                  got_ip;             /**< ESP32 station got IP */
+    system_event_sta_got_ip_t                  got_ip;             /**< ESP32 station got IP, first time got IP or when IP is changed */
     system_event_sta_wps_er_pin_t              sta_er_pin;         /**< ESP32 station WPS enrollee mode PIN code received */
     system_event_sta_wps_fail_reason_t         sta_er_fail_reason;/**< ESP32 station WPS enrollee mode failed reason code received */
     system_event_ap_staconnected_t             sta_connected;      /**< a station connected to ESP32 soft-AP */
index 6fda896660d001dd6d4aec5bae2a294a757d4276..0189f203c202a1bc27c3b76ab8c2575bcf3662b7 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 6fda896660d001dd6d4aec5bae2a294a757d4276
+Subproject commit 0189f203c202a1bc27c3b76ab8c2575bcf3662b7
index 1c18494e15d290eac1f45484665dafc3026078f7..74c9403dc86936d2fd09a35c0200b0119da5f770 100755 (executable)
@@ -270,6 +270,15 @@ dhcp_handle_nak(struct netif *netif)
     (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
   /* remove IP address from interface (must no longer be used, as per RFC2131) */
   netif_set_addr(netif, IP4_ADDR_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY);
+
+  if (dhcp->cb != NULL) {
+#ifdef ESP_LWIP
+    dhcp->cb(netif);
+#else
+    dhcp->cb();
+#endif
+  }
+
   /* Change to a defined state */
   dhcp_set_state(dhcp, DHCP_STATE_BACKING_OFF);
   /* We can immediately restart discovery */
@@ -1413,6 +1422,14 @@ dhcp_release(struct netif *netif)
   /* remove IP address from interface (prevents routing from selecting this interface) */
   netif_set_addr(netif, IP4_ADDR_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY);
 
+  if (dhcp->cb != NULL) {
+#ifdef ESP_LWIP
+    dhcp->cb(netif);
+#else
+    dhcp->cb();
+#endif
+  }
+
   return result;
 }
 
diff --git a/components/tcpip_adapter/Kconfig b/components/tcpip_adapter/Kconfig
new file mode 100644 (file)
index 0000000..eecf120
--- /dev/null
@@ -0,0 +1,16 @@
+menu "tcpip adapter"
+
+config IP_LOST_TIMER_INTERVAL
+    int "IP Address lost timer interval (seconds)"
+    range 0 65535
+    default 120
+    help
+        The value of 0 indicates the IP lost timer is disabled, otherwise the timer is enabled.
+        
+        The IP address may be lost because of some reasons, e.g. when the station disconnects
+        from soft-AP, or when DHCP IP renew fails etc. If the IP lost timer is enabled, it will 
+        be started everytime the IP is lost. Event SYSTEM_EVENT_STA_LOST_IP will be raised if
+        the timer expires. The IP lost timer is stopped if the station get the IP again before
+        the timer expires.
+
+endmenu
index 6d99b4a81146a9f9f7b3db431365755cc875f202..2e6db6b5a71cfce77fc59ac6b71aeaabbf92a201 100644 (file)
@@ -154,6 +154,10 @@ typedef struct tcpip_adapter_api_msg_s {
 
 #define TCPIP_ADAPTER_IPC_CALL(_if, _mac, _ip, _hostname, _fn) do {\
     tcpip_adapter_api_msg_t msg;\
+    if (tcpip_inited == false) {\
+        ESP_LOGE(TAG, "tcpip_adapter is not initialized!");\
+        abort();\
+    }\
     memset(&msg, 0, sizeof(msg));\
     msg.tcpip_if = (_if);\
     msg.mac      = (_mac);\
@@ -168,6 +172,9 @@ typedef struct tcpip_adapter_api_msg_s {
     }\
 }while(0)
 
+typedef struct tcpip_adatper_ip_lost_timer_s {
+    bool timer_running;
+} tcpip_adapter_ip_lost_timer_t;
 
 /**
  * @brief  Initialize tcpip adapter
@@ -278,13 +285,44 @@ esp_err_t tcpip_adapter_get_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_i
  * This function is mainly used for setting static IP.
  *
  * @param[in]  tcpip_if: the interface which we want to set IP information
- * @param[in]  ip_info: If successful, IP information will be returned in this argument.
+ * @param[in]  ip_info: store the IP information which needs to be set to specified interface
  *
  * @return ESP_OK
  *         ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS
  */
 esp_err_t tcpip_adapter_set_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ip_info_t *ip_info);
 
+/**
+ * @brief  Get interface's old IP information
+ *
+ * When the interface successfully gets a valid IP from DHCP server or static configured, a copy of 
+ * the IP information is set to the old IP information. When IP lost timer expires, the old IP 
+ * information is reset to 0.
+ *
+ * @param[in]   tcpip_if: the interface which we want to get old IP information
+ * @param[out]  ip_info: If successful, IP information will be returned in this argument.
+ *
+ * @return ESP_OK
+ *         ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS
+ */
+esp_err_t tcpip_adapter_get_old_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ip_info_t *ip_info);
+
+/**
+ * @brief  Set interface's old IP information
+ *
+ * When the interface successfully gets a valid IP from DHCP server or static configured, a copy of 
+ * the IP information is set to the old IP information. When IP lost timer expires, the old IP 
+ * information is reset to 0.
+ *
+ * @param[in]  tcpip_if: the interface which we want to set old IP information
+ * @param[in]  ip_info: store the IP information which needs to be set to specified interface
+ *
+ * @return ESP_OK
+ *         ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS
+ */
+esp_err_t tcpip_adapter_set_old_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ip_info_t *ip_info);
+
+
 /**
  * @brief  create interface's linklocal IPv6 information
  *
index a04c527b66f3ad8752ab9e98123e130fb9926c85..b1bb85bc25237fed099435e69d93c1d5ecb9def7 100644 (file)
 
 static struct netif *esp_netif[TCPIP_ADAPTER_IF_MAX];
 static tcpip_adapter_ip_info_t esp_ip[TCPIP_ADAPTER_IF_MAX];
+static tcpip_adapter_ip_info_t esp_ip_old[TCPIP_ADAPTER_IF_MAX];
 static tcpip_adapter_ip6_info_t esp_ip6[TCPIP_ADAPTER_IF_MAX];
 static netif_init_fn esp_netif_init_fn[TCPIP_ADAPTER_IF_MAX];
+static tcpip_adapter_ip_lost_timer_t esp_ip_lost_timer[TCPIP_ADAPTER_IF_MAX];
 
 static tcpip_adapter_dhcp_status_t dhcps_status = TCPIP_ADAPTER_DHCP_INIT;
 static tcpip_adapter_dhcp_status_t dhcpc_status[TCPIP_ADAPTER_IF_MAX] = {TCPIP_ADAPTER_DHCP_INIT};
@@ -55,7 +57,12 @@ static esp_err_t tcpip_adapter_dhcps_stop_api(tcpip_adapter_api_msg_t * msg);
 static esp_err_t tcpip_adapter_dhcpc_start_api(tcpip_adapter_api_msg_t * msg);
 static esp_err_t tcpip_adapter_dhcpc_stop_api(tcpip_adapter_api_msg_t * msg);
 static esp_err_t tcpip_adapter_set_hostname_api(tcpip_adapter_api_msg_t * msg);
+static esp_err_t tcpip_adapter_reset_ip_info(tcpip_adapter_if_t tcpip_if);
+static esp_err_t tcpip_adapter_start_ip_lost_timer(tcpip_adapter_if_t tcpip_if);
+static void tcpip_adapter_ip_lost_timer(void *arg);
 static sys_sem_t api_sync_sem = NULL;
+static bool tcpip_inited = false;
+static sys_sem_t api_lock_sem = NULL;
 extern sys_thread_t g_lwip_task;
 
 #define TAG "tcpip_adapter"
@@ -78,7 +85,6 @@ static void tcpip_adapter_api_cb(void* api_msg)
 
 void tcpip_adapter_init(void)
 {
-    static bool tcpip_inited = false;
     int ret;
 
     if (tcpip_inited == false) {
@@ -87,12 +93,19 @@ void tcpip_adapter_init(void)
         tcpip_init(NULL, NULL);
 
         memset(esp_ip, 0, sizeof(tcpip_adapter_ip_info_t)*TCPIP_ADAPTER_IF_MAX);
+        memset(esp_ip_old, 0, sizeof(tcpip_adapter_ip_info_t)*TCPIP_ADAPTER_IF_MAX);
+
         IP4_ADDR(&esp_ip[TCPIP_ADAPTER_IF_AP].ip, 192, 168 , 4, 1);
         IP4_ADDR(&esp_ip[TCPIP_ADAPTER_IF_AP].gw, 192, 168 , 4, 1);
         IP4_ADDR(&esp_ip[TCPIP_ADAPTER_IF_AP].netmask, 255, 255 , 255, 0);
         ret = sys_sem_new(&api_sync_sem, 0);
         if (ERR_OK != ret) {
-            ESP_LOGD(TAG, "tcpip adatper api sync sem init fail");
+            ESP_LOGE(TAG, "tcpip adatper api sync sem init fail");
+        }
+
+        ret = sys_sem_new(&api_lock_sem, 1);
+        if (ERR_OK != ret) {
+            ESP_LOGE(TAG, "tcpip adatper api lock sem init fail");
         }
     }
 }
@@ -114,7 +127,9 @@ static int tcpip_adapter_ipc_check(tcpip_adapter_api_msg_t *msg)
         return TCPIP_ADAPTER_IPC_LOCAL;
     }
 
+    sys_arch_sem_wait(&api_lock_sem, 0);
     tcpip_send_api_msg((tcpip_callback_fn)tcpip_adapter_api_cb, msg, &api_sync_sem);
+    sys_sem_signal(&api_lock_sem);
 
     return TCPIP_ADAPTER_IPC_REMOTE;
 #else
@@ -224,9 +239,7 @@ esp_err_t tcpip_adapter_stop(tcpip_adapter_if_t tcpip_if)
 
         dhcpc_status[tcpip_if] = TCPIP_ADAPTER_DHCP_INIT;
 
-        ip4_addr_set_zero(&esp_ip[tcpip_if].ip);
-        ip4_addr_set_zero(&esp_ip[tcpip_if].gw);
-        ip4_addr_set_zero(&esp_ip[tcpip_if].netmask);
+        tcpip_adapter_reset_ip_info(tcpip_if);
     }
 
     netif_set_down(esp_netif[tcpip_if]);
@@ -295,15 +308,12 @@ esp_err_t tcpip_adapter_down(tcpip_adapter_if_t tcpip_if)
 
             dhcpc_status[tcpip_if] = TCPIP_ADAPTER_DHCP_INIT;
 
-            ip4_addr_set_zero(&esp_ip[tcpip_if].ip);
-            ip4_addr_set_zero(&esp_ip[tcpip_if].gw);
-            ip4_addr_set_zero(&esp_ip[tcpip_if].netmask);
+            tcpip_adapter_reset_ip_info(tcpip_if);
         }
 
-        /* Modify ip address to trigger tcp/udp pcb cleanup */
         netif_set_addr(esp_netif[tcpip_if], IP4_ADDR_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY);
-
         netif_set_down(esp_netif[tcpip_if]);
+        tcpip_adapter_start_ip_lost_timer(tcpip_if);
     }
 
     return ESP_OK;
@@ -314,6 +324,33 @@ static esp_err_t tcpip_adapter_down_api(tcpip_adapter_api_msg_t * msg)
     return tcpip_adapter_down(msg->tcpip_if);
 }
 
+esp_err_t tcpip_adapter_set_old_ip_info_api(tcpip_adapter_api_msg_t * msg)
+{
+    memcpy(&esp_ip_old[msg->tcpip_if], msg->ip_info, sizeof(tcpip_adapter_ip_info_t));
+    return ESP_OK;
+}
+
+esp_err_t tcpip_adapter_set_old_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ip_info_t *ip_info)
+{
+    if (tcpip_if >= TCPIP_ADAPTER_IF_MAX || ip_info == NULL) {
+        return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
+    }
+
+    TCPIP_ADAPTER_IPC_CALL(tcpip_if, 0, ip_info, 0, tcpip_adapter_set_old_ip_info_api);
+
+    return ESP_OK;
+}
+
+esp_err_t tcpip_adapter_get_old_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ip_info_t *ip_info)
+{
+    if (tcpip_if >= TCPIP_ADAPTER_IF_MAX || ip_info == NULL) {
+        return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
+    }
+
+    memcpy(ip_info, &esp_ip_old[tcpip_if], sizeof(tcpip_adapter_ip_info_t));
+    return ESP_OK;
+}
+
 esp_err_t tcpip_adapter_get_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ip_info_t *ip_info)
 {
     struct netif *p_netif;
@@ -378,6 +415,20 @@ esp_err_t tcpip_adapter_set_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_i
 
     if (p_netif != NULL && netif_is_up(p_netif)) {
         netif_set_addr(p_netif, &ip_info->ip, &ip_info->netmask, &ip_info->gw);
+        if (!(ip4_addr_isany_val(ip_info->ip) || ip4_addr_isany_val(ip_info->ip) || ip4_addr_isany_val(ip_info->ip))) {
+            system_event_t evt;
+            evt.event_id = SYSTEM_EVENT_STA_GOT_IP;
+            evt.event_info.got_ip.ip_changed = false;
+
+            if (memcmp(ip_info, &esp_ip_old[tcpip_if], sizeof(tcpip_adapter_ip_info_t))) {
+                evt.event_info.got_ip.ip_changed = true;
+            }
+
+            memcpy(&evt.event_info.got_ip.ip_info, ip_info, sizeof(tcpip_adapter_ip_info_t));
+            memcpy(&esp_ip_old[tcpip_if], ip_info, sizeof(tcpip_adapter_ip_info_t));
+            esp_event_send(&evt);
+            ESP_LOGD(TAG, "if%d tcpip adapter set static ip: ip changed=%d", tcpip_if, evt.event_info.got_ip.ip_changed);
+        }
     }
 
     return ESP_OK;
@@ -675,24 +726,30 @@ esp_err_t tcpip_adapter_dhcpc_option(tcpip_adapter_option_mode_t opt_op, tcpip_a
 
 static void tcpip_adapter_dhcpc_cb(struct netif *netif)
 {
+    tcpip_adapter_ip_info_t *ip_info_old = NULL;
+    tcpip_adapter_ip_info_t *ip_info = NULL;
+    tcpip_adapter_if_t tcpip_if;
+
     if (!netif) {
         ESP_LOGD(TAG, "null netif=%p", netif);
         return;
     }
 
-    if (netif != esp_netif[TCPIP_ADAPTER_IF_STA] && netif != esp_netif[TCPIP_ADAPTER_IF_ETH]) {
+    if( netif == esp_netif[TCPIP_ADAPTER_IF_STA] ) {
+        tcpip_if = TCPIP_ADAPTER_IF_STA;
+    } else if(netif == esp_netif[TCPIP_ADAPTER_IF_ETH] ) {
+        tcpip_if = TCPIP_ADAPTER_IF_ETH;
+    } else { 
         ESP_LOGD(TAG, "err netif=%p", netif);
         return;
     }
 
-    if ( !ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), IP4_ADDR_ANY) ) {
-        tcpip_adapter_ip_info_t *ip_info = NULL;
-        if( netif == esp_netif[TCPIP_ADAPTER_IF_STA] ) {
-            ip_info = &esp_ip[TCPIP_ADAPTER_IF_STA];
-        } else if(netif == esp_netif[TCPIP_ADAPTER_IF_ETH] ) {
-            ip_info = &esp_ip[TCPIP_ADAPTER_IF_ETH];
-        } 
+    ESP_LOGD(TAG, "if%d dhcpc cb", tcpip_if);
+    ip_info = &esp_ip[tcpip_if];
+    ip_info_old = &esp_ip_old[tcpip_if];
 
+    if ( !ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), IP4_ADDR_ANY) ) {
+        
         //check whether IP is changed
         if ( !ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), &ip_info->ip) ||
                 !ip4_addr_cmp(ip_2_ip4(&netif->netmask), &ip_info->netmask) ||
@@ -704,23 +761,83 @@ static void tcpip_adapter_dhcpc_cb(struct netif *netif)
             ip4_addr_set(&ip_info->gw, ip_2_ip4(&netif->gw));
 
             //notify event
-            if (netif == esp_netif[TCPIP_ADAPTER_IF_STA]) {
-                evt.event_id = SYSTEM_EVENT_STA_GOT_IP;
-            } else if (netif == esp_netif[TCPIP_ADAPTER_IF_ETH]) {
-                evt.event_id = SYSTEM_EVENT_ETH_GOT_IP;
+            evt.event_id = SYSTEM_EVENT_STA_GOT_IP;
+            evt.event_info.got_ip.ip_changed = false;
+
+            if (memcmp(ip_info, ip_info_old, sizeof(tcpip_adapter_ip_info_t))) {
+                evt.event_info.got_ip.ip_changed = true;
             }
 
             memcpy(&evt.event_info.got_ip.ip_info, ip_info, sizeof(tcpip_adapter_ip_info_t));
-
+            memcpy(ip_info_old, ip_info, sizeof(tcpip_adapter_ip_info_t));
+            ESP_LOGD(TAG, "if%d ip changed=%d", tcpip_if, evt.event_info.got_ip.ip_changed);
             esp_event_send(&evt);
         } else {
-            ESP_LOGD(TAG, "ip unchanged");
+            ESP_LOGD(TAG, "if%d ip unchanged", tcpip_if);
+        }
+    } else {
+        if (!ip4_addr_cmp(&ip_info->ip, IP4_ADDR_ANY)) {
+            tcpip_adapter_start_ip_lost_timer(tcpip_if);
         }
     }
 
     return;
 }
 
+static esp_err_t tcpip_adapter_start_ip_lost_timer(tcpip_adapter_if_t tcpip_if)
+{
+    tcpip_adapter_ip_info_t *ip_info_old = &esp_ip_old[tcpip_if];
+    struct netif *netif = esp_netif[tcpip_if];
+
+    ESP_LOGD(TAG, "if%d start ip lost tmr: enter", tcpip_if);
+    if (tcpip_if != TCPIP_ADAPTER_IF_STA) {
+        ESP_LOGD(TAG, "if%d start ip lost tmr: only sta support ip lost timer", tcpip_if);
+        return ESP_OK;
+    }
+
+    if (esp_ip_lost_timer[tcpip_if].timer_running) {
+        ESP_LOGD(TAG, "if%d start ip lost tmr: already started", tcpip_if);
+        return ESP_OK;
+    }
+
+    if ( netif && (CONFIG_IP_LOST_TIMER_INTERVAL > 0) && !ip4_addr_isany_val(ip_info_old->ip)) {
+        esp_ip_lost_timer[tcpip_if].timer_running = true;
+        sys_timeout(CONFIG_IP_LOST_TIMER_INTERVAL*1000, tcpip_adapter_ip_lost_timer, (void*)tcpip_if);
+        ESP_LOGD(TAG, "if%d start ip lost tmr: interval=%d", tcpip_if, CONFIG_IP_LOST_TIMER_INTERVAL);
+        return ESP_OK;
+    }
+
+    ESP_LOGD(TAG, "if%d start ip lost tmr: no need start because netif=%p interval=%d ip=%x", 
+                  tcpip_if, netif, CONFIG_IP_LOST_TIMER_INTERVAL, ip_info_old->ip.addr);
+
+    return ESP_OK;
+}
+
+static void tcpip_adapter_ip_lost_timer(void *arg)
+{
+    tcpip_adapter_if_t tcpip_if = (tcpip_adapter_if_t)arg;
+
+    ESP_LOGD(TAG, "if%d ip lost tmr: enter", tcpip_if);
+    esp_ip_lost_timer[tcpip_if].timer_running = false;
+
+    if (tcpip_if == TCPIP_ADAPTER_IF_STA) {
+        struct netif *netif = esp_netif[tcpip_if];
+
+        if ( (!netif) || (netif && ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), IP4_ADDR_ANY))){
+            system_event_t evt;
+
+            ESP_LOGD(TAG, "if%d ip lost tmr: raise ip lost event", tcpip_if);
+            memset(&esp_ip_old[tcpip_if], 0, sizeof(tcpip_adapter_ip_info_t));
+            evt.event_id = SYSTEM_EVENT_STA_LOST_IP;
+            esp_event_send(&evt);
+        } else {
+            ESP_LOGD(TAG, "if%d ip lost tmr: no need raise ip lost event", tcpip_if);
+        }
+    } else {
+        ESP_LOGD(TAG, "if%d ip lost tmr: not station", tcpip_if);
+    }
+}
+
 esp_err_t tcpip_adapter_dhcpc_get_status(tcpip_adapter_if_t tcpip_if, tcpip_adapter_dhcp_status_t *status)
 {
     *status = dhcpc_status[tcpip_if];
@@ -741,9 +858,7 @@ esp_err_t tcpip_adapter_dhcpc_start(tcpip_adapter_if_t tcpip_if)
     if (dhcpc_status[tcpip_if] != TCPIP_ADAPTER_DHCP_STARTED) {
         struct netif *p_netif = esp_netif[tcpip_if];
 
-        ip4_addr_set_zero(&esp_ip[tcpip_if].ip);
-        ip4_addr_set_zero(&esp_ip[tcpip_if].gw);
-        ip4_addr_set_zero(&esp_ip[tcpip_if].netmask);
+        tcpip_adapter_reset_ip_info(tcpip_if);
 
         if (p_netif != NULL) {
             if (netif_is_up(p_netif)) {
@@ -751,6 +866,7 @@ esp_err_t tcpip_adapter_dhcpc_start(tcpip_adapter_if_t tcpip_if)
                 ip_addr_set_zero(&p_netif->ip_addr);
                 ip_addr_set_zero(&p_netif->netmask);
                 ip_addr_set_zero(&p_netif->gw);
+                tcpip_adapter_start_ip_lost_timer(tcpip_if);
             } else {
                 ESP_LOGD(TAG, "dhcp client re init");
                 dhcpc_status[tcpip_if] = TCPIP_ADAPTER_DHCP_INIT;
@@ -798,10 +914,8 @@ esp_err_t tcpip_adapter_dhcpc_stop(tcpip_adapter_if_t tcpip_if)
 
         if (p_netif != NULL) {
             dhcp_stop(p_netif);
-
-            ip4_addr_set_zero(&esp_ip[tcpip_if].ip);
-            ip4_addr_set_zero(&esp_ip[tcpip_if].gw);
-            ip4_addr_set_zero(&esp_ip[tcpip_if].netmask);
+            tcpip_adapter_reset_ip_info(tcpip_if);
+            tcpip_adapter_start_ip_lost_timer(tcpip_if);
         } else {
             ESP_LOGD(TAG, "dhcp client if not ready");
             return ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY;
@@ -934,4 +1048,12 @@ esp_err_t tcpip_adapter_get_hostname(tcpip_adapter_if_t tcpip_if, const char **h
 #endif
 }
 
+static esp_err_t tcpip_adapter_reset_ip_info(tcpip_adapter_if_t tcpip_if)
+{
+    ip4_addr_set_zero(&esp_ip[tcpip_if].ip);
+    ip4_addr_set_zero(&esp_ip[tcpip_if].gw);
+    ip4_addr_set_zero(&esp_ip[tcpip_if].netmask);
+    return ESP_OK;
+}
+
 #endif /* CONFIG_TCPIP_LWIP */