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

#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";
}