diff -r 000000000000 -r 913eb9ca40b1 main/task_wifi.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/task_wifi.c Thu Oct 19 17:32:16 2023 +0200 @@ -0,0 +1,422 @@ +/** + * @file task_wifi.c + * @brief WiFi task. Connect to the known AP with the strongest signal. + */ + + +#include "dcf77tx.h" + +#define MAX_AP_NUM 10 + +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 = (uint8_t *)CONFIG_ESP_WIFI_SSID, + .bssid = 0, + .channel = 0, + .show_hidden = false +}; + +bool _wifi_ScanDone = false; ///< Scan ready +bool _wifi_BetterAP = false; ///< If better AP available. +int8_t _wifi_RSSI = -127; ///< Latest RSSI level. +uint16_t _wifi_Scanned = 0; ///< Total scanned APs. + +extern char hostname[]; ///< Generated hostname + + + +const int TASK_WIFI_REQUEST_STA_DISCONNECT = BIT0; ///< When set, means a client requested to disconnect from currently connected AP. +const int TASK_WIFI_REQUEST_STA_CONNECT = BIT1; ///< When set, means a client requested to connect to an access point. +const int TASK_WIFI_REQUEST_STA_SCAN = BIT2; ///< When set, means a client requested a AP scan. +const int TASK_WIFI_REQUEST_STA_STATUS = BIT3; ///< When set, means a client requested to update the connection status. + +const int TASK_WIFI_HAS_IP = BIT4; ///< 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 BIT5. + + + +/** + * @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); +} + + + +void request_WiFi(void) +{ + xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); +} + + +void scan_WiFi(void) +{ + xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_SCAN); +} + + +void disconnect_WiFi(void) +{ + xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_DISCONNECT); + xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); +} + + +static void print_servers(void) +{ + ESP_LOGI(TAG, "List of configured NTP servers:"); + + for (uint8_t i = 0; i < SNTP_MAX_SERVERS; ++i){ + if (esp_sntp_getservername(i)){ + ESP_LOGI(TAG, "server %d: %s", i, esp_sntp_getservername(i)); + } else { + // we have either IPv4 or IPv6 address, let's print it + char buff[64]; + ip_addr_t const *ip = esp_sntp_getserver(i); + if (ipaddr_ntoa_r(ip, buff, 64) != NULL) + ESP_LOGI(TAG, "server %d: %s", i, buff); + } + } +} + + +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)); + ESP_LOGI(TAG, "Event wifi Scane done, %d records", ap_num); + _wifi_BetterAP = false; + for (int i = 0; i < ap_num; i++) { + wifi_ap_record_t ap = accessp_records[i]; + ESP_LOGI(TAG, "AP:%d bssid:%02x:%02x:%02x:%02x:%02x:%02x ssid:%s ch:%d rssi:%d", + i, ap.bssid[0], ap.bssid[1], ap.bssid[2], ap.bssid[3], ap.bssid[4], ap.bssid[5], + ap.ssid, ap.primary, ap.rssi); + if (ap.rssi > CONFIG_ESP_WIFI_ROAMING_LEVEL && ap.rssi > (_wifi_RSSI + 3)) { + _wifi_BetterAP = true; + ESP_LOGI(TAG, "AP:%d is a better AP", i); + } + } + _wifi_Scanned = ap_num; + _wifi_ScanDone = true; + if (_wifi_BetterAP) { + ESP_LOGI(TAG, "Disconnect current AP"); + disconnect_WiFi(); + } + break; + } + + case WIFI_EVENT_STA_START: + { + ESP_LOGI(TAG, "Event wifi START"); + // Set the configured hostname for the dhcp client. + ESP_ERROR_CHECK(esp_netif_set_hostname(sta_netif, hostname)); + esp_wifi_connect(); + _wifi_BetterAP = false; + 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; + wifi_state->STA_channel = ap_info.primary; + sprintf(wifi_state->STA_ssid, "%s", ap_info.ssid); + snprintf(wifi_state->STA_bssid, 18, "%02x:%02x:%02x:%02x:%02x:%02x", + ap_info.bssid[0], ap_info.bssid[1], ap_info.bssid[2], ap_info.bssid[3], ap_info.bssid[4], ap_info.bssid[5]); + xSemaphoreGive(xSemaphoreWiFi); + } else { + ESP_LOGE(TAG, "wifi_event_handler() lock error WIFI_EVENT_STA_CONNECTED"); + } + print_servers(); + _wifi_BetterAP = false; + 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"); + } + _wifi_BetterAP = false; + xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED); + xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED); + break; + } + + default: + ESP_LOGW(TAG, "Unknown WiFi event %ld", 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"); + } + +// ESP_LOGI(TAG, "Starting SNTP"); +// esp_netif_sntp_start(); + + 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; + + case IP_EVENT_AP_STAIPASSIGNED: + ESP_LOGI(TAG, "IP_EVENT_AP_STAIPASSIGNED"); + break; + + default: + ESP_LOGW(TAG, "Unknown IP event %ld", event_id); + break; + } +} + + +void time_sync_notification_cb(struct timeval *tv) +{ + time_t now; + char strftime_buf[64]; + struct tm timeinfo; + + ESP_LOGI(TAG, "Notification of a time synchronization event"); + 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); + ESP_LOGI(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_LOGI(TAG, "Starting WiFi"); + + /* 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()); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + sta_netif = esp_netif_create_default_wifi_sta(); + assert(sta_netif); + + /* + * Setup SNTP configuration + */ + /** + * NTP server address could be acquired via DHCP, + * see following menuconfig options: + * 'LWIP_DHCP_GET_NTP_SRV' - enable STNP over DHCP + * 'LWIP_SNTP_DEBUG' - enable debugging messages + * + * NOTE: This call should be made BEFORE esp acquires IP address from DHCP, + * otherwise NTP option would be rejected by default. + */ + ESP_LOGI(TAG, "Initializing SNTP"); + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org"); + config.start = false; // start SNTP service explicitly (after connecting) + config.server_from_dhcp = true; // accept NTP offers from DHCP server, if any (need to enable *before* connecting) + config.renew_servers_after_new_IP = true; // let esp-netif update configured SNTP server(s) after receiving DHCP lease + config.index_of_first_server = 1; // updates from server num 1, leaving server 0 (from DHCP) intact + config.ip_event_to_renew = IP_EVENT_STA_GOT_IP; + config.sync_cb = time_sync_notification_cb; // only if we need the notification function + esp_netif_sntp_init(&config); + ESP_LOGI(TAG, "Starting SNTP"); + esp_netif_sntp_start(); + + + /* + * memory allocation of objects used by the task + */ + accessp_records = (wifi_ap_record_t*)malloc(sizeof(wifi_ap_record_t) * MAX_AP_NUM); + xSemaphoreWiFi = xSemaphoreCreateMutex(); + wifi_state = malloc(sizeof(WIFI_State)); + memset(wifi_state, 0x00, sizeof(WIFI_State)); + + /* + * init wifi as station + */ + 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) ); + + wifi_config_t wifi_config = { + .sta = { + .ssid = CONFIG_ESP_WIFI_SSID, + .password = CONFIG_ESP_WIFI_PASSWORD, +#if CONFIG_WIFI_ALL_CHANNEL_SCAN + .scan_method = WIFI_ALL_CHANNEL_SCAN, +#elif CONFIG_WIFI_FAST_SCAN + .scan_method = WIFI_FAST_SCAN, +#endif + .failure_retry_cnt = 3, + .sort_method = WIFI_CONNECT_AP_BY_SIGNAL, + .threshold.rssi = CONFIG_ESP_FAST_SCAN_MINIMUM_SIGNAL, + .threshold.authmode = WIFI_AUTH_WPA2_PSK, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); + ESP_ERROR_CHECK(esp_wifi_start()); + + xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); + xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED); + 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_STA_DISCONNECT | TASK_WIFI_REQUEST_STA_SCAN | 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 + */ + 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); + ESP_LOGI(TAG, "Request STA disconnect is done"); + + } else if (uxBits & TASK_WIFI_REQUEST_STA_CONNECT) { + + ESP_LOGI(TAG, "Request STA connect"); + xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_FAILED); + xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_CONNECT); + + ESP_LOGI(TAG, "Connecting to `%s'", CONFIG_ESP_WIFI_SSID); + esp_err_t wifierror = esp_wifi_connect(); + if (wifierror != ESP_OK) { + ESP_LOGE(TAG, "esp_wifi_connect() `%s' rc=%04x", CONFIG_ESP_WIFI_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); + + } else if (uxBits & TASK_WIFI_REQUEST_STA_STATUS) { + /* + * Request WiFi update status, refresh the rssi. + */ + ESP_LOGD(TAG, "Request STA status"); + 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); + _wifi_RSSI = ap_info.rssi; + _wifi_BetterAP = false; + if (xSemaphoreTake(xSemaphoreWiFi, 35) == pdTRUE) { + wifi_state->STA_rssi = ap_info.rssi; + wifi_state->STA_channel = ap_info.primary; + snprintf(wifi_state->STA_bssid, 18, "%02x:%02x:%02x:%02x:%02x:%02x", + ap_info.bssid[0], ap_info.bssid[1], ap_info.bssid[2], ap_info.bssid[3], ap_info.bssid[4], ap_info.bssid[5]); + xSemaphoreGive(xSemaphoreWiFi); + } else { + ESP_LOGE(TAG, "lock error TASK_WIFI_REQUEST_STA_STATUS"); + } + + } else if (uxBits & TASK_WIFI_REQUEST_STA_SCAN) { + + ESP_LOGI(TAG, "Request STA scan"); + xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_REQUEST_STA_SCAN); + /* safe guard against overflow */ + ap_num = MAX_AP_NUM; + _wifi_ScanDone = false; + _wifi_BetterAP = false; + ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, false)); + } + + } /* for(;;) */ +} + +