You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
356 lines
9.5 KiB
356 lines
9.5 KiB
#include "nx/firmware/Wifi.h" |
|
|
|
#include "freertos/FreeRTOS.h" |
|
#include "freertos/task.h" |
|
#include "freertos/event_groups.h" |
|
#include "esp_system.h" |
|
#include "esp_wifi.h" |
|
#include "esp_event.h" |
|
#include "esp_log.h" |
|
#include "nvs_flash.h" |
|
|
|
#include "lwip/err.h" |
|
#include "lwip/sys.h" |
|
#include "lwip/dns.h" |
|
#include "lwip/inet.h" |
|
#include "lwip/sockets.h" |
|
|
|
#define TAG "WIFI" |
|
|
|
#define WIFI_MAXIMUM_RETRY -1 |
|
#define WIFI_RECONNECT_DELAY_SEC 15 |
|
#define WIFI_AP_CHANNEL 11 |
|
#define WIFI_MAX_CONNECTION 3 |
|
|
|
/* The event group allows multiple bits for each event, but we only care about two events: |
|
* - we are connected to the AP with an IP |
|
* - we failed to connect after the maximum amount of retries */ |
|
#define WIFI_CONNECTED_BIT BIT0 |
|
#define WIFI_FAIL_BIT BIT1 |
|
|
|
#define WIFI_AP_PASSWORD "" |
|
|
|
#define DEVICE_NAME_MAX_LEN 32 |
|
|
|
static const int POWER_SAVE_AP_BEACON_INTERVAL = 10; |
|
|
|
static EventGroupHandle_t wifiEventGroup; |
|
|
|
static int retryCount = 0; |
|
|
|
static WifiSettings* settings = NULL; |
|
|
|
static WifiCallback errorCallback = NULL; |
|
static WifiCallback connectedCallback = NULL; |
|
|
|
static char deviceName[DEVICE_NAME_MAX_LEN] = {0}; |
|
|
|
static bool initWifiStation(void); |
|
|
|
static bool initWifiAp(void); |
|
|
|
// --------- Public API --------- // |
|
|
|
bool nxInitWifi(WifiSettings* wifiSettings) |
|
{ |
|
settings = wifiSettings; |
|
if (settings->mode == NX_WIFI_MODE_AP) { |
|
return initWifiAp(); |
|
} |
|
return initWifiStation(); |
|
} |
|
|
|
void nxSetWifiConnectedCallback(WifiCallback callback) |
|
{ |
|
connectedCallback = callback; |
|
} |
|
|
|
void nxSetWifiErrorCallback(WifiCallback callback) |
|
{ |
|
errorCallback = callback; |
|
} |
|
|
|
|
|
// ------------------------------ // |
|
|
|
|
|
static void generateDeviceName() |
|
{ |
|
ESP_LOGI(TAG, "Generating device name with prefix %s", settings->devicePrefix); |
|
|
|
uint8_t mac[6]; |
|
esp_read_mac(mac, 0); // 0 means WiFi base MAC address |
|
sprintf(deviceName, "%s%x%x%x%x%x%x", settings->devicePrefix, |
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); |
|
ESP_LOGI(TAG, "Device name generated: %s", deviceName); |
|
} |
|
|
|
static void handleStaEvents(esp_event_base_t event_base, int32_t event_id, void* event_data) |
|
{ |
|
ESP_LOGI(TAG, "WiFi STA event received; event ID: %i", event_id); |
|
|
|
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { |
|
esp_wifi_connect(); |
|
} |
|
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { |
|
ESP_LOGE(TAG, "Cannot connect to the AP"); |
|
if (errorCallback) { |
|
errorCallback(); |
|
} |
|
|
|
if (WIFI_MAXIMUM_RETRY < 0 || retryCount < WIFI_MAXIMUM_RETRY) { |
|
ESP_LOGI(TAG, "Sleeping %i seconds before AP reconnection attempt", WIFI_RECONNECT_DELAY_SEC); |
|
vTaskDelay(WIFI_RECONNECT_DELAY_SEC * 1000 / portTICK_PERIOD_MS); |
|
|
|
ESP_LOGI(TAG, "AP reconnection..."); |
|
esp_wifi_connect(); |
|
retryCount++; |
|
} |
|
else { |
|
xEventGroupSetBits(wifiEventGroup, WIFI_FAIL_BIT); |
|
} |
|
} |
|
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { |
|
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; |
|
ESP_LOGI(TAG, "IP address acquired: " IPSTR, IP2STR(&event->ip_info.ip)); |
|
retryCount = 0; |
|
if (connectedCallback) { |
|
connectedCallback(); |
|
} |
|
xEventGroupSetBits(wifiEventGroup, WIFI_CONNECTED_BIT); |
|
} |
|
} |
|
|
|
static void handleApEvents(esp_event_base_t event_base, int32_t event_id, void* event_data) |
|
{ |
|
ESP_LOGI(TAG, "WiFi AP event received; event ID: %i", event_id); |
|
|
|
if (event_id == WIFI_EVENT_AP_STACONNECTED) { |
|
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data; |
|
ESP_LOGI(TAG, "Station "MACSTR" joined, AID=%d", |
|
MAC2STR(event->mac), event->aid); |
|
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) { |
|
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data; |
|
ESP_LOGI(TAG, "Station "MACSTR" left, AID=%d", |
|
MAC2STR(event->mac), event->aid); |
|
} |
|
} |
|
|
|
static void eventHandler(void* arg, esp_event_base_t event_base, |
|
int32_t event_id, void* event_data) |
|
{ |
|
ESP_LOGI(TAG, "Handling WiFi event in mode %i", settings->mode); |
|
|
|
if (settings->mode == NX_WIFI_MODE_STA) { |
|
handleStaEvents(event_base, event_id, event_data); |
|
} |
|
else { |
|
handleApEvents(event_base, event_id, event_data); |
|
} |
|
} |
|
|
|
|
|
static bool initWifiAp(void) |
|
{ |
|
generateDeviceName(NX_WIFI_MODE_AP); |
|
ESP_LOGI(TAG, "Initializing WiFi AP"); |
|
|
|
ESP_ERROR_CHECK(esp_netif_init()); |
|
ESP_ERROR_CHECK(esp_event_loop_create_default()); |
|
esp_netif_create_default_wifi_ap(); |
|
|
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); |
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); |
|
|
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, |
|
ESP_EVENT_ANY_ID, |
|
&eventHandler, |
|
NULL, |
|
NULL)); |
|
|
|
wifi_config_t wifiConfig = { |
|
.ap = { |
|
.ssid_len = strlen(deviceName), |
|
.channel = WIFI_AP_CHANNEL, |
|
.password = WIFI_AP_PASSWORD, |
|
.max_connection = WIFI_MAX_CONNECTION, |
|
.authmode = WIFI_AUTH_WPA_WPA2_PSK |
|
}, |
|
}; |
|
strcpy((char*)(wifiConfig.ap.ssid), deviceName); |
|
|
|
if (strlen((const char*)wifiConfig.ap.password) == 0) { |
|
wifiConfig.ap.authmode = WIFI_AUTH_OPEN; |
|
} |
|
|
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); |
|
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifiConfig)); |
|
ESP_ERROR_CHECK(esp_wifi_start()); |
|
|
|
ESP_LOGI(TAG, "WiFi AP initialization finished. SSID: %s password: %s channel: %d", |
|
wifiConfig.ap.ssid, wifiConfig.ap.password, wifiConfig.ap.channel); |
|
return true; |
|
} |
|
|
|
static void configStaticApAddress(esp_netif_t* sta) |
|
{ |
|
ESP_LOGI(TAG, "Setting static IP address"); |
|
esp_netif_dhcpc_stop(sta); |
|
esp_netif_ip_info_t ip_info; |
|
|
|
IP4_ADDR(&ip_info.ip, |
|
settings->ip4addr[0], |
|
settings->ip4addr[1], |
|
settings->ip4addr[2], |
|
settings->ip4addr[3] |
|
); |
|
IP4_ADDR(&ip_info.gw, |
|
settings->ip4gw[0], |
|
settings->ip4gw[1], |
|
settings->ip4gw[2], |
|
settings->ip4gw[3] |
|
); |
|
IP4_ADDR(&ip_info.netmask, |
|
settings->ip4mask[0], |
|
settings->ip4mask[1], |
|
settings->ip4mask[2], |
|
settings->ip4mask[3] |
|
); |
|
ESP_LOGI(TAG, "Calling esp_netif_set_ip_info"); |
|
esp_netif_set_ip_info(sta, &ip_info); |
|
} |
|
|
|
static void registerWifiStaHandlers(void) |
|
{ |
|
ESP_LOGI(TAG, "Registering WiFi station handlers"); |
|
|
|
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, |
|
&eventHandler, |
|
NULL, |
|
&instance_any_id)); |
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, |
|
IP_EVENT_STA_GOT_IP, |
|
&eventHandler, |
|
NULL, |
|
&instance_got_ip)); |
|
} |
|
|
|
static void configureWifiSta(void) |
|
{ |
|
ESP_LOGI(TAG, "Configuring WiFi station"); |
|
|
|
wifi_config_t wifi_config = { |
|
.sta = { |
|
.threshold.authmode = WIFI_AUTH_WPA2_PSK, |
|
.listen_interval = POWER_SAVE_AP_BEACON_INTERVAL, |
|
.pmf_cfg = { |
|
.capable = true, |
|
.required = false |
|
}, |
|
}, |
|
}; |
|
|
|
strcpy((char*)wifi_config.sta.ssid, settings->wname); |
|
strcpy((char*)wifi_config.sta.password, settings->wpass); |
|
|
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); |
|
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); |
|
ESP_LOGI(TAG, "WiFi station configured"); |
|
} |
|
|
|
static bool waitForStaConnection(void) |
|
{ |
|
ESP_LOGI(TAG, "Waiting for the WiFi station to connect"); |
|
|
|
bool result = false; |
|
|
|
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum |
|
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ |
|
EventBits_t bits = xEventGroupWaitBits(wifiEventGroup, |
|
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, |
|
pdFALSE, |
|
pdFALSE, |
|
portMAX_DELAY); |
|
|
|
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually |
|
* happened. */ |
|
if (bits & WIFI_CONNECTED_BIT) { |
|
ESP_LOGI(TAG, "Connected to the AP; SSID: %s", settings->wname); |
|
|
|
//resolveBrokerAddr(); |
|
|
|
if (*settings->usePowerSave) { |
|
esp_wifi_set_ps(WIFI_PS_MAX_MODEM); |
|
} |
|
|
|
result = true; |
|
} else if (bits & WIFI_FAIL_BIT) { |
|
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", |
|
settings->wname, settings->wpass); |
|
if (errorCallback) { |
|
errorCallback(); |
|
} |
|
} else { |
|
ESP_LOGE(TAG, "UNEXPECTED EVENT"); |
|
} |
|
return result; |
|
} |
|
|
|
static bool initWifiStation(void) |
|
{ |
|
generateDeviceName(NX_WIFI_MODE_STA); |
|
ESP_LOGI(TAG, "Initializing WiFi station"); |
|
|
|
wifiEventGroup = xEventGroupCreate(); |
|
|
|
ESP_ERROR_CHECK(esp_netif_init()); |
|
ESP_ERROR_CHECK(esp_event_loop_create_default()); |
|
|
|
esp_netif_t* sta = esp_netif_create_default_wifi_sta(); |
|
|
|
if (*settings->useStaticAddr) { |
|
configStaticApAddress(sta); |
|
} |
|
|
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); |
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); |
|
|
|
registerWifiStaHandlers(); |
|
|
|
configureWifiSta(); |
|
|
|
ESP_ERROR_CHECK(esp_wifi_start() ); |
|
|
|
ESP_LOGI(TAG, "Updating the host name"); |
|
ESP_ERROR_CHECK(esp_netif_set_hostname(sta, deviceName)); |
|
|
|
ESP_LOGI(TAG, "Updating DNS server IPv4"); |
|
|
|
esp_netif_dns_info_t dns; |
|
dns.ip.u_addr.ip4.addr = PP_HTONL(LWIP_MAKEU32( |
|
settings->dns[0], |
|
settings->dns[1], |
|
settings->dns[2], |
|
settings->dns[3])); |
|
dns.ip.type = IPADDR_TYPE_V4; |
|
ESP_ERROR_CHECK(esp_netif_set_dns_info(sta, ESP_NETIF_DNS_MAIN, &dns)); |
|
|
|
|
|
return waitForStaConnection(); |
|
} |
|
|
|
const char* nxGetWifiDeviceName(void) |
|
{ |
|
if (settings && settings->devicePrefix && strlen(deviceName) == 0) { |
|
generateDeviceName(); |
|
return deviceName; |
|
} |
|
else if (strlen(deviceName)) { |
|
return deviceName; |
|
} |
|
return "unknown"; |
|
} |
|
|
|
|