|
@@ -1 +1,153 @@
|
|
|
-#include "kbf/wifi.h"
|
|
|
+#include "kbf/wifi.h"
|
|
|
+
|
|
|
+#include <esp_log.h>
|
|
|
+#include <esp_wifi.h>
|
|
|
+
|
|
|
+#define KBF_INTERNAL
|
|
|
+
|
|
|
+#include "kbf/internal/wifi.h"
|
|
|
+#include "kbf/macros.h"
|
|
|
+#include "kbf/exception.h"
|
|
|
+
|
|
|
+using namespace std;
|
|
|
+
|
|
|
+namespace {
|
|
|
+ constexpr const char *const TAG = "kbf::wifi::ap";
|
|
|
+
|
|
|
+ string ssid;
|
|
|
+ string password;
|
|
|
+
|
|
|
+ bool dhcpInit = false;
|
|
|
+
|
|
|
+ esp_netif_obj *interface = nullptr;
|
|
|
+ wifi_ap_config_t apConfig = {};
|
|
|
+
|
|
|
+ esp_event_handler_instance_t connectHandler = {};
|
|
|
+ esp_event_handler_instance_t disconnectHandler = {};
|
|
|
+
|
|
|
+ void handleConnect(void *arg, esp_event_base_t baseType, int32_t eventId, void *);
|
|
|
+
|
|
|
+ void handleDisconnect(void *arg, esp_event_base_t baseType, int32_t eventId, void *);
|
|
|
+
|
|
|
+ void initDhcp(const kbf::net::IP &ip, const kbf::net::IP &netmask);
|
|
|
+
|
|
|
+ void registerEventHandlers();
|
|
|
+
|
|
|
+ void unregisterEventHandlers();
|
|
|
+}
|
|
|
+
|
|
|
+using namespace kbf;
|
|
|
+using namespace kbf::wifi;
|
|
|
+
|
|
|
+const std::string &ap::ssid() { return ::ssid; }
|
|
|
+
|
|
|
+const std::string &ap::password() { return ::password; }
|
|
|
+
|
|
|
+void ap::start(std::string ssid, std::string password, net::IP ip, net::IP netmask) {
|
|
|
+ ESP_LOGI(TAG, "%s(%s, <omitted>, %s, %s)", __func__, ssid.c_str(), ip.str().c_str(), netmask.str().c_str());
|
|
|
+
|
|
|
+ if (internal::mode == Mode::AP || internal::mode == Mode::DUAL) throw exception::InvalidMode();
|
|
|
+ if (ssid.empty()) throw kbf::exception::InvalidArgument("no SSID");
|
|
|
+ if (password.length() < 8) throw kbf::exception::InvalidArgument("password.length() < 8");
|
|
|
+
|
|
|
+ internal::init();
|
|
|
+ interface = esp_netif_create_default_wifi_ap();
|
|
|
+ initDhcp(ip, netmask);
|
|
|
+ registerEventHandlers();
|
|
|
+
|
|
|
+ std::move(ssid.begin(), ssid.end(), ::ssid);
|
|
|
+ std::move(password.begin(), password.end(), ::password);
|
|
|
+
|
|
|
+ apConfig.ssid_len = ::ssid.length();
|
|
|
+ apConfig.max_connection = 5; // TODO use Kconfig
|
|
|
+ apConfig.authmode = WIFI_AUTH_WPA2_PSK; // TODO use AUTH_OPEN if no password is provided
|
|
|
+
|
|
|
+ wifi_config_t config = {.ap = apConfig};
|
|
|
+ CHECK(esp_wifi_set_config(WIFI_IF_AP, &config));
|
|
|
+
|
|
|
+ if (internal::mode == Mode::OFF) {
|
|
|
+ CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
|
|
|
+ CHECK(esp_wifi_start());
|
|
|
+ internal::mode = Mode::AP;
|
|
|
+ } else {
|
|
|
+ CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
|
|
|
+ internal::mode = Mode::DUAL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void ap::stop() {
|
|
|
+ ESP_LOGI(TAG, "%s()", __func__);
|
|
|
+
|
|
|
+ if (internal::mode != Mode::AP && internal::mode != Mode::DUAL) {
|
|
|
+ throw wifi::exception::InvalidMode();
|
|
|
+ }
|
|
|
+
|
|
|
+ esp_netif_destroy(interface);
|
|
|
+ unregisterEventHandlers();
|
|
|
+
|
|
|
+ if (internal::mode == Mode::DUAL) {
|
|
|
+ CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
|
|
+ internal::mode = Mode::STA;
|
|
|
+ } else {
|
|
|
+ CHECK(esp_wifi_stop());
|
|
|
+ internal::mode = Mode::OFF;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void initDhcp(const net::IP &ip, const net::IP &netmask) {
|
|
|
+ ESP_LOGI(TAG, "%s()", __func__);
|
|
|
+
|
|
|
+ if (dhcpInit) {
|
|
|
+ ESP_LOGI(TAG, "DHCP already initialized");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ esp_netif_ip_info_t ipInfo;
|
|
|
+ IP4_ADDR(&ipInfo.ip, ip[0], ip[1], ip[2], ip[3]);
|
|
|
+ IP4_ADDR(&ipInfo.gw, ip[0], ip[1], ip[2], ip[3]);
|
|
|
+ IP4_ADDR(&ipInfo.netmask, netmask[0], netmask[1], netmask[2], netmask[3]);
|
|
|
+
|
|
|
+ CHECK(esp_netif_dhcps_stop(interface));
|
|
|
+ CHECK(esp_netif_set_ip_info(interface, &ipInfo));
|
|
|
+ CHECK(esp_netif_dhcps_start(interface));
|
|
|
+
|
|
|
+ dhcpInit = true;
|
|
|
+}
|
|
|
+
|
|
|
+void registerEventHandlers() {
|
|
|
+ ESP_LOGI(TAG, "%s()", __func__);
|
|
|
+
|
|
|
+ CHECK(esp_event_handler_instance_register(
|
|
|
+ WIFI_EVENT, WIFI_EVENT_AP_STACONNECTED, &handleConnect, nullptr, &connectHandler
|
|
|
+ ));
|
|
|
+ CHECK(esp_event_handler_instance_register(
|
|
|
+ WIFI_EVENT, WIFI_EVENT_AP_STADISCONNECTED, &handleDisconnect, nullptr, &disconnectHandler
|
|
|
+ ));
|
|
|
+}
|
|
|
+
|
|
|
+void unregisterEventHandlers() {
|
|
|
+ ESP_LOGI(TAG, "%s()", __func__);
|
|
|
+
|
|
|
+ CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, WIFI_EVENT_AP_STACONNECTED, &connectHandler));
|
|
|
+ CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, WIFI_EVENT_AP_STADISCONNECTED, &disconnectHandler));
|
|
|
+ CHECK(esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_AP_STACONNECTED, &handleConnect));
|
|
|
+ CHECK(esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_AP_STADISCONNECTED, &handleDisconnect));
|
|
|
+}
|
|
|
+
|
|
|
+void handleConnect(void *, esp_event_base_t, int32_t, void *data) {
|
|
|
+ ESP_LOGI(TAG, "%s()", __func__);
|
|
|
+
|
|
|
+ if (ap::onConnect) {
|
|
|
+ auto sta = STA(*static_cast<wifi_event_ap_staconnected_t *>(data));
|
|
|
+ ap::onConnect(sta);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void handleDisconnect(void *, esp_event_base_t, int32_t, void *data) {
|
|
|
+ ESP_LOGI(TAG, "%s()", __func__);
|
|
|
+
|
|
|
+ if (ap::onDisconnect) {
|
|
|
+ auto sta = STA(*static_cast<wifi_event_ap_staconnected_t *>(data));
|
|
|
+ ap::onDisconnect(sta);
|
|
|
+ }
|
|
|
+}
|