main/task_wifi.c

changeset 0
88d965579617
child 23
58a328e91881
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/task_wifi.c	Tue Oct 08 12:00:31 2019 +0200
@@ -0,0 +1,320 @@
+/**
+ * @file task_wifi.c
+ * @brief WiFi task. Connect to the known AP with the strongest signal.
+ */
+
+
+#include "config.h"
+
+
+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.
+
+wifi_scan_config_t scan_config = {				///< WiFi scanner configuration.
+	.ssid = 0,
+	.bssid = 0,
+	.channel = 0,
+	.show_hidden = false,
+	.scan_time.passive = 130				///< Beacons are usually sent every 100 mSec.
+};
+
+uint8_t				_wifi_ssid[33];			///< Current SSID
+bool				_wifi_ScanAPs = false;		///< Scanning
+bool				_wifi_ScanDone = false;		///< Scan ready
+uint16_t			_wifi_Scanned = 0;		///< Total scanned APs.
+
+extern uint32_t			TimeSpent;			///< Counter that is increased each second.
+extern bool			System_TimeOk;
+extern time_t			now;
+extern char			strftime_buf[64];
+extern struct tm		timeinfo;
+
+const int TASK_WIFI_REQUEST_WIFI_SCAN = BIT0;			///< When set, means a client requested to scan wireless networks.
+const int TASK_WIFI_REQUEST_STA_DISCONNECT = BIT1;		///< When set, means a client requested to disconnect from currently connected AP.
+const int TASK_WIFI_REQUEST_STA_CONNECT = BIT2;			///< When set, means a client requested to connect to an access point.
+
+const int TASK_WIFI_HAS_IP = BIT3;				///< Indicate that we have an IP address
+const int TASK_WIFI_STA_FAILED = BIT4;				///< Indicate that we could not get a connection to AP as station.
+const int TASK_WIFI_STA_DISCONNECTED = BIT5;			///< Indicate that we are disconnected from an ap station.
+const int TASK_WIFI_STA_CONNECTED = BIT6;			///< Indicate that we are connected to AP as station, flip of BIT6.
+
+const int TASK_WIFI_REQUEST_SYSTEM = BIT8;			///< The system needs a connection
+const int TASK_WIFI_REQUEST_USER = BIT9;			///< The user needs a connection
+
+
+/**
+ * @brief local callback function. Is called when the timesync is valid
+ *        from a timeserver. Sets the global boolean System_TimeOk value. 
+ * @param tv is the received time. Not used.
+ */
+void time_sync_notification_cb(struct timeval *tv);
+
+/**
+ * @brief Array with AP security names
+ */
+const char *apsec[] = { "Open", "WEP", "WPA", "WPA2", "WPA WPA2", "Enterprise" };
+
+
+/****************************************************************************/
+
+
+
+void requestWiFi_system(bool state)
+{
+    if (state)
+	xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_SYSTEM);
+    else
+        xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_SYSTEM);
+
+    if (xEventGroupGetBits(xEventGroupWifi) & (TASK_WIFI_REQUEST_SYSTEM | TASK_WIFI_REQUEST_USER))
+	xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
+    else
+	xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT);
+}
+
+
+
+void requestWiFi_user(bool state)
+{
+    if (state)
+        xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_USER);
+    else
+        xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_USER);
+
+    if (xEventGroupGetBits(xEventGroupWifi) & (TASK_WIFI_REQUEST_SYSTEM | TASK_WIFI_REQUEST_USER))
+        xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
+    else
+        xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT);
+}
+
+
+
+bool ready_WiFi(void)
+{
+    if (wifi_state->STA_connected && wifi_state->STA_online)
+        return true;
+    return false;
+}
+
+
+
+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));
+            _wifi_Scanned = ap_num;
+            _wifi_ScanDone = true;
+	    break;
+
+	case WIFI_EVENT_STA_START:
+	    ESP_LOGI(TAG, "Event wifi START");
+            // Set the configured hostname for the dhcp client.
+            ESP_ERROR_CHECK(tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, config.hostname));
+            esp_wifi_connect();
+	    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, 25) == pdTRUE) {
+                    wifi_state->STA_connected = true;
+                    wifi_state->STA_rssi = ap_info.rssi;
+                    sprintf(wifi_state->STA_ssid, "%s", ap_info.ssid);
+                    xSemaphoreGive(xSemaphoreWiFi);
+                }
+                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, 10) == pdTRUE) {
+                    wifi_state->STA_connected = false;
+                    wifi_state->STA_online = false;
+                    wifi_state->STA_rssi = 0;
+                    xSemaphoreGive(xSemaphoreWiFi);
+                }
+                xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED);
+                xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED);
+		break;
+	    }
+
+	default:
+	    ESP_LOGI(TAG, "Unknown WiFi event %d", 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, 10) == pdTRUE) {
+            	wifi_state->STA_online = true;
+		snprintf(wifi_state->STA_ip, 16, "%s", ip4addr_ntoa(&event->ip_info.ip));
+                snprintf(wifi_state->STA_nm, 16, "%s", ip4addr_ntoa(&event->ip_info.netmask));
+                snprintf(wifi_state->STA_gw, 16, "%s", ip4addr_ntoa(&event->ip_info.gw));
+                xSemaphoreGive(xSemaphoreWiFi);
+	    }
+	    break;
+
+	case IP_EVENT_STA_LOST_IP:
+            ESP_LOGW(TAG, "Lost IP address");
+            xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_HAS_IP);
+            if (xSemaphoreTake(xSemaphoreWiFi, 10) == 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);
+            }
+	    break;
+
+	default:
+	    ESP_LOGI(TAG, "Unknown IP event %d", event_id);
+	    break;
+    }
+}
+
+
+
+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 */
+    tcpip_adapter_init();
+    ESP_ERROR_CHECK(esp_event_loop_create_default());
+
+    /*
+     * memory allocation of objects used by the task 
+     */
+    accessp_records = (wifi_ap_record_t*)malloc(sizeof(wifi_ap_record_t) * MAX_AP_NUM);
+    task_wifi_ConfigSTA = (wifi_config_t*)malloc(sizeof(wifi_config_t));
+    memset(task_wifi_ConfigSTA, 0x00, sizeof(wifi_config_t));
+
+    xSemaphoreWiFi = xSemaphoreCreateMutex();
+    wifi_state = malloc(sizeof(WIFI_State));
+    wifi_state->STA_connected = false;
+    wifi_state->STA_online = false;
+    wifi_state->STA_rssi = 0;
+
+    /* stop dhcp server and start dhcp client */
+    ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP));
+    ESP_ERROR_CHECK(tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA));
+
+    /*
+     * init wifi as station
+     */
+    wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
+
+    ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL) );
+    ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &got_ip_event_handler, NULL) );
+
+    ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
+    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
+    ESP_ERROR_CHECK(esp_wifi_start());
+
+    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_WIFI_SCAN | TASK_WIFI_REQUEST_STA_DISCONNECT,
+		                     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);
+
+	} else if (uxBits & TASK_WIFI_REQUEST_STA_CONNECT) {
+
+	    ESP_LOGI(TAG, "Request STA connect");
+	    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_FAILED);
+            _wifi_ScanAPs = true;
+            _wifi_ScanDone = false;
+            ap_num = MAX_AP_NUM;
+            ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, false));
+	    while (_wifi_ScanDone == false) {
+		vTaskDelay(10 / portTICK_PERIOD_MS);
+            }
+	    ESP_LOGI(TAG, "Scan done %d APs", _wifi_Scanned);
+	    bool found = false;
+
+            // Available Access Points.
+            for (int i = 0; i < _wifi_Scanned; i++) {
+		wifi_ap_record_t ap = accessp_records[i];
+		// Check if we know this AP in the database.
+//		ESP_LOGI(TAG, "%d %-20s ch: %2d rssi: %d %s", i, ap.ssid, ap.primary, ap.rssi, apsec[ap.authmode]);
+		if ((read_station(ap.ssid) >= 0)) {
+		    /* ssid */
+		    size_t sz = sizeof(task_wifi_ConfigSTA->sta.ssid);
+		    memcpy(task_wifi_ConfigSTA->sta.ssid, wifiStation.SSID, sz);
+		    /* password */
+		    sz = sizeof(task_wifi_ConfigSTA->sta.password);
+		    memcpy(task_wifi_ConfigSTA->sta.password, wifiStation.Password, sz);
+		    found = true;
+		    break;
+		}
+	    }
+	    if (found) {
+		/*
+		 * Now connect to the known SSID
+		 */
+	//	ESP_LOGI(TAG, "Connecting to `%s'", task_wifi_ConfigSTA->sta.ssid);
+		ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, task_wifi_ConfigSTA));
+		esp_err_t wifierror = esp_wifi_connect();
+		if (wifierror != ESP_OK) {
+		    ESP_LOGE(TAG, "esp_wifi_connect() `%s' rc=%04x", task_wifi_ConfigSTA->sta.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);
+		if (uxBits & TASK_WIFI_STA_CONNECTED)
+		    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); // Only clear when connected.
+	    } else {
+		ESP_LOGI(TAG, "No known AP found, scan again");
+		vTaskDelay(3000 / portTICK_PERIOD_MS);
+	    }
+	}
+
+    } /* for(;;) */
+    vTaskDelay(10 / portTICK_PERIOD_MS);
+}
+
+

mercurial