main/task_wifi.c

Mon, 21 Jun 2021 19:04:10 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Mon, 21 Jun 2021 19:04:10 +0200
changeset 102
96e30a3a3980
parent 94
87aa80b8e452
child 119
1cef3c25426b
permissions
-rw-r--r--

Finished experimental code to drive the German HendiControl board. Added BoilPower and RampPower buttons during the while boil process. RampPower (going to boil power) is now adjustable. Added PWM driver code to the driver task.

/**
 * @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.
 */


#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.
esp_netif_t			*sta_netif = NULL;		///< Station interface


wifi_scan_config_t scan_config = {				///< WiFi scanner configuration.
	.ssid = 0,
	.bssid = 0,
	.channel = 0,
	.show_hidden = false
};

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 int			Main_Screen;			///< Current Screen number.
extern sButton			Buttons[MAXBUTTONS];		///< Buttons definitions.
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 = 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.
 * @param ctx Context
 * @param event The event
 * @return Esp error code.
 */
esp_err_t task_wifi_EventHandler(void *ctx, system_event_t *event);

/**
 * @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" };


/****************************************************************************/



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_LOGD(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) >= 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);

	ESP_LOGD(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;
}



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:
		// Set the configured hostname for the dhcp client.
		ESP_ERROR_CHECK(esp_netif_set_hostname(sta_netif, config.hostname));
		esp_wifi_connect();
		break;

	case WIFI_EVENT_STA_CONNECTED: {
		system_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);
		} else {
                    ESP_LOGE(TAG, "wifi_event_handler() lock error WIFI_EVENT_STA_CONNECTED");
                }
		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;
		wifi_ap_record_t    ap;

            	ESP_LOGW(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, 25) == 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");
                }
		xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED);
		xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED);
		sntp_stop();
		
		if (disconnected->reason == WIFI_REASON_NO_AP_FOUND && ! _wifi_ScanAPs) {
		    ESP_LOGI(TAG, "Request scan for another AP");
		    _wifi_ScanAPs = true;
                    _wifi_ScanDone = false;
                    ap_num = MAX_AP_NUM;
                    ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, false));
		    xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);	// Keep looping active.
		    break;
		}
		if (disconnected->reason == WIFI_REASON_NO_AP_FOUND && _wifi_ScanAPs && _wifi_ScanDone) {
		    ESP_LOGD(TAG, "Scan completed, look for another AP, found:%d", _wifi_Scanned);
		    _wifi_ScanAPs = false;
                    _wifi_ScanDone = false;
		    for (int i = 0; i < _wifi_Scanned; i++) {
			ap = accessp_records[i];
			if ((read_station(ap.ssid) != -1)) {
			    if (wifiStation.hide) {
				continue;               // Blacklisted.
                            }
			    /* We know this one */
			    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));
			    ESP_LOGD(TAG, "new AP %s %s", wifiStation.SSID, wifiStation.Password);
                            xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
			    break;
			}
                    }
		    break;
		}

		/*
		 * Reconnect previous AP.
		 */
		if (FetchStaConfig()) {
		    xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
		}
		break;
	}
	default:
		ESP_LOGW(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, 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");
            	}

                /*
                 * There doesn't seem to be support for configuring NTP via DHCP so
                 * we need to hardcode the ntp servers. The preffered server can be
                 * set via the setup screen. It should be on your LAN, else leave it
                 * empty. And if you are on a different lan someday, there is no extra
                 * delay because the hostname will not be found. 
                 */
                sntp_stop();
                if (strlen(config.ntp_server))
                    sntp_setservername(0, config.ntp_server);
                sntp_setservername(1, (char *)"pool.ntp.org"); // Will get you servers nearby
                sntp_set_sync_mode(SNTP_SYNC_MODE_IMMED);
                sntp_set_time_sync_notification_cb(time_sync_notification_cb);
                sntp_init();
#if 0
                if (strlen(config.ntp_server))
                    ESP_LOGI(TAG, "NTP server %s", sntp_getservername(0));
                ESP_LOGI(TAG, "NTP server %s", sntp_getservername(1));
#endif
                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");
            	}
                sntp_stop();
                break;

	case IP_EVENT_AP_STAIPASSIGNED:
		ESP_LOGI(TAG, "IP_EVENT_AP_STAIPASSIGNED");
		break;

        default:
            ESP_LOGW(TAG, "Unknown IP event %d", event_id);
            break;
    }
}



void time_sync_notification_cb(struct timeval *tv)
{
    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);
	log_msg(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_err_t		ret;

    ESP_LOGI(TAG, "Start WiFi");

    /*
     * Initialize NVS
     */
    ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
	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 */
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    sta_netif = esp_netif_create_default_wifi_sta();
    assert(sta_netif);

    /*
     * 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;

    /*
     * 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_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) );

    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());

    /*
     * 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);
    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 STA 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);

	} 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);
	    }

	    /* 
	     * 3 scenarios here: connection is successful and TASK_WIFI_STA_CONNECTED will be posted
	     * or it's a failure and we get a TASK_WIFI_STA_FAILED with a reason code.
	     * Or, option 3, the 5 seconds timeout is reached. This happens when the AP is not in range.
	     * Note that the reason code is not exploited. For all intent and purposes a failure is a failure.
	     */
//	    ESP_LOGI(TAG, "2 wait for %08x", TASK_WIFI_STA_CONNECTED | TASK_WIFI_STA_FAILED);
	    uxBits = xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED | TASK_WIFI_STA_FAILED, pdFALSE, pdFALSE, 5000 / portTICK_PERIOD_MS);
