diff --git a/main/common/constants.h b/main/common/constants.h index 62eb2b5..894b1a7 100644 --- a/main/common/constants.h +++ b/main/common/constants.h @@ -13,4 +13,5 @@ // #define DISPLAY_READY_BIT (1 << 1) #define TOUCH_CALIBRATED_BIT (1 << 2) -#define STORAGE_READY_BIT (1 << 3) \ No newline at end of file +#define STORAGE_READY_BIT (1 << 3) +#define NETWORK_READY_BIT (1 << 4) \ No newline at end of file diff --git a/main/network/http_handler.h b/main/network/http_handler.h new file mode 100644 index 0000000..1be7670 --- /dev/null +++ b/main/network/http_handler.h @@ -0,0 +1,55 @@ +#pragma once +#include +#include "esp_http_client.h" +#include "network/wifi_handler.h" + +// forward declare NetworkHandler to avoid circular include with network.h +class NetworkHandler; + +// default config values for esp_http_client_config_t +// disable Wmissing-field-initializers warning for these structs +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +static const inline esp_http_client_config_t DEFAULT_HTTP_CLIENT_CONFIG = { + .timeout_ms = 10000, +}; + +static const inline esp_http_client_config_t DEFAULT_HTTP_CLIENT_CONFIG_HTTPS = { + .transport_type = HTTP_TRANSPORT_OVER_SSL, + // + .use_global_ca_store = true, + .skip_cert_common_name_check = false, +}; +#pragma GCC diagnostic pop + +// esp http client wrapper with automatic initialization and cleanup +class HttpHandler { +public: + ~HttpHandler(); + + esp_err_t set_method(esp_http_client_method_t method); + esp_err_t set_header(const char* header, const char* value); + esp_err_t set_post_field(const char* field, size_t len); + // + esp_err_t perform_request(); + // buffer is allocated inside the method, caller must free it + void get_body( + char*& buffer, + int& total_len + ); + + + // only NetworkHandler can create HttpHandler instances + friend class NetworkHandler; + // disable copy constructor and assignment operator + HttpHandler(const HttpHandler&) = delete; + HttpHandler& operator=(const HttpHandler&) = delete; + +private: + // private constructor, only NetworkHandler can create instances + HttpHandler(const esp_http_client_config_t&& config, WifiHandler* wifiHandler); + + esp_http_client_handle_t client; + // backreference to WifiHandler to ensure WiFi is connected, DO NOT DELETE + WifiHandler* wifiHandler; +}; diff --git a/main/network/network.h b/main/network/network.h index e69de29..ba7eaac 100644 --- a/main/network/network.h +++ b/main/network/network.h @@ -0,0 +1,27 @@ +#pragma once +#include +#include "freertos/FreeRTOS.h" +#include "esp_system.h" +#include "network/wifi_handler.h" +#include "esp_http_client.h" + +// forward declare HttpHandler to avoid circular include with http_handler.h +class HttpHandler; + +class NetworkHandler { +public: + NetworkHandler( + WifiHandler&& wifiHandler + ); + ~NetworkHandler(); + + void init(EventGroupHandle_t system_event_group); + WifiHandler& get_wifi_handler(); + // factory method to create HttpHandler instances + std::unique_ptr get_http_handler(const esp_http_client_config_t&& config); + + +private: + WifiHandler wifiHandler; + bool initialized = false; +}; diff --git a/main/network/wifi_handler.h b/main/network/wifi_handler.h new file mode 100644 index 0000000..5614e36 --- /dev/null +++ b/main/network/wifi_handler.h @@ -0,0 +1,54 @@ +#pragma once +#include "io/io.h" +#include "esp_wifi.h" +#include "freertos/event_groups.h" + +#define WIFI_CONNECTED_BIT (1 << 0) + +class WifiHandler { +public: + WifiHandler( + // this handler is used to store/retrieve WiFi credentials + // should have a unique namespace for WiFi credentials + // it will be owned by WifiHandler and deleted in its destructor + KVStorageHandler* kvs + ); + ~WifiHandler(); + + // move semantics + WifiHandler(WifiHandler&& other) noexcept; + + void init(); + esp_err_t connect(const char* ssid, const char* password); + esp_err_t connect(const char* ssid); // connect using stored password + esp_err_t reconnect(); // reconnect to current SSID + void disconnect(); + EventBits_t wait_for_connection(TickType_t ticks_to_wait); + // returns list of available networks, caller is responsible for freeing the returned memory + // returns nullptr if scan failed + esp_err_t scan_networks( + wifi_ap_record_t*& ap_records, + uint16_t& ap_count + ); + + static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data); + +private: + // prevent copying + WifiHandler(const WifiHandler&) = delete; + WifiHandler& operator=(const WifiHandler&) = delete; + + char* build_password_key(const char* ssid); + void get_wifi_credentials(char*& ssid, char*& password); + + bool initialized = false; + KVStorageHandler* kvs = nullptr; + EventGroupHandle_t s_wifi_event_group = 0; + SemaphoreHandle_t scan_mutex = nullptr; + SemaphoreHandle_t connection_mutex = nullptr; + // current connected / preferred SSID + char* current_ssid = nullptr; + // prevent auto-reconnect on expected disconnection, e.g. when user calls disconnect() + // should be reset to false after connect() + bool expect_disconnected = false; +};