main/task_wifi.c

changeset 0
b74b0e4902c3
child 1
ad2c8b13eb88
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/task_wifi.c	Sat Oct 20 13:23:15 2018 +0200
@@ -0,0 +1,806 @@
+/**
+ * @file task_wifi.c
+ * @brief WiFi task. Connects to a known Access Point. If we know more then
+ *        one AP, try to connect all of them until it succeeds (Not yet written).
+ */
+
+
+#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.
+
+
+uint8_t				_wifi_ssid[33];
+bool				_wifi_ScanAPs = false;
+bool				_wifi_ScanDone = false;
+uint16_t			_wifi_Scanned = 0;
+
+extern int			Main_Screen;			///< Current Screen number.
+extern sButton			Buttons[MAXBUTTONS];		///< Buttons definitions.
+extern uint32_t			TimeSpent;			///< Counter that is increased each second.
+
+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_AP_STARTED = BIT4;				///< Indicate that the SoftAP is started
+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 BIT6.
+
+
+/**
+ * @brief Local function, save station configuration.
+ * @return Esp error code.
+ */
+esp_err_t SaveStaConfig(void);
+
+/**
+ * @brief Local function, fetch last connected station configuration.
+ * @return True if there was a last connection, false if there was not.
+ */
+bool FetchStaConfig(void);
+
+/**
+ * @brief Local function, WiFi event handler.
+ * @return Esp error code.
+ */
+esp_err_t task_wifi_EventHandler(void *ctx, system_event_t *event);
+
+
+/****************************************************************************/
+
+
+
+esp_err_t SaveStaConfig(void)
+{
+    int		record;
+
+    if (task_wifi_ConfigSTA && strlen((char *)task_wifi_ConfigSTA->sta.ssid)) {
+	/*
+	 * Store in /spiffs/stations.conf if it's a new station.
+	 */
+	record = read_station(task_wifi_ConfigSTA->sta.ssid);
+	if (record == -1) {
+	    add_station(task_wifi_ConfigSTA->sta.ssid, task_wifi_ConfigSTA->sta.password);
+	}
+
+	/*
+	 * Update main configuration if needed.
+	 */
+	if (strcmp(config.lastSSID, (char *)task_wifi_ConfigSTA->sta.ssid)) {
+	    sprintf(config.lastSSID, "%s", task_wifi_ConfigSTA->sta.ssid);
+	    write_config();
+	}
+	ESP_LOGI(TAG, "SaveStaConfig %s, record %d", wifiStation.SSID, record);
+    }
+
+    return ESP_OK;
+}
+
+
+
+bool FetchStaConfig(void)
+{
+    if (task_wifi_ConfigSTA == NULL) {
+	task_wifi_ConfigSTA = (wifi_config_t*)malloc(sizeof(wifi_config_t));
+    }
+    memset(task_wifi_ConfigSTA, 0x00, sizeof(wifi_config_t));
+
+    /*
+     * Search last connected AP as station.
+     */
+    if (strlen(config.lastSSID)) {
+	read_station((uint8_t *)config.lastSSID);
+
+	/* 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);
+
+	ESP_LOGI(TAG, "FetchStaConfig: last connected to ssid: %s", task_wifi_ConfigSTA->sta.ssid);
+	return task_wifi_ConfigSTA->sta.ssid[0] != '\0';
+    }
+
+    ESP_LOGI(TAG, "FetchStaConfig: no last connection found");
+    return false;
+}
+
+
+
+esp_err_t task_wifi_EventHandler(void *ctx, system_event_t *event)
+{
+    switch(event->event_id) {
+	case SYSTEM_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 SYSTEM_EVENT_STA_START:
+		ESP_LOGD(TAG, "Event STA started");
+		// 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;
+
+	//   SYSTEM_EVENT_STA_STOP		3
+	case SYSTEM_EVENT_STA_CONNECTED:
+		ESP_LOGI(TAG, "Event STA connected, turn off AP");
+		wifi_ap_record_t ap_info;
+		esp_wifi_sta_get_ap_info(&ap_info);
+		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);
+		}
+		// Turn off AP
+		ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
+		xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED);
+		xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED);
+		break;
+
+	case SYSTEM_EVENT_STA_DISCONNECTED:
+		ESP_LOGI(TAG, "Event STA disconnected, turn on AP");
+		if (xSemaphoreTake(xSemaphoreWiFi, 10) == pdTRUE) {
+		    wifi_state->STA_connected = false;
+		    wifi_state->STA_rssi = 0;
+		    xSemaphoreGive(xSemaphoreWiFi);
+		}
+		// Turn on AP
+		ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
+		xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED);
+		xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED);
+
+		/*
+		 * Meanwhile, try to reconnect.
+		 */
+		if (FetchStaConfig()) {
+		    xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
+		}
+		break;
+
+	//   SYSTEM_EVENT_STA_AUTHMODE_CHANGE	6
+	case SYSTEM_EVENT_STA_GOT_IP:
+//		printf("SYSTEM_EVENT_STA_GOT_IP\n");
+		xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_HAS_IP);
+		tcpip_adapter_ip_info_t ip;
+		memset(&ip, 0, sizeof(tcpip_adapter_ip_info_t));
+		if (tcpip_adapter_get_ip_info(ESP_IF_WIFI_STA, &ip) == 0) {
+		    if (xSemaphoreTake(xSemaphoreWiFi, 10) == pdTRUE) {
+		    	snprintf(wifi_state->STA_ip, 15, IPSTR, IP2STR(&ip.ip));
+			snprintf(wifi_state->STA_nm, 15, IPSTR, IP2STR(&ip.netmask));
+			snprintf(wifi_state->STA_gw, 15, IPSTR, IP2STR(&ip.gw));
+		    	xSemaphoreGive(xSemaphoreWiFi);
+		    }
+		}
+		break;
+
+	case SYSTEM_EVENT_STA_LOST_IP:
+		ESP_LOGI(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';
+		    xSemaphoreGive(xSemaphoreWiFi);
+		}
+		break;
+
+	//   SYSTEM_EVENT_STA_WPS_ER_SUCCESS	9
+	//   SYSTEM_EVENT_STA_WPS_ER_FAILED	10
+	//   SYSTEM_EVENT_STA_WPS_ER_TIMEOUT	11
+	//   SYSTEM_EVENT_STA_WPS_ER_PIN	12
+
+    	case SYSTEM_EVENT_AP_START:
+		ESP_LOGD(TAG, "Event AP started");
+    		xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_AP_STARTED);
+		if (xSemaphoreTake(xSemaphoreWiFi, 25) == pdTRUE) {
+		    wifi_state->AP_active = true;
+		    wifi_state->AP_clients = 0;
+		    xSemaphoreGive(xSemaphoreWiFi);
+		}
+		break;
+
+	case SYSTEM_EVENT_AP_STOP:
+		ESP_LOGD(TAG, "Event AP stopped");
+		xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_AP_STARTED);
+		if (xSemaphoreTake(xSemaphoreWiFi, 25) == pdTRUE) {
+		    wifi_state->AP_active = false;
+		    wifi_state->AP_clients = 0;
+		    xSemaphoreGive(xSemaphoreWiFi);
+		}
+		break;
+
+    	case SYSTEM_EVENT_AP_STACONNECTED:
+		if (xSemaphoreTake(xSemaphoreWiFi, 25) == pdTRUE) {
+		    wifi_state->AP_clients++;
+		    xSemaphoreGive(xSemaphoreWiFi);
+		}
+		ESP_LOGI(TAG, "Event AP new client, %d connections", wifi_state->AP_clients);
+		break;
+
+    	case SYSTEM_EVENT_AP_STADISCONNECTED:
+		if (xSemaphoreTake(xSemaphoreWiFi, 25) == pdTRUE) {
+		    if (wifi_state->AP_clients > 0)
+		    	wifi_state->AP_clients--;
+		    else
+		    	wifi_state->AP_clients = 0;
+		    xSemaphoreGive(xSemaphoreWiFi);
+		}
+		ESP_LOGI(TAG, "Event AP client disconnect, %d connections", wifi_state->AP_clients);
+		break;
+
+	//   SYSTEM_EVENT_AP_PROBEREQRECVED	17
+	//   SYSTEM_EVENT_GOT_IP6		18
+	//   SYSTEM_EVENT_ETH_START		19
+	//   SYSTEM_EVENT_ETH_STOP		20
+	//   SYSTEM_EVENT_ETH_CONNECTED		21
+	//   SYSTEM_EVENT_ETH_DISCONNECTED	22
+	//   SYSTEM_EVENT_ETH_GOT_IP		23
+
+	default:
+		printf("Unknown event %d\n", event->event_id);
+        	break;
+    }
+    return ESP_OK;
+}
+
+
+
+/**
+ * @brief WiFi manager task
+ */
+void task_wifi( void * pvParameters )
+{
+    esp_err_t		ret;
+
+    ESP_LOGI(TAG, "Starting WiFi driver");
+
+    /*
+     * Initialize NVS
+     */
+    ret = nvs_flash_init();
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+	ESP_ERROR_CHECK(nvs_flash_erase());
+	ret = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK(ret);
+
+    /* event handler and event group for the wifi driver */
+    xEventGroupWifi = xEventGroupCreate();
+    /* initialize the tcp stack */
+    tcpip_adapter_init();
+    ESP_ERROR_CHECK(esp_event_loop_init(task_wifi_EventHandler, NULL));
+
+    /*
+     * 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->AP_clients = 0;
+    wifi_state->AP_active = false;
+    wifi_state->STA_connected = false;
+    wifi_state->STA_rssi = 0;
+
+    /* wifi scanner config */
+    wifi_scan_config_t scan_config = {
+	.ssid = 0,
+	.bssid = 0,
+	.channel = 0,
+	.show_hidden = false
+    };
+
+    /*
+     * start the softAP access point
+     * stop DHCP server
+     */
+    ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP));
+
+    /*
+     * Assign a static IP to the AP network interface
+     */
+    tcpip_adapter_ip_info_t info;
+    memset(&info, 0x00, sizeof(info));
+    IP4_ADDR(&info.ip, 192, 168, 1, 1);
+    IP4_ADDR(&info.gw, 192, 168, 1, 1);
+    IP4_ADDR(&info.netmask, 255, 255, 255, 0);
+    ESP_ERROR_CHECK(tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_AP, &info));
+
+    /* start dhcp server */
+    ESP_ERROR_CHECK(tcpip_adapter_dhcps_start(TCPIP_ADAPTER_IF_AP));
+    ESP_LOGI(TAG, "AP start dhcps ip: 192.168.1.1 nm: 255.255.255.0 gw: 192.168.1.1");
+
+    /* start dhcp client */
+    ESP_ERROR_CHECK(tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA));
+    ESP_LOGI(TAG, "Start DHCP client for STA interface.");
+
+    /*
+     * init wifi as station + access point
+     */
+    wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
+    ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
+    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
+    ESP_ERROR_CHECK(esp_wifi_set_bandwidth(WIFI_IF_AP, config.ap_bandwidth));
+
+    // configure the softAP and start it */
+    wifi_config_t ap_config = {
+	.ap = {
+	    .ssid_len = 0,
+	    .channel = config.ap_channel,
+	    .authmode = WIFI_AUTH_WPA2_PSK,
+	    .ssid_hidden = config.ap_ssid_hidden,
+	    .max_connection = AP_MAX_CONNECTIONS,
+	    .beacon_interval = 100,
+	},
+    };
+    memcpy(ap_config.ap.ssid, config.ap_ssid , sizeof(config.ap_ssid));
+    memcpy(ap_config.ap.password, config.ap_pwd, sizeof(config.ap_pwd));
+    ret = esp_wifi_set_config(WIFI_IF_AP, &ap_config);
+    if (ret != ESP_OK) {
+	ESP_LOGE(TAG, "esp_wifi_set_config(WIFI_IF_AP, nnn) rc=%d", ret);
+    }
+    ESP_ERROR_CHECK(esp_wifi_start());
+
+    ESP_LOGI(TAG, "SoftAP start ssid: `%s' pwd: `%s' channel: %d, hidden: %s", 
+		    ap_config.ap.ssid, ap_config.ap.password, ap_config.ap.channel, ap_config.ap.ssid_hidden ? "yes":"no");
+
+    /*
+     * try to get access to previously saved wifi
+     */
+    if (FetchStaConfig()) {
+	xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
+    }
+
+    /* 
+     * Wait for access point to start
+     */
+    xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED);
+    xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_AP_STARTED, pdFALSE, pdTRUE, portMAX_DELAY );
+    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 but also erase NVS memory
+	     */
+	    ESP_LOGI(TAG, "Request disconnect");
+	    sntp_stop();
+	    ESP_ERROR_CHECK(esp_wifi_disconnect());
+	    xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED, pdFALSE, pdTRUE, portMAX_DELAY );
+	    
+	    /*
+	     * erase configuration
+	     */
+	    if (task_wifi_ConfigSTA) {
+		memset(task_wifi_ConfigSTA, 0x00, sizeof(wifi_config_t));
+	    }
+	    config.lastSSID[0] = '\0';
+	    write_config();
+
+	    /* finally: release the scan request bit */
+	    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT);
+	    ESP_LOGI(TAG, "Request disconnect is finished.");
+
+	} else if (uxBits & TASK_WIFI_REQUEST_STA_CONNECT) {
+
+	    //someone requested a connection!
+	    ESP_LOGI(TAG, "Request STA connect `%s'", task_wifi_ConfigSTA->sta.ssid);
+	    /* set the new config and connect - reset the failed bit first as it is later tested */
+	    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_FAILED);
+	    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() rc=%04x", (int)wifierror);
+		xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_FAILED);
+	    }
+
+	    /* 
+	     * 2 scenarios here: connection is successful and TASK_WIFI_HAS_IP will be posted
+	     * or it's a failure and we get a TASK_WIFI_STA_FAILED with a reason code.
+	     * Note that the reason code is not exploited. For all intent and purposes a failure is a failure.
+	     */
+	    uxBits = xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_HAS_IP | TASK_WIFI_STA_FAILED, pdFALSE, pdFALSE, portMAX_DELAY );
+
+	    if (uxBits & (TASK_WIFI_HAS_IP | TASK_WIFI_STA_FAILED)) {
+		/* 
+		 * only save the config if the connection was successful! 
+		 */
+		if(uxBits & TASK_WIFI_HAS_IP) {
+		    /* save wifi config */
+		    SaveStaConfig();
+		    sntp_setservername(0, "nl.pool.ntp.org");
+		    sntp_init();
+		    ESP_LOGI(TAG, "Initialized SNTP %s", sntp_getservername(0));
+		} else {
+		    ESP_LOGI(TAG, "Connection failed");	// TODO: Scan other SSID's for known networks.
+		    /* failed attempt to connect regardles of the reason */
+
+		    /* otherwise: reset the config */
+		    memset(task_wifi_ConfigSTA, 0x00, sizeof(wifi_config_t));
+		}
+	    } else {
+		/* hit portMAX_DELAY limit ? */
+		abort();
+	    }
+
+	    /* finally: release the connection request bit */
+	    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
+
+	} else if (uxBits & TASK_WIFI_REQUEST_WIFI_SCAN) {
+
+	    /* safe guard against overflow */
+	    ap_num = MAX_AP_NUM;
+	    ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, false));
+
+	    /* finally: release the scan request bit */
+	    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_WIFI_SCAN);
+	}
+
+	/*
+	 * Here we should check for reconnect actions.
+	 */
+
+    } /* for(;;) */
+    vTaskDelay( (TickType_t)10);
+}
+
+
+const char *apsec[] = { "Open", "WEP", "WPA", "WPA2", "WPA WPA2", "Enterprise" };
+
+
+/**
+ * @brief Show an AP station as a button. The buttons are already defined.
+ * @param idx The index position on the display, 1 to 7.
+ * @param ap The AP information from the WiFi scan.
+ * @param show, How to display. 0 is blank, 1 is unknown, 2 is known, 3 is a connected AP.
+ */
+void Show_AP(uint8_t idx, wifi_ap_record_t ap, int show)
+{
+    char	tmp[33];
+
+    if ((idx > 7) || (idx < 1))
+	return;
+
+    if (show == 0) {
+	_bg = TFT_BLACK;
+    } else {
+    	_bg = (color_t){ 63, 63, 64 };
+    }
+
+    TFT_fillRect(Buttons[idx].x, Buttons[idx].y, Buttons[idx].w, Buttons[idx].h, _bg);
+    if (show == 0)
+	return;
+
+    TFT_drawRect(Buttons[idx].x, Buttons[idx].y, Buttons[idx].w, Buttons[idx].h, TFT_NAVY);
+    if (show == 3) {
+	_fg = TFT_WHITE;
+    } else if (show == 1) {
+    	_fg = TFT_YELLOW;
+    } else {
+	_fg = TFT_CYAN;
+    }
+
+    TFT_setFont(DEJAVU18_FONT, NULL);
+    sprintf(tmp, "%s", ap.ssid);
+    TFT_print(tmp, Buttons[idx].x + 5, Buttons[idx].y + 6);
+    sprintf(tmp, "%d", ap.rssi);
+    TFT_setFont(DEF_SMALL_FONT, NULL);
+    TFT_print(tmp, Buttons[idx].x + Buttons[idx].w - (TFT_getStringWidth(tmp) + 5), Buttons[idx].y + 4);
+    sprintf(tmp, "%s", apsec[ap.authmode]);
+    TFT_print(tmp, Buttons[idx].x + Buttons[idx].w - (TFT_getStringWidth(tmp) + 5), Buttons[idx].y + 15);
+}
+
+
+
+bool WiFi_Init(void)
+{
+    char	pwd[65], pmpt[32];
+
+    switch (Main_Screen) {
+	case MAIN_TOOLS_SETUP_WIFI:
+			TopMessage("WiFi");
+			TFT_setFont(DEJAVU24_FONT, NULL);
+			_fg = TFT_WHITE;
+			TFT_print("Momentje ..", CENTER, CENTER);
+			_wifi_ScanAPs = true;
+			_wifi_ScanDone = false;
+			Buttons_Add(260, 200, 60, 40, "Ok", 0);
+			Buttons[0].dark = true;
+			Buttons_Show();
+			// Now add the buttons we draw manually.
+			Buttons_Add(  0, 30, 250, 30, "", 1);
+			Buttons_Add(  0, 60, 250, 30, "", 2);
+			Buttons_Add(  0, 90, 250, 30, "", 3);
+			Buttons_Add(  0,120, 250, 30, "", 4);
+			Buttons_Add(  0,150, 250, 30, "", 5);
+			Buttons_Add(  0,180, 250, 30, "", 6);
+			Buttons_Add(  0,210, 250, 30, "", 7);
+			break;
+
+	case MAIN_TOOLS_SETUP_WIFI_CUR:
+			TopMessage("WiFi verbinding");
+			// Get extra information.
+			wifi_ap_record_t ap_info;
+			esp_wifi_sta_get_ap_info(&ap_info);
+
+			wifi_config_t *wconfig = task_wifi_ConfigSTA /*task_wifi_GetWifiStaConfig( ) */;
+			if (wconfig) {
+
+			    tcpip_adapter_ip_info_t ip_info;
+			    ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info));
+			    char ip[IP4ADDR_STRLEN_MAX];
+			    char gw[IP4ADDR_STRLEN_MAX];
+			    char netmask[IP4ADDR_STRLEN_MAX];
+			    strcpy(ip, ip4addr_ntoa(&ip_info.ip));
+			    strcpy(netmask, ip4addr_ntoa(&ip_info.netmask));
+			    strcpy(gw, ip4addr_ntoa(&ip_info.gw));
+			    TFT_setFont(DEFAULT_FONT, NULL);
+			    _fg = TFT_WHITE;
+			    TFT_print("SSID", 155 - TFT_getStringWidth("SSID"), 40);
+			    TFT_print("Kanaal", 155 - TFT_getStringWidth("Kanaal"), 60);
+			    TFT_print("Rssi", 155 - TFT_getStringWidth("Rssi"), 80);
+			    TFT_print("Mode", 155 - TFT_getStringWidth("Mode"), 100);
+			    TFT_print("IP adres", 155 - TFT_getStringWidth("IP adres"), 120);
+			    TFT_print("Netmask", 155 - TFT_getStringWidth("Netmask"), 140);
+			    TFT_print("Gateway", 155 - TFT_getStringWidth("Gateway"), 160);
+			    _fg = TFT_YELLOW;
+			    TFT_print((char*)wconfig->sta.ssid, 165, 40);
+			    sprintf(pmpt, "%d", ap_info.primary);
+			    TFT_print(pmpt, 165, 60);
+			    sprintf(pmpt, "%d", ap_info.rssi);
+			    TFT_print(pmpt, 165, 80);
+			    sprintf(pmpt, "%s%s%s", ap_info.phy_11b ? "b":"", ap_info.phy_11g ? "g":"", ap_info.phy_11n ? "n":"");
+			    TFT_print(pmpt, 165, 100);
+			    TFT_print((char*)ip, 165, 120);
+			    TFT_print((char*)netmask, 165, 140);
+			    TFT_print((char*)gw, 165, 160);
+			}
+			Buttons_Add(130, 200, 60, 40, "Ok", 0);
+			Buttons[0].dark = true;
+			Buttons_Show();
+			break;
+
+	case MAIN_TOOLS_SETUP_WIFI_CON:
+			TopMessage("WiFi verbinden");
+			TFT_setFont(DEJAVU18_FONT, NULL);
+			_fg = TFT_WHITE;
+			TFT_print("SSID", 155 - TFT_getStringWidth("SSID"), 70);
+			_fg = TFT_YELLOW;
+			TFT_print((char*)_wifi_ssid, 165, 70);
+			Buttons_Add(  0, 200, 100, 40, "Annuleer", 0);
+			Buttons_Add(110, 200, 100, 40, "Vergeet",  1);
+			Buttons_Add(220, 200, 100, 40, "Verbind",  2);
+			Buttons_Show();
+			Buttons[0].dark = true;
+			break;
+
+	case MAIN_TOOLS_SETUP_WIFI_NEW:
+			TopMessage("WiFi nieuw");
+			snprintf(pmpt, 32, "Password for %s", _wifi_ssid);
+			pwd[0] = '\0';
+			EditTextMin(pmpt, pwd, 64, 8);
+			/*
+			 * Disconnect first
+			 */
+			_bg = TFT_BLACK;
+			TFT_fillScreen(_bg);
+			TFT_setFont(DEJAVU24_FONT, NULL);
+			_fg = TFT_WHITE;
+			TFT_print("Momentje ..", CENTER, CENTER);
+			xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT);
+			vTaskDelay(100 / portTICK_PERIOD_MS);
+			xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED, pdFALSE, pdTRUE, portMAX_DELAY );
+
+			/*
+			 * Setup new connection
+			 */
+			if (strlen(pwd)) {
+			    wifi_config_t* config = task_wifi_ConfigSTA;
+			    memset(config, 0x00, sizeof(wifi_config_t));
+			    memcpy(config->sta.ssid, _wifi_ssid, strlen((char*)_wifi_ssid));
+			    memcpy(config->sta.password, pwd, strlen(pwd));
+			    ESP_LOGI(TAG, "new AP %s %s", _wifi_ssid, pwd);
+			    xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
+			} else {
+			    // TODO: what about WPS, it works but how to insert it in this app.
+			    return true;
+			}
+			// We must wait here for the result.
+			break;
+
+	default:
+			break;
+    }
+
+    return false;
+}
+
+
+bool WiFi_Loop(void)
+{
+    uint8_t		idx;
+    int			Choice;
+    static int		AP[8];
+    wifi_ap_record_t	ap;
+
+    switch (Main_Screen) {
+	case MAIN_TOOLS_SETUP_WIFI:
+			if (_wifi_ScanAPs) {
+			    xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_WIFI_SCAN);
+			    _wifi_ScanAPs = false;
+			    TimeSpent = 0;
+			}
+			if (_wifi_ScanDone) {
+			    /*
+			     * Show scan results. There is room for 7 entries. If we have a connection,
+			     * the first one is that connection followed by available Access Points.
+			     * If there is no connection yet, there is only a iist of available Access
+			     * points.
+			     * The list is sorted by signal strength and is filled by the eventhandler.
+			     */
+			    idx = 1;
+			    _wifi_ScanDone = false;
+
+			    if ((xEventGroupGetBits(xEventGroupWifi) & TASK_WIFI_STA_CONNECTED) == TASK_WIFI_STA_CONNECTED) {
+				// We are connected. Search and display this one.
+				if (xSemaphoreTake(xSemaphoreWiFi, 25) == pdTRUE) {
+				    for (int i = 0; i < _wifi_Scanned; i++) {
+					ap = accessp_records[i];
+					if (strcmp(wifi_state->STA_ssid, (char *)ap.ssid) == 0) {
+					    AP[idx] = i;
+					    Show_AP(idx, ap, 3);
+					    idx++;
+					    break;
+					}
+				    }
+				    xSemaphoreGive(xSemaphoreWiFi);
+				}
+			    }
+
+			    // Display available Access Points.
+			    for (int i = 0; i < _wifi_Scanned; i++) {
+				// The connected AP can be somewhere in this list, don't display it again.
+				ap = accessp_records[i];
+				if (xSemaphoreTake(xSemaphoreWiFi, 25) == pdTRUE) {
+				    if (strcmp(wifi_state->STA_ssid, (char *)ap.ssid) == 0) {
+					xSemaphoreGive(xSemaphoreWiFi);
+					continue;	// Skip connected AP, already on top of the list.
+				    }
+				    xSemaphoreGive(xSemaphoreWiFi);
+				}
+				// Check if we know this AP in the database.
+				if ((read_station(ap.ssid) == -1)) {
+				    Show_AP(idx, ap, 2);	// Unknown
+				} else {
+				    if (wifiStation.hide) {
+					continue;		// Blacklisted.
+				    }
+				    Show_AP(idx, ap, 1);	// We know this one.
+				}
+				AP[idx] = i;
+				idx++;
+				if (idx ==  8)
+				    break;
+			    }
+			    if (idx < 7) {
+				for (int i = idx; i < 8; i++) {
+				    Show_AP(i, ap, 0);
+				    AP[i] = 0;
+				}
+			    }
+			}
+
+			Choice = Buttons_Scan();
+			if ((Choice >= 1) && (Choice <= 7)) {
+			    ap = accessp_records[AP[Choice]];
+			    sprintf((char *)_wifi_ssid, "%s", ap.ssid);		// Save selected SSID.
+			}
+			if ((Choice == 1) && ((xEventGroupGetBits(xEventGroupWifi) & TASK_WIFI_STA_CONNECTED) == TASK_WIFI_STA_CONNECTED)) {
+			    Main_Screen = MAIN_TOOLS_SETUP_WIFI_CUR;
+			    // Cancel a possible scan.
+			    ESP_ERROR_CHECK(esp_wifi_scan_stop());
+			} else if ((Choice >= 1) && (Choice <= 7)) {
+			    if ((read_station(_wifi_ssid) != -1)) {
+				Main_Screen = MAIN_TOOLS_SETUP_WIFI_CON;
+			    } else {
+				Main_Screen = MAIN_TOOLS_SETUP_WIFI_NEW;
+			    }
+			    ESP_ERROR_CHECK(esp_wifi_scan_stop());
+			} else if (Choice == 0) {
+			    Main_Screen = MAIN_TOOLS_SETUP;
+			    ESP_ERROR_CHECK(esp_wifi_scan_stop());
+			}
+			if (TimeSpent > 10) {
+			     _wifi_ScanAPs = true;
+			}
+			break;
+
+	case MAIN_TOOLS_SETUP_WIFI_CUR:
+
+			if (Buttons_Scan() == 0) {
+			    Main_Screen = MAIN_TOOLS_SETUP_WIFI;
+			}
+			break;
+
+	case MAIN_TOOLS_SETUP_WIFI_CON:
+			switch (Buttons_Scan()) {
+			    case 0:	// Cancel choice
+				    	Main_Screen = MAIN_TOOLS_SETUP_WIFI;
+					break;
+
+			    case 1:	// Forget connection
+					remove_station(_wifi_ssid);
+					Main_Screen = MAIN_TOOLS_SETUP_WIFI;
+					break;
+
+			    case 2:	// Connect
+					_bg = TFT_BLACK;
+					TFT_fillScreen(_bg);
+					TFT_setFont(DEJAVU24_FONT, NULL);
+					_fg = TFT_WHITE;
+					TFT_print("Momentje ..", CENTER, CENTER);
+					/*
+					 * Disconnect old connections and wait until it's gone.
+					 */
+					xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT);
+					vTaskDelay(100 / portTICK_PERIOD_MS);
+					xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED, pdFALSE, pdTRUE, portMAX_DELAY );
+					/*
+					 * Setup new connection.
+					 */
+					if ((read_station(_wifi_ssid) != -1)) {
+					    wifi_config_t* config = task_wifi_ConfigSTA;
+					    memset(config, 0x00, sizeof(wifi_config_t));
+					    memcpy(config->sta.ssid, wifiStation.SSID, strlen(wifiStation.SSID));
+					    memcpy(config->sta.password, wifiStation.Password, strlen(wifiStation.Password));
+					    xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
+					    vTaskDelay(1000 / portTICK_PERIOD_MS);
+					}
+					Main_Screen = MAIN_TOOLS_SETUP_WIFI;
+					break;
+
+			    default:	break;
+			}
+			break;
+												         
+	case MAIN_TOOLS_SETUP_WIFI_NEW:
+			// All work is already done, jump to the base screen.
+			Main_Screen = MAIN_TOOLS_SETUP_WIFI;
+			break;
+
+	default:
+			break;
+    }
+
+    return false;
+}
+
+

mercurial