blackmagic-esp32-s2/main/network.c

280 lines
9.2 KiB
C
Raw Normal View History

2021-11-22 11:24:16 +00:00
#include "nvs.h"
#include "network.h"
#include <esp_log.h>
#include <esp_wifi.h>
#include <freertos/event_groups.h>
#include <string.h>
#include <m-string.h>
#include <mdns.h>
#include <lwip/apps/netbiosns.h>
#define TAG "network"
#define ESP_WIFI_SSID "blackmagic"
#define ESP_WIFI_PASS "iamwitcher"
#define ESP_WIFI_CHANNEL 1
#define MDNS_HOST_NAME "blackmagic"
#define MDNS_INSTANCE "blackmagic web server"
#ifndef min
#define min(a, b) \
({ \
__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a < _b ? _a : _b; \
})
#endif
#define WIFI_MAXIMUM_RETRY 3
// TODO remove global vars
static EventGroupHandle_t wifi_event_group;
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static WIFIMode wifi_mode = WIFIModeSTA;
static int s_retry_num = 0;
static void
sta_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
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) {
if(s_retry_num < WIFI_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG, "connect to the AP fail");
} 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, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
}
}
static void
ap_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
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 " join, 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 " leave, AID=%d", MAC2STR(event->mac), event->aid);
}
}
static void network_start_ap(mstring_t* ap_ssid, mstring_t* ap_pass) {
ESP_LOGI(TAG, "init access point mode");
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, &ap_event_handler, NULL, NULL));
wifi_config_t wifi_config;
memset(&wifi_config, 0, sizeof(wifi_config_t));
wifi_config.ap.ssid_len = strlen("");
wifi_config.ap.channel = ESP_WIFI_CHANNEL;
wifi_config.ap.max_connection = 4;
wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK;
memcpy(
&wifi_config.ap.ssid,
mstring_get_cstr(ap_ssid),
min(sizeof(wifi_config.ap.ssid), mstring_length(ap_ssid)));
memcpy(
&wifi_config.ap.password,
mstring_get_cstr(ap_pass),
min(sizeof(wifi_config.ap.password), mstring_length(ap_pass)));
wifi_config.ap.ssid_len = mstring_length(ap_ssid);
if(mstring_length(ap_pass) == 0) {
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
}
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(
TAG,
"wifi_init_softap finished. SSID:%s password:%s channel:%d",
mstring_get_cstr(ap_ssid),
mstring_get_cstr(ap_pass),
ESP_WIFI_CHANNEL);
ESP_LOGI(TAG, "init access point mode done");
}
static bool network_connect_ap(mstring_t* ap_ssid, mstring_t* ap_pass) {
bool result = false;
ESP_LOGI(TAG, "init connect to AP");
wifi_event_group = xEventGroupCreate();
esp_netif_t* netif = esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(
esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &sta_event_handler, NULL));
ESP_ERROR_CHECK(
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &sta_event_handler, NULL));
wifi_config_t wifi_config;
memset(&wifi_config, 0, sizeof(wifi_config_t));
memcpy(
&wifi_config.sta.ssid,
mstring_get_cstr(ap_ssid),
min(sizeof(wifi_config.sta.ssid), mstring_length(ap_ssid)));
memcpy(
&wifi_config.sta.password,
mstring_get_cstr(ap_pass),
min(sizeof(wifi_config.sta.password), mstring_length(ap_pass)));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(
TAG,
"init connect to AP done. SSID:%s password:%s",
mstring_get_cstr(ap_ssid),
mstring_get_cstr(ap_pass));
/* 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(
wifi_event_group, 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 AP");
result = true;
} else if(bits & WIFI_FAIL_BIT) {
ESP_LOGI(TAG, "failed to connect to AP");
} else {
ESP_LOGE(TAG, "unexpected event while connecting to AP");
}
ESP_ERROR_CHECK(
esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &sta_event_handler));
ESP_ERROR_CHECK(
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &sta_event_handler));
vEventGroupDelete(wifi_event_group);
if(!result) {
ESP_LOGI(TAG, "wifi deinit");
if(esp_wifi_disconnect() == ESP_FAIL) {
ESP_LOGE(TAG, "cannot disconnect wifi, internal WIFI error");
abort();
}
ESP_ERROR_CHECK(esp_wifi_stop());
ESP_ERROR_CHECK(esp_wifi_deinit());
ESP_ERROR_CHECK(esp_wifi_clear_default_wifi_driver_and_handlers(netif));
esp_netif_destroy(netif);
ESP_LOGI(TAG, "wifi deinit done");
}
return result;
}
WIFIMode network_init(void) {
mstring_t* ap_mode = mstring_alloc();
mstring_t* ap_ssid = mstring_alloc();
mstring_t* ap_pass = mstring_alloc();
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_netif_init());
if(nvs_load_string("ap_mode", ap_mode) != ESP_OK) {
ESP_LOGW(TAG, "cannot load [ap_mode]");
mstring_set(ap_mode, ESP_WIFI_MODE_AP);
nvs_save_string("ap_mode", ap_mode);
}
if(nvs_load_string("ap_ssid", ap_ssid) != ESP_OK) {
ESP_LOGW(TAG, "cannot load [ap_ssid]");
mstring_set(ap_ssid, ESP_WIFI_SSID);
nvs_save_string("ap_ssid", ap_ssid);
}
if(nvs_load_string("ap_pass", ap_pass) != ESP_OK) {
ESP_LOGW(TAG, "cannot load [ap_pass]");
mstring_set(ap_pass, ESP_WIFI_PASS);
nvs_save_string("ap_pass", ap_pass);
}
if(mstring_length(ap_pass) < 8) {
ESP_LOGW(TAG, "too short [ap_pass]");
mstring_set(ap_ssid, ESP_WIFI_SSID);
nvs_save_string("ap_ssid", ap_ssid);
mstring_set(ap_pass, ESP_WIFI_PASS);
nvs_save_string("ap_pass", ap_pass);
mstring_set(ap_mode, ESP_WIFI_MODE_AP);
nvs_save_string("ap_mode", ap_mode);
}
if(mstring_length(ap_ssid) < 1 || mstring_length(ap_ssid) > 32) {
ESP_LOGW(TAG, "too short or too long [ap_ssid]");
mstring_set(ap_ssid, ESP_WIFI_SSID);
nvs_save_string("ap_ssid", ap_ssid);
mstring_set(ap_pass, ESP_WIFI_PASS);
nvs_save_string("ap_pass", ap_pass);
mstring_set(ap_mode, ESP_WIFI_MODE_AP);
nvs_save_string("ap_mode", ap_mode);
}
if(strcmp(mstring_get_cstr(ap_mode), ESP_WIFI_MODE_STA) == 0) {
if(!network_connect_ap(ap_ssid, ap_pass)) {
ESP_LOGW(TAG, "cannot connect to AP");
} else {
wifi_mode = WIFIModeSTA;
}
} else {
network_start_ap(ap_ssid, ap_pass);
wifi_mode = WIFIModeAP;
mstring_set(ap_mode, ESP_WIFI_MODE_AP);
nvs_save_string("ap_mode", ap_mode);
}
mstring_free(ap_ssid);
mstring_free(ap_pass);
ESP_LOGI(TAG, "init mdns");
mdns_init();
mdns_hostname_set(MDNS_HOST_NAME);
mdns_instance_name_set(MDNS_INSTANCE);
mdns_txt_item_t serviceTxtData[] = {{"board", "esp32"}, {"path", "/"}};
ESP_ERROR_CHECK(mdns_service_add(
"ESP32-WebServer",
"_http",
"_tcp",
80,
serviceTxtData,
sizeof(serviceTxtData) / sizeof(serviceTxtData[0])));
ESP_LOGI(TAG, "init MDNS done");
ESP_LOGI(TAG, "init netbios");
netbiosns_init();
netbiosns_set_name(MDNS_HOST_NAME);
ESP_LOGI(TAG, "init netbios done");
return wifi_mode;
}
WIFIMode network_get_mode(void) {
return wifi_mode;
}