diff -r 000000000000 -r 88d965579617 main/task_wifi.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/task_wifi.c Tue Oct 08 12:00:31 2019 +0200 @@ -0,0 +1,320 @@ +/** + * @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); + } + 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, 10) == pdTRUE) { + wifi_state->STA_connected = false; + wifi_state->STA_online = false; + wifi_state->STA_rssi = 0; + xSemaphoreGive(xSemaphoreWiFi); + } + 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); + } + 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); + } + 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); +} + +