main/task_wifi.c

changeset 0
913eb9ca40b1
child 1
86b275481021
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/task_wifi.c	Thu Oct 19 17:32:16 2023 +0200
@@ -0,0 +1,422 @@
+/**
+ * @file task_wifi.c
+ * @brief WiFi task. Connect to the known AP with the strongest signal.
+ */
+
+
+#include "dcf77tx.h"
+
+#define	MAX_AP_NUM		10
+
+static const char *TAG = "task_wifi";
+
+
+SemaphoreHandle_t       	xSemaphoreWiFi = NULL;		///< Semaphore WiFi task.
+EventGroupHandle_t		xEventGroupWifi;		///< Events WiFi task.
+uint16_t			ap_num = MAX_AP_NUM;		///< Scan counter.
+wifi_ap_record_t		*accessp_records;		///< [MAX_AP_NUM] records array with scan results.
+wifi_config_t			*task_wifi_ConfigSTA = NULL;	///< Current STA configuration.
+WIFI_State			*wifi_state = NULL;		///< Public state for other tasks.
+esp_netif_t			*sta_netif = NULL;		///< Station interface
+
+
+wifi_scan_config_t scan_config = {				///< WiFi scanner configuration.
+    .ssid = (uint8_t *)CONFIG_ESP_WIFI_SSID,
+    .bssid = 0,
+    .channel = 0,
+    .show_hidden = false
+};
+
+bool				_wifi_ScanDone = false;		///< Scan ready
+bool				_wifi_BetterAP = false;		///< If better AP available.
+int8_t				_wifi_RSSI = -127;		///< Latest RSSI level.
+uint16_t			_wifi_Scanned = 0;		///< Total scanned APs.
+
+extern char			hostname[];			///< Generated hostname
+
+
+
+const int TASK_WIFI_REQUEST_STA_DISCONNECT = BIT0;		///< When set, means a client requested to disconnect from currently connected AP.
+const int TASK_WIFI_REQUEST_STA_CONNECT = BIT1;			///< When set, means a client requested to connect to an access point.
+const int TASK_WIFI_REQUEST_STA_SCAN = BIT2;			///< When set, means a client requested a AP scan.
+const int TASK_WIFI_REQUEST_STA_STATUS = BIT3;			///< When set, means a client requested to update the connection status.
+
+const int TASK_WIFI_HAS_IP = BIT4;				///< Indicate that we have an IP address
+const int TASK_WIFI_STA_FAILED = BIT5;				///< Indicate that we could not get a connection to AP as station.
+const int TASK_WIFI_STA_DISCONNECTED = BIT6;			///< Indicate that we are disconnected from an ap station.
+const int TASK_WIFI_STA_CONNECTED = BIT7;			///< Indicate that we are connected to AP as station, flip of BIT5.
+
+
+
+/**
+ * @brief Array with AP security names
+ */
+const char *apsec[] = { "Open", "WEP", "WPA", "WPA2", "WPA WPA2", "Enterprise" };
+
+
+/****************************************************************************/
+
+
+bool ready_WiFi(void)
+{
+    if (wifi_state->STA_connected && wifi_state->STA_online)
+        return true;
+    return false;
+}
+
+
+
+void status_WiFi(void)
+{
+    xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_STATUS);
+}
+
+
+
+void request_WiFi(void)
+{
+    xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
+}
+
+
+void scan_WiFi(void)
+{
+    xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_SCAN);
+}
+
+
+void disconnect_WiFi(void)
+{
+    xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT);
+    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
+}
+
+
+static void print_servers(void)
+{
+    ESP_LOGI(TAG, "List of configured NTP servers:");
+
+    for (uint8_t i = 0; i < SNTP_MAX_SERVERS; ++i){
+        if (esp_sntp_getservername(i)){
+            ESP_LOGI(TAG, "server %d: %s", i, esp_sntp_getservername(i));
+        } else {
+            // we have either IPv4 or IPv6 address, let's print it
+            char buff[64];
+            ip_addr_t const *ip = esp_sntp_getserver(i);
+            if (ipaddr_ntoa_r(ip, buff, 64) != NULL)
+                ESP_LOGI(TAG, "server %d: %s", i, buff);
+        }
+    }
+}
+
+
+static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
+{
+    switch (event_id) {
+
+	case WIFI_EVENT_SCAN_DONE:
+	    {
+            	/* Get the results so the memory used is freed. */
+            	ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&ap_num, accessp_records));
+		ESP_LOGI(TAG, "Event wifi Scane done, %d records", ap_num);
+		_wifi_BetterAP = false;
+		for (int i = 0; i < ap_num; i++) {
+		    wifi_ap_record_t ap = accessp_records[i];
+		    ESP_LOGI(TAG, "AP:%d bssid:%02x:%02x:%02x:%02x:%02x:%02x ssid:%s ch:%d rssi:%d",
+					i, ap.bssid[0], ap.bssid[1], ap.bssid[2], ap.bssid[3], ap.bssid[4], ap.bssid[5],
+					ap.ssid, ap.primary, ap.rssi);
+		    if (ap.rssi > CONFIG_ESP_WIFI_ROAMING_LEVEL && ap.rssi > (_wifi_RSSI + 3)) {
+			_wifi_BetterAP = true;
+			ESP_LOGI(TAG, "AP:%d is a better AP", i);
+		    }
+		}
+            	_wifi_Scanned = ap_num;
+            	_wifi_ScanDone = true;
+		if (_wifi_BetterAP) {
+		    ESP_LOGI(TAG, "Disconnect current AP");
+		    disconnect_WiFi();
+		}
+	    	break;
+	    }
+
+	case WIFI_EVENT_STA_START:
+	    {
+		ESP_LOGI(TAG, "Event wifi START");
+        	// Set the configured hostname for the dhcp client.
+        	ESP_ERROR_CHECK(esp_netif_set_hostname(sta_netif, hostname));
+        	esp_wifi_connect();
+		_wifi_BetterAP = false;
+		break;
+	    }
+
+	case WIFI_EVENT_STA_CONNECTED:
+	    {
+		wifi_event_sta_connected_t* event = (wifi_event_sta_connected_t*) event_data;
+                wifi_ap_record_t ap_info;
+                esp_wifi_sta_get_ap_info(&ap_info);
+		ESP_LOGI(TAG, "Event STA connected, ssid:%s, bssid:" MACSTR ", channel:%d, rssi: %d, authmode:%s",
+                       ap_info.ssid, MAC2STR(ap_info.bssid), event->channel, ap_info.rssi, apsec[event->authmode]);
+                if (xSemaphoreTake(xSemaphoreWiFi, 35) == pdTRUE) {
+                    wifi_state->STA_connected = true;
+                    wifi_state->STA_rssi = ap_info.rssi;
+		    wifi_state->STA_channel = ap_info.primary;
+                    sprintf(wifi_state->STA_ssid, "%s", ap_info.ssid);
+		    snprintf(wifi_state->STA_bssid, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
+			     ap_info.bssid[0], ap_info.bssid[1], ap_info.bssid[2], ap_info.bssid[3], ap_info.bssid[4], ap_info.bssid[5]);
+                    xSemaphoreGive(xSemaphoreWiFi);
+                } else {
+		    ESP_LOGE(TAG, "wifi_event_handler() lock error WIFI_EVENT_STA_CONNECTED");
+		}
+		print_servers();
+		_wifi_BetterAP = false;
+                xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED);
+                xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED);
+	    	break;
+	    }
+
+	case WIFI_EVENT_STA_DISCONNECTED:
+	    {
+		wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data;
+
+                ESP_LOGI(TAG, "Event STA disconnected, ssid:%s, ssid_len:%d, bssid:" MACSTR ", reason:%d",
+                       disconnected->ssid, disconnected->ssid_len, MAC2STR(disconnected->bssid), disconnected->reason);
+                if (xSemaphoreTake(xSemaphoreWiFi, 35) == pdTRUE) {
+                    wifi_state->STA_connected = false;
+                    wifi_state->STA_online = false;
+                    wifi_state->STA_rssi = 0;
+                    xSemaphoreGive(xSemaphoreWiFi);
+                } else {
+		    ESP_LOGE(TAG, "wifi_event_handler() lock error WIFI_EVENT_STA_DISCONNECTED");
+		}
+		_wifi_BetterAP = false;
+                xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED);
+                xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED);
+		break;
+	    }
+
+	default:
+	    ESP_LOGW(TAG, "Unknown WiFi event %ld", event_id);
+	    break;
+    }
+}
+
+
+
+static void got_ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
+{
+    switch (event_id) {
+
+	case IP_EVENT_STA_GOT_IP:
+		xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_HAS_IP);
+		ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
+		if (xSemaphoreTake(xSemaphoreWiFi, 25) == pdTRUE) {
+			wifi_state->STA_online = true;
+			snprintf(wifi_state->STA_ip, 16, IPSTR, IP2STR(&event->ip_info.ip));
+			snprintf(wifi_state->STA_nm, 16, IPSTR, IP2STR(&event->ip_info.netmask));
+			snprintf(wifi_state->STA_gw, 16, IPSTR, IP2STR(&event->ip_info.gw));
+			xSemaphoreGive(xSemaphoreWiFi);
+		} else {
+			ESP_LOGE(TAG, "got_ip_event_handler() lock error IP_EVENT_STA_GOT_IP");
+		}
+
+//		ESP_LOGI(TAG, "Starting SNTP");
+//    esp_netif_sntp_start();
+
+		break;
+
+	case IP_EVENT_STA_LOST_IP:
+		ESP_LOGW(TAG, "Lost IP address");
+		xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_HAS_IP);
+		if (xSemaphoreTake(xSemaphoreWiFi, 25) == pdTRUE) {
+			wifi_state->STA_ip[0] = '\0';
+			wifi_state->STA_nm[0] = '\0';
+			wifi_state->STA_gw[0] = '\0';
+			wifi_state->STA_online = false;
+			xSemaphoreGive(xSemaphoreWiFi);
+		} else {
+			ESP_LOGE(TAG, "got_ip_event_handler() lock error IP_EVENT_STA_LOST_IP");
+		}
+		break;
+
+	case IP_EVENT_AP_STAIPASSIGNED:
+		ESP_LOGI(TAG, "IP_EVENT_AP_STAIPASSIGNED");
+		break;
+
+	default:
+		ESP_LOGW(TAG, "Unknown IP event %ld", event_id);
+		break;
+    }
+}
+
+
+void time_sync_notification_cb(struct timeval *tv)
+{
+    time_t	now;
+    char	strftime_buf[64];
+    struct tm	timeinfo;
+
+    ESP_LOGI(TAG, "Notification of a time synchronization event");
+    int rc = sntp_get_sync_status();
+
+    if (rc == SNTP_SYNC_STATUS_COMPLETED) {
+        time(&now);
+        localtime_r(&now, &timeinfo);
+//        System_TimeOk = true;
+        strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
+        ESP_LOGI(TAG, "NTP time is set: %s", strftime_buf);
+    } else {
+        ESP_LOGI(TAG, "NTP unknown time sync event rc=%d", rc);
+    }
+}
+
+
+void task_wifi( void * pvParameters )
+{
+    ESP_LOGI(TAG, "Starting WiFi");
+
+    /* event handler and event group for the wifi driver */
+    xEventGroupWifi = xEventGroupCreate();
+    /* initialize the tcp stack */
+    ESP_ERROR_CHECK(esp_netif_init());
+    ESP_ERROR_CHECK(esp_event_loop_create_default());
+
+    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+
+    sta_netif = esp_netif_create_default_wifi_sta();
+    assert(sta_netif);
+
+    /*
+     * Setup SNTP configuration
+     */
+    /**
+     * NTP server address could be acquired via DHCP,
+     * see following menuconfig options:
+     * 'LWIP_DHCP_GET_NTP_SRV' - enable STNP over DHCP
+     * 'LWIP_SNTP_DEBUG' - enable debugging messages
+     *
+     * NOTE: This call should be made BEFORE esp acquires IP address from DHCP,
+     * otherwise NTP option would be rejected by default.
+     */
+    ESP_LOGI(TAG, "Initializing SNTP");
+    esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org");
+    config.start = false;                       // start SNTP service explicitly (after connecting)
+    config.server_from_dhcp = true;             // accept NTP offers from DHCP server, if any (need to enable *before* connecting)
+    config.renew_servers_after_new_IP = true;   // let esp-netif update configured SNTP server(s) after receiving DHCP lease
+    config.index_of_first_server = 1;           // updates from server num 1, leaving server 0 (from DHCP) intact
+    config.ip_event_to_renew = IP_EVENT_STA_GOT_IP;
+    config.sync_cb = time_sync_notification_cb; // only if we need the notification function
+    esp_netif_sntp_init(&config);
+    ESP_LOGI(TAG, "Starting SNTP");
+    esp_netif_sntp_start();
+
+
+    /*
+     * memory allocation of objects used by the task 
+     */
+    accessp_records = (wifi_ap_record_t*)malloc(sizeof(wifi_ap_record_t) * MAX_AP_NUM);
+    xSemaphoreWiFi = xSemaphoreCreateMutex();
+    wifi_state = malloc(sizeof(WIFI_State));
+    memset(wifi_state, 0x00, sizeof(WIFI_State));
+
+    /*
+     * init wifi as station
+     */
+    esp_event_handler_instance_t instance_any_id;
+    esp_event_handler_instance_t instance_got_ip;
+    ESP_ERROR_CHECK( esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, &instance_any_id) );
+    ESP_ERROR_CHECK( esp_event_handler_instance_register(IP_EVENT, ESP_EVENT_ANY_ID, &got_ip_event_handler, NULL, &instance_got_ip) );
+
+    wifi_config_t wifi_config = {
+	.sta = {
+	    .ssid = CONFIG_ESP_WIFI_SSID,
+	    .password = CONFIG_ESP_WIFI_PASSWORD,
+#if CONFIG_WIFI_ALL_CHANNEL_SCAN
+	    .scan_method = WIFI_ALL_CHANNEL_SCAN,
+#elif CONFIG_WIFI_FAST_SCAN
+	    .scan_method = WIFI_FAST_SCAN,
+#endif
+	    .failure_retry_cnt = 3,
+	    .sort_method = WIFI_CONNECT_AP_BY_SIGNAL,
+	    .threshold.rssi = CONFIG_ESP_FAST_SCAN_MINIMUM_SIGNAL,
+	    .threshold.authmode = WIFI_AUTH_WPA2_PSK,
+	},
+    };
+    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
+    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
+    ESP_ERROR_CHECK(esp_wifi_start());
+
+    xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
+    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED);
+    xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED);
+    EventBits_t uxBits;
+
+    for(;;) {
+
+	/* actions that can trigger: request a connection, a scan, or a disconnection */
+	uxBits = xEventGroupWaitBits(xEventGroupWifi, 
+		       TASK_WIFI_REQUEST_STA_CONNECT | TASK_WIFI_REQUEST_STA_DISCONNECT | TASK_WIFI_REQUEST_STA_SCAN | TASK_WIFI_REQUEST_STA_STATUS,
+		       pdFALSE, pdFALSE, portMAX_DELAY );
+
+	if (uxBits & TASK_WIFI_REQUEST_STA_DISCONNECT) {
+	    /*
+	     * user requested a disconnect, this will in effect disconnect the wifi
+	     */
+	    ESP_LOGI(TAG, "Request STA disconnect");
+	    ESP_ERROR_CHECK(esp_wifi_disconnect());
+	    xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED, pdFALSE, pdTRUE, portMAX_DELAY );
+
+	    /* finally: release the scan request bit */
+	    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT);
+	    ESP_LOGI(TAG, "Request STA disconnect is done");
+
+	} else if (uxBits & TASK_WIFI_REQUEST_STA_CONNECT) {
+
+	    ESP_LOGI(TAG, "Request STA connect");
+	    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_FAILED);
+	    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
+
+	    ESP_LOGI(TAG, "Connecting to `%s'", CONFIG_ESP_WIFI_SSID);
+	    esp_err_t wifierror = esp_wifi_connect();
+	    if (wifierror != ESP_OK) {
+		ESP_LOGE(TAG, "esp_wifi_connect() `%s' rc=%04x", CONFIG_ESP_WIFI_SSID, (int)wifierror);
+		xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_FAILED);
+	    }
+	    uxBits = xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED | TASK_WIFI_STA_FAILED, pdFALSE, pdFALSE, 5000 / portTICK_PERIOD_MS);
+
+	} else if (uxBits & TASK_WIFI_REQUEST_STA_STATUS) {
+	    /*
+	     * Request WiFi update status, refresh the rssi.
+	     */
+	    ESP_LOGD(TAG, "Request STA status");
+	    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_STATUS);
+	    wifi_ap_record_t ap_info;
+            esp_wifi_sta_get_ap_info(&ap_info);
+            ESP_LOGI(TAG, "Event STA status, ssid:%s, bssid:" MACSTR ", rssi: %d", ap_info.ssid, MAC2STR(ap_info.bssid), ap_info.rssi);
+	    _wifi_RSSI = ap_info.rssi;
+	    _wifi_BetterAP = false;
+	    if (xSemaphoreTake(xSemaphoreWiFi, 35) == pdTRUE) {
+                wifi_state->STA_rssi = ap_info.rssi;
+		wifi_state->STA_channel = ap_info.primary;
+		snprintf(wifi_state->STA_bssid, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
+			 ap_info.bssid[0], ap_info.bssid[1], ap_info.bssid[2], ap_info.bssid[3], ap_info.bssid[4], ap_info.bssid[5]);
+                xSemaphoreGive(xSemaphoreWiFi);
+            } else {
+                ESP_LOGE(TAG, "lock error TASK_WIFI_REQUEST_STA_STATUS");
+            }
+
+	} else if (uxBits & TASK_WIFI_REQUEST_STA_SCAN) {
+
+	    ESP_LOGI(TAG, "Request STA scan");
+	    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_SCAN);
+	    /* safe guard against overflow */
+	    ap_num = MAX_AP_NUM;
+	    _wifi_ScanDone = false;
+	    _wifi_BetterAP = false;
+	    ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, false));
+	}
+
+    } /* for(;;) */
+}
+
+

mercurial