//	    ESP_LOGI(TAG, "2 waitbits %08x", uxBits & (TASK_WIFI_STA_CONNECTED | TASK_WIFI_STA_FAILED));

	    if (uxBits & (TASK_WIFI_STA_CONNECTED | TASK_WIFI_STA_FAILED)) {
		/* 
		 * only save the config if the connection was successful! 
		 */
		if (uxBits & TASK_WIFI_STA_CONNECTED) {
		    /* save wifi config */
		    SaveStaConfig();
		} else {
		    ESP_LOGW(TAG, "Connection failed");
		    /* failed attempt to connect regardles of the reason */

		    /* otherwise: reset the config */
		    memset(task_wifi_ConfigSTA, 0x00, sizeof(wifi_config_t));
		}
		xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
	    } else {
		/* hit 10 seconds timeout */
		ESP_LOGW(TAG, "Connection timeout");
		xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
                vTaskDelay(100 / portTICK_PERIOD_MS);
		xEventGroupSetBits(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);
	}

    } /* for(;;) */
    vTaskDelay( (TickType_t)10);
}



/**
 * @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[96];

    switch (Main_Screen) {
	case MAIN_TOOLS_SETUP_WIFI:
			TopMessage((char *)"WiFi");
			TFT_setFont(DEJAVU24_FONT, NULL);
			_fg = TFT_WHITE;
			TFT_print((char *)"Momentje ..", CENTER, CENTER);
			_wifi_ScanAPs = true;
			_wifi_ScanDone = false;
			Buttons_Add(260, 200, 60, 40, (char *)"Ok", 0);
			Buttons[0].dark = true;
			Buttons_Show();
			// Now add the buttons we draw manually.
			Buttons_Add(  0, 30, 250, 30, (char *)"", 1);
			Buttons_Add(  0, 60, 250, 30, (char *)"", 2);
			Buttons_Add(  0, 90, 250, 30, (char *)"", 3);
			Buttons_Add(  0,120, 250, 30, (char *)"", 4);
			Buttons_Add(  0,150, 250, 30, (char *)"", 5);
			Buttons_Add(  0,180, 250, 30, (char *)"", 6);
			Buttons_Add(  0,210, 250, 30, (char *)"", 7);
			break;

	case MAIN_TOOLS_SETUP_WIFI_CUR:
			TopMessage((char *)"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) {

			    esp_netif_ip_info_t ip_info;
			    ESP_ERROR_CHECK(esp_netif_get_ip_info(sta_netif, &ip_info));
			    char ip[IP4ADDR_STRLEN_MAX];
			    char gw[IP4ADDR_STRLEN_MAX];
			    char netmask[IP4ADDR_STRLEN_MAX];
			    sprintf(ip, IPSTR, IP2STR(&ip_info.ip));
			    sprintf(netmask, IPSTR, IP2STR(&ip_info.netmask));
			    sprintf(gw, IPSTR, IP2STR(&ip_info.gw));
			    TFT_setFont(DEFAULT_FONT, NULL);
			    _fg = TFT_WHITE;
			    TFT_print((char *)"SSID", 155 - TFT_getStringWidth((char *)"SSID"), 40);
			    TFT_print((char *)"Kanaal", 155 - TFT_getStringWidth((char *)"Kanaal"), 60);
			    TFT_print((char *)"Rssi", 155 - TFT_getStringWidth((char *)"Rssi"), 80);
			    TFT_print((char *)"Mode", 155 - TFT_getStringWidth((char *)"Mode"), 100);
			    TFT_print((char *)"IP adres", 155 - TFT_getStringWidth((char *)"IP adres"), 120);
			    TFT_print((char *)"Netmask", 155 - TFT_getStringWidth((char *)"Netmask"), 140);
			    TFT_print((char *)"Gateway", 155 - TFT_getStringWidth((char *)"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, (char *)"Ok", 0);
			Buttons[0].dark = true;
			Buttons_Show();
			break;

	case MAIN_TOOLS_SETUP_WIFI_CON:
			TopMessage((char *)"WiFi verbinden");
			TFT_setFont(DEJAVU18_FONT, NULL);
			_fg = TFT_WHITE;
			TFT_print((char *)"SSID", 155 - TFT_getStringWidth((char *)"SSID"), 70);
			_fg = TFT_YELLOW;
			TFT_print((char*)_wifi_ssid, 165, 70);
			Buttons_Add(  0, 200, 100, 40, (char *)"Annuleer", 0);
			Buttons_Add(110, 200, 100, 40, (char *)"Vergeet",  1);
			Buttons_Add(220, 200, 100, 40, (char *)"Verbind",  2);
			Buttons_Show();
			Buttons[0].dark = true;
			break;

	case MAIN_TOOLS_SETUP_WIFI_NEW:
			TopMessage((char *)"WiFi nieuw");
			snprintf(pmpt, 95, "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((char *)"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;
			    _wifi_ScanAPs = false;
			    _wifi_ScanDone = false;
			    ESP_ERROR_CHECK(esp_wifi_scan_stop());
			} else 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((char *)"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