main/task_wifi.c

Fri, 08 Nov 2019 22:40:15 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Fri, 08 Nov 2019 22:40:15 +0100
changeset 26
8a3696620c0a
parent 24
64078aa15512
child 27
8bb63daa7b46
permissions
-rw-r--r--

Increaded stacksize for the user process. Implemented the network update using the proven brewboard code. Reverted the lock release and display sendbuffer lines to the previous code. The networks status screen uses the wifi lock.

/**
 * @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);
                } 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, 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);
		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);
	    } else {
		ESP_LOGE(TAG, "got_ip_event_handler() lock error IP_EVENT_STA_GOT_IP");
	    }
	    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);
            } else {
                ESP_LOGE(TAG, "got_ip_event_handler() lock error IP_EVENT_STA_LOST_IP");
            }
	    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