main/task_wifi.c

Sat, 14 Mar 2020 13:07:02 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Sat, 14 Mar 2020 13:07:02 +0100
changeset 47
1ab1f4a8c328
parent 44
e52d11b8f252
child 48
d43ea0c916de
permissions
-rw-r--r--

Version 0.2.2 Changed to use a permanent network and WiFi connection. Removed three mainloop stages. Removed MQTT sequence counter that was not used. Update WiFi rssi status during eacht measure cycle. Changed FreeRTOS schedulng to 500 Hz.

/**
 * @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 = {
	.ssid = 0,
	.bssid = 0,
	.channel = 0,
	.show_hidden = false,
	.scan_time.passive = 130				///< Beacons are usually sent every 100 mSec.
};								///< WiFi scanner configuration.

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.


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_REQUEST_STA_STATUS = BIT8;

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.



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



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, 35) == 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;

                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");
		}
		connect_mqtt(false);
                xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED);
                xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED);

		//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, "%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);
		} else {
			ESP_LOGE(TAG, "got_ip_event_handler() lock error IP_EVENT_STA_GOT_IP");
		}
		connect_mqtt(true);
		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");
		}
		connect_mqtt(false);
		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 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));
    memset(wifi_state, 0x00, sizeof(WIFI_State));

    /* 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, ESP_EVENT_ANY_ID, &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_REQUEST_STA_CONNECT);
    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 | 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
	     */
	    connect_mqtt(false);
	    ESP_LOGD(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_LOGD(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_LOGD(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_LOGD(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);
	    }
	} else if (uxBits & TASK_WIFI_REQUEST_STA_STATUS) {
	    /*
	     * Request WiFi update status, refresh the rssi.
	     */
	    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);
	    if (xSemaphoreTake(xSemaphoreWiFi, 35) == pdTRUE) {
                wifi_state->STA_rssi = ap_info.rssi;
                xSemaphoreGive(xSemaphoreWiFi);
            } else {
                ESP_LOGE(TAG, "lock error TASK_WIFI_REQUEST_STA_STATUS");
            }
	    user_refresh();
	}

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

mercurial