main/task_wifi.c

Sun, 16 Apr 2023 12:27:12 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Sun, 16 Apr 2023 12:27:12 +0200
changeset 30
7448b8dd4288
parent 24
74609f70411e
child 35
9827c5a08c63
permissions
-rw-r--r--

Preparations for BLE GATT. Added extra time after INA219 is powered on before measurement. Reduced LEDC frequency to 60 Hz, that makes the LED lights less nervous. Hardware mod on output 4, now needs external pulldown resistor.

/**
 * @file task_wifi.c
 * @brief WiFi task. Connects to a known Access Point.
 */


#include "config.h"


static const char *TAG = "task_wifi";

#define ESP_WIFI_SSID           CONFIG_ESP_WIFI_SSID
#define ESP_WIFI_PASS           CONFIG_ESP_WIFI_PASSWORD

SemaphoreHandle_t       	xSemaphoreWiFi = NULL;		///< Semaphore WiFi task.
EventGroupHandle_t		xEventGroupWifi;		///< Events WiFi task.
esp_event_handler_instance_t	instance_any_id;		///< WiFi event handler.
esp_event_handler_instance_t	instance_got_ip;		///< IP event handler.

WIFI_State			*wifi_state = NULL;		///< Public state for other tasks.
esp_netif_t			*sta_netif = NULL;		///< Station interface.


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.


static void init_wifi(void);
void wifi_connect(void);


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


bool ready_WiFi(void)
{
    if ((xEventGroupGetBits(xEventGroupWifi) & (TASK_WIFI_STA_CONNECTED | TASK_WIFI_HAS_IP)) == (TASK_WIFI_STA_CONNECTED | TASK_WIFI_HAS_IP))
        return true;
    return false;
}



void request_WiFi(bool connect)
{
    if (connect)
    	xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
    else
	xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT);
}



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_STA_START:
		ESP_LOGI(TAG, "Event wifi START");
        	// Set the hostname for the dhcp client.
#ifdef CONFIG_CODE_PRODUCTION
		ESP_ERROR_CHECK(esp_netif_set_hostname(sta_netif, "balkon"));
#endif
#ifdef CONFIG_CODE_TESTING
		ESP_ERROR_CHECK(esp_netif_set_hostname(sta_netif, "wemos"));
#endif
		break;

	case WIFI_EVENT_STA_CONNECTED: {
                wifi_ap_record_t ap_info;
		esp_wifi_sta_get_ap_info(&ap_info);
		ESP_LOGI(TAG, "Event STA connected rssi=%d", ap_info.rssi);
                if (xSemaphoreTake(xSemaphoreWiFi, 35) == pdTRUE) {
                    wifi_state->STA_connected = true;
                    wifi_state->STA_rssi = ap_info.rssi;
                    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, reason: %d", disconnected->reason);

		/*
		 * If it's not a normal request to disconnect, make sure the mqtt
		 * connection will be removed.
		 */
		if (disconnected->reason != 8)
		    request_mqtt(false);

		/*
		 * Error conditions.
		 */
		if (disconnected->reason == 2) {
		    ESP_LOGW(TAG, "Auth Expire: try to recover");
		    wifi_connect();
		} else if (disconnected->reason == 39) {
		    ESP_LOGW(TAG, "Timeout: try to recover");
		    ESP_ERROR_CHECK(esp_wifi_connect());
		}
                if (xSemaphoreTake(xSemaphoreWiFi, 25) == pdTRUE) {
                    wifi_state->STA_connected = false;
                    wifi_state->STA_online = false;
                    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_LOGW(TAG, "Unknown WiFi event %d", (int)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:
		//ESP_LOGE(TAG, "got_ip_event_handler()");
		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");
		}
		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");
		}
		break;

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


static void init_wifi(void)
{
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    xSemaphoreWiFi = xSemaphoreCreateMutex();

    /* initialize the tcp stack */
    ESP_ERROR_CHECK(esp_netif_init());
    sta_netif = esp_netif_create_default_wifi_sta();
    assert(sta_netif);

    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_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_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_start());

    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED);
    xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED);
}


void wifi_connect(void)
{
    ESP_LOGI(TAG, "wifi_connect() start");
    wifi_config_t	wifi_Config = {		///< Current STA configuration.
	.sta = {
	    .ssid = ESP_WIFI_SSID,
	    .password = ESP_WIFI_PASS,
	    .threshold.authmode = WIFI_AUTH_WPA2_PSK,
	},
    };
    // .threshold.authmode = WIFI_AUTH_WPA2_PSK,

    ESP_ERROR_CHECK(esp_wifi_disconnect());
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_Config) );

    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_FAILED);
    esp_err_t wifierror = esp_wifi_connect();

    if (wifierror != ESP_OK) {
	ESP_LOGE(TAG, "esp_wifi_connect() rc=%04x %s", (int)wifierror, esp_err_to_name(wifierror));
	xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_FAILED);
    } else {
	ESP_LOGI(TAG, "Connected Ok");
    }
    ESP_LOGI(TAG, "wifi_connect() done");
}


void task_wifi( void * pvParameters )
{
//    uint64_t starttime = 0;

    ESP_LOGI(TAG, "Starting WiFi task");
    esp_log_level_set("wifi", ESP_LOG_ERROR);

    /*
     * memory allocation of objects used by the task 
     */
    wifi_state = malloc(sizeof(WIFI_State));
    memset(wifi_state, 0x00, sizeof(WIFI_State));

    /*
     * event group for the wifi driver
     */
    xEventGroupWifi = xEventGroupCreate();

    /*
     * init wifi as station
     */
    init_wifi();
    EventBits_t uxBits;
    int8_t tx_level;
    ESP_ERROR_CHECK(esp_wifi_get_max_tx_power(&tx_level));
    ESP_LOGI(TAG, "Startup completed, maximum transmit power %d dBm", tx_level / 4);

    for(;;) {

	/*
	 * Actions that can trigger: request a connection or a disconnection
	 */
	uxBits = xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT | 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 request bit
	     */
	    xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT);
//	    ESP_LOGI(TAG, "Connection time %llu", (esp_timer_get_time() / 1000) - starttime);

	} else if (uxBits & TASK_WIFI_REQUEST_STA_CONNECT) {

	    ESP_LOGI(TAG, "Request STA connect `%s' `%s'", ESP_WIFI_SSID, ESP_WIFI_PASS);
//	    starttime = esp_timer_get_time() / 1000;
	    wifi_connect();

	    /*
	     * 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.
	     */
	    uxBits = xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED | TASK_WIFI_STA_FAILED, pdFALSE, pdFALSE, 5000 / portTICK_PERIOD_MS);

	    if (uxBits & (TASK_WIFI_STA_CONNECTED | TASK_WIFI_STA_FAILED)) {
		/*
		 * only save the config if the connection was successful!
		 */
		if (uxBits & TASK_WIFI_STA_FAILED) {
		    ESP_LOGI(TAG, "No AP found");
		    vTaskDelay(3000 / portTICK_PERIOD_MS);
		    ESP_LOGW(TAG, "Connection failed");
		    /* failed attempt to connect regardles of the reason */
            	}
	    }

	    /*
	     * Finally: release the request bit
	     */
            xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT);
	}

    } /* for(;;) */
}

mercurial