Refactor NVS and WiFi handlers for improved memory management and logging
- Updated KVStorageHandler interface to use std::string instead of char* for key-value operations. - Enhanced NVSStorageHandler to utilize ESP_LOG for error and info messages instead of printf. - Refactored WifiHandler to manage WiFi credentials using JSON format for better structure and storage. - Replaced raw pointers with std::unique_ptr in WifiHandler and NetworkHandler for automatic memory management. - Removed unused TouchHandler and EInkTouchHandler classes to clean up the codebase. - Adjusted CMakeLists.txt to remove unnecessary include directories. - Updated lv_conf.h to enable FreeRTOS and gesture recognition features.
This commit is contained in:
@@ -3,4 +3,4 @@ file(GLOB SRCS "main.cpp" "*.cpp" "*.c" "**/*.cpp" "**/*.c")
|
|||||||
|
|
||||||
idf_component_register(SRCS ${SRCS}
|
idf_component_register(SRCS ${SRCS}
|
||||||
PRIV_REQUIRES ${requires}
|
PRIV_REQUIRES ${requires}
|
||||||
INCLUDE_DIRS "." "display" "touch" "network" "ui" "io" "common")
|
INCLUDE_DIRS "." "display" "network" "ui" "io" "common")
|
||||||
|
|||||||
15
main/io/io.h
15
main/io/io.h
@@ -3,8 +3,8 @@
|
|||||||
#include "freertos/event_groups.h"
|
#include "freertos/event_groups.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
typedef bool(*FilterFunc)(const char* const& key);
|
typedef bool(*FilterFunc)(const std::string& key);
|
||||||
typedef void (*KeyValueProcessor)(void* arg, const char* const& key, const char* const& value);
|
typedef void (*KeyValueProcessor)(void* arg, const std::string& key, const std::string& value);
|
||||||
|
|
||||||
class KVStorageHandler {
|
class KVStorageHandler {
|
||||||
public:
|
public:
|
||||||
@@ -13,15 +13,14 @@ public:
|
|||||||
virtual void init(const EventGroupHandle_t& system_event_group) = 0;
|
virtual void init(const EventGroupHandle_t& system_event_group) = 0;
|
||||||
|
|
||||||
// Store a key-value pair
|
// Store a key-value pair
|
||||||
virtual void put(const char* const& key, const char* const& value) = 0;
|
virtual void put(const std::string& key, const std::string& value) = 0;
|
||||||
|
|
||||||
// Retrieve a value by key, returns nullptr if key not found
|
// Retrieve a value by key, returns empty string if key not found
|
||||||
// The caller is responsible for freeing the returned memory
|
virtual std::string get(const std::string& key) const = 0;
|
||||||
virtual std::unique_ptr<char[]> get(const char* const& key) const = 0;
|
|
||||||
virtual esp_err_t process_all(KeyValueProcessor processor, void* arg) const = 0;
|
virtual esp_err_t process_all(KeyValueProcessor processor, void* arg) const = 0;
|
||||||
virtual esp_err_t process_filtered(const char* const& key_prefix, KeyValueProcessor processor, void* arg) const = 0;
|
virtual esp_err_t process_filtered(const std::string& key_prefix, KeyValueProcessor processor, void* arg) const = 0;
|
||||||
virtual esp_err_t process_filtered(FilterFunc filter_func, KeyValueProcessor processor, void* arg) const = 0;
|
virtual esp_err_t process_filtered(FilterFunc filter_func, KeyValueProcessor processor, void* arg) const = 0;
|
||||||
|
|
||||||
// Delete a key-value pair
|
// Delete a key-value pair
|
||||||
virtual void remove(const char* const& key) = 0;
|
virtual void remove(const std::string& key) = 0;
|
||||||
};
|
};
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
#include "io/nvs_handler.h"
|
#include "io/nvs_handler.h"
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
#define TAG "NVSStorageHandler"
|
||||||
|
|
||||||
NVSStorageHandler::NVSStorageHandler(
|
NVSStorageHandler::NVSStorageHandler(
|
||||||
const char* name_space
|
const char* name_space
|
||||||
@@ -24,49 +27,51 @@ void NVSStorageHandler::init(const EventGroupHandle_t& system_event_group) {
|
|||||||
|
|
||||||
err = nvs_open(this->name_space, NVS_READWRITE, &this->nvsHandle);
|
err = nvs_open(this->name_space, NVS_READWRITE, &this->nvsHandle);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Error (%s) opening NVS handle!", esp_err_to_name(err));
|
||||||
} else {
|
} else {
|
||||||
|
if (system_event_group != nullptr) {
|
||||||
xEventGroupSetBits(system_event_group, STORAGE_READY_BIT);
|
xEventGroupSetBits(system_event_group, STORAGE_READY_BIT);
|
||||||
printf("NVS Storage initialized.\n");
|
}
|
||||||
|
ESP_LOGI(TAG, "NVS Storage initialized.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NVSStorageHandler::put(const char* const& key, const char* const& value) {
|
void NVSStorageHandler::put(const std::string& key, const std::string& value) {
|
||||||
if (this->nvsHandle == 0) {
|
if (this->nvsHandle == 0) {
|
||||||
printf("NVS handle is not initialized.\n");
|
ESP_LOGE(TAG, "NVS handle is not initialized.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t err = nvs_set_str(this->nvsHandle, key, value);
|
esp_err_t err = nvs_set_str(this->nvsHandle, key.c_str(), value.c_str());
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
printf("Error (%s) setting key-value pair in NVS!\n", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Error (%s) setting key-value pair in NVS!", esp_err_to_name(err));
|
||||||
} else {
|
} else {
|
||||||
nvs_commit(this->nvsHandle);
|
nvs_commit(this->nvsHandle);
|
||||||
printf("Key-value pair (%s, %s) stored in NVS.\n", key, value);
|
ESP_LOGI(TAG, "Key-value pair (%s, %s) stored in NVS.", key.c_str(), value.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<char[]> NVSStorageHandler::get(const char* const& key) const {
|
std::string NVSStorageHandler::get(const std::string& key) const {
|
||||||
if (this->nvsHandle == 0) {
|
if (this->nvsHandle == 0) {
|
||||||
printf("NVS handle is not initialized.\n");
|
ESP_LOGE(TAG, "NVS handle is not initialized.");
|
||||||
return nullptr;
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t required_size = 0;
|
size_t required_size = 0;
|
||||||
esp_err_t err = nvs_get_str(this->nvsHandle, key, nullptr, &required_size);
|
esp_err_t err = nvs_get_str(this->nvsHandle, key.c_str(), nullptr, &required_size);
|
||||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||||
printf("Key %s not found in NVS.\n", key);
|
ESP_LOGW(TAG, "Key %s not found in NVS.", key.c_str());
|
||||||
return nullptr;
|
return "";
|
||||||
} else if (err != ESP_OK) {
|
} else if (err != ESP_OK) {
|
||||||
printf("Error (%s) getting size for key %s from NVS!\n", esp_err_to_name(err), key);
|
ESP_LOGE(TAG, "Error (%s) getting size for key %s from NVS!", esp_err_to_name(err), key.c_str());
|
||||||
return nullptr;
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<char[]> value(new char[required_size]);
|
std::string value;
|
||||||
err = nvs_get_str(this->nvsHandle, key, value.get(), &required_size);
|
err = nvs_get_str(this->nvsHandle, key.c_str(), value.data(), &required_size);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
printf("Error (%s) getting value for key %s from NVS!\n", esp_err_to_name(err), key);
|
ESP_LOGE(TAG, "Error (%s) getting value for key %s from NVS!", esp_err_to_name(err), key.c_str());
|
||||||
return nullptr;
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@@ -76,7 +81,7 @@ NVSIteratorGuard NVSStorageHandler::create_iterator() const {
|
|||||||
nvs_iterator_t it = nullptr;
|
nvs_iterator_t it = nullptr;
|
||||||
esp_err_t err = nvs_entry_find(NVS_DEFAULT_PART_NAME, this->name_space, NVS_TYPE_ANY, &it);
|
esp_err_t err = nvs_entry_find(NVS_DEFAULT_PART_NAME, this->name_space, NVS_TYPE_ANY, &it);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
printf("Error (%s) creating NVS iterator!\n", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Error (%s) creating NVS iterator!", esp_err_to_name(err));
|
||||||
return NVSIteratorGuard(nullptr, err);
|
return NVSIteratorGuard(nullptr, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,22 +99,23 @@ esp_err_t NVSStorageHandler::process_all(KeyValueProcessor processor, void* arg)
|
|||||||
nvs_entry_info_t info;
|
nvs_entry_info_t info;
|
||||||
esp_err_t err = nvs_entry_info(it, &info);
|
esp_err_t err = nvs_entry_info(it, &info);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
printf("Error (%s) getting NVS entry info!\n", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Error (%s) getting NVS entry info!", esp_err_to_name(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
nvs_handle_t temp_handle;
|
nvs_handle_t temp_handle;
|
||||||
err = nvs_open(this->name_space, NVS_READONLY, &temp_handle);
|
err = nvs_open(this->name_space, NVS_READONLY, &temp_handle);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
printf("Error (%s) opening NVS handle for reading!\n", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Error (%s) opening NVS handle for reading!", esp_err_to_name(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// call the processor with the key and value
|
// call the processor with the key and value
|
||||||
processor(arg, info.key, this->get(info.key).get());
|
std::string key_str = info.key;
|
||||||
|
processor(arg, key_str, this->get(key_str));
|
||||||
}
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
esp_err_t NVSStorageHandler::process_filtered(const char* const& key_prefix, KeyValueProcessor processor, void* arg) const {
|
esp_err_t NVSStorageHandler::process_filtered(const std::string& key_prefix, KeyValueProcessor processor, void* arg) const {
|
||||||
NVSIteratorGuard iterator_guard = this->create_iterator();
|
NVSIteratorGuard iterator_guard = this->create_iterator();
|
||||||
if (!iterator_guard.is_valid()) {
|
if (!iterator_guard.is_valid()) {
|
||||||
return iterator_guard.get_error();
|
return iterator_guard.get_error();
|
||||||
@@ -120,19 +126,19 @@ esp_err_t NVSStorageHandler::process_filtered(const char* const& key_prefix, Key
|
|||||||
nvs_entry_info_t info;
|
nvs_entry_info_t info;
|
||||||
esp_err_t err = nvs_entry_info(it, &info);
|
esp_err_t err = nvs_entry_info(it, &info);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
printf("Error (%s) getting NVS entry info!\n", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Error (%s) getting NVS entry info!", esp_err_to_name(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
// check if the key matches the prefix
|
// check if the key matches the prefix
|
||||||
if (strncmp(info.key, key_prefix, strlen(key_prefix)) == 0) {
|
if (strncmp(info.key, key_prefix.c_str(), key_prefix.length()) == 0) {
|
||||||
nvs_handle_t temp_handle;
|
nvs_handle_t temp_handle;
|
||||||
err = nvs_open(this->name_space, NVS_READONLY, &temp_handle);
|
err = nvs_open(this->name_space, NVS_READONLY, &temp_handle);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
printf("Error (%s) opening NVS handle for reading!\n", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Error (%s) opening NVS handle for reading!", esp_err_to_name(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
// call the processor with the key and value
|
// call the processor with the key and value
|
||||||
processor(arg, info.key, this->get(info.key).get());
|
processor(arg, std::string(info.key), this->get(std::string(info.key)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
@@ -149,35 +155,36 @@ esp_err_t NVSStorageHandler::process_filtered(FilterFunc filter_func, KeyValuePr
|
|||||||
nvs_entry_info_t info;
|
nvs_entry_info_t info;
|
||||||
esp_err_t err = nvs_entry_info(it, &info);
|
esp_err_t err = nvs_entry_info(it, &info);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
printf("Error (%s) getting NVS entry info!\n", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Error (%s) getting NVS entry info!", esp_err_to_name(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
// check if the key matches the filter function
|
// check if the key matches the filter function
|
||||||
if (filter_func(info.key)) {
|
std::string key_str(info.key);
|
||||||
|
if (filter_func(key_str)) {
|
||||||
nvs_handle_t temp_handle;
|
nvs_handle_t temp_handle;
|
||||||
err = nvs_open(this->name_space, NVS_READONLY, &temp_handle);
|
err = nvs_open(this->name_space, NVS_READONLY, &temp_handle);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
printf("Error (%s) opening NVS handle for reading!\n", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Error (%s) opening NVS handle for reading!", esp_err_to_name(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
// call the processor with the key and value
|
// call the processor with the key and value
|
||||||
processor(arg, info.key, this->get(info.key).get());
|
processor(arg, key_str, this->get(key_str));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NVSStorageHandler::remove(const char* const& key) {
|
void NVSStorageHandler::remove(const std::string& key) {
|
||||||
if (this->nvsHandle == 0) {
|
if (this->nvsHandle == 0) {
|
||||||
printf("NVS handle is not initialized.\n");
|
ESP_LOGE(TAG, "NVS handle is not initialized.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t err = nvs_erase_key(this->nvsHandle, key);
|
esp_err_t err = nvs_erase_key(this->nvsHandle, key.c_str());
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
printf("Error (%s) deleting key %s from NVS!\n", esp_err_to_name(err), key);
|
ESP_LOGE(TAG, "Error (%s) deleting key %s from NVS!", esp_err_to_name(err), key.c_str());
|
||||||
} else {
|
} else {
|
||||||
nvs_commit(this->nvsHandle);
|
nvs_commit(this->nvsHandle);
|
||||||
printf("Key %s deleted from NVS.\n", key);
|
ESP_LOGI(TAG, "Key %s deleted from NVS.", key.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,14 +53,14 @@ public:
|
|||||||
|
|
||||||
void init(const EventGroupHandle_t& system_event_group) override;
|
void init(const EventGroupHandle_t& system_event_group) override;
|
||||||
|
|
||||||
void put(const char* const& key, const char* const& value) override;
|
void put(const std::string& key, const std::string& value) override;
|
||||||
|
|
||||||
std::unique_ptr<char[]> get(const char* const& key) const override;
|
std::string get(const std::string& key) const override;
|
||||||
esp_err_t process_all(KeyValueProcessor processor, void* arg) const override;
|
esp_err_t process_all(KeyValueProcessor processor, void* arg) const override;
|
||||||
esp_err_t process_filtered(const char* const& key_prefix, KeyValueProcessor processor, void* arg) const override;
|
esp_err_t process_filtered(const std::string& key_prefix, KeyValueProcessor processor, void* arg) const override;
|
||||||
esp_err_t process_filtered(FilterFunc filter_func, KeyValueProcessor processor, void* arg) const override;
|
esp_err_t process_filtered(FilterFunc filter_func, KeyValueProcessor processor, void* arg) const override;
|
||||||
|
|
||||||
void remove(const char* const& key) override;
|
void remove(const std::string& key) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NVSIteratorGuard create_iterator() const;
|
NVSIteratorGuard create_iterator() const;
|
||||||
|
|||||||
@@ -109,7 +109,8 @@
|
|||||||
* - LV_OS_MQX
|
* - LV_OS_MQX
|
||||||
* - LV_OS_SDL2
|
* - LV_OS_SDL2
|
||||||
* - LV_OS_CUSTOM */
|
* - LV_OS_CUSTOM */
|
||||||
#define LV_USE_OS LV_OS_NONE
|
// #define LV_USE_OS LV_OS_NONE
|
||||||
|
#define LV_USE_OS LV_OS_FREERTOS
|
||||||
|
|
||||||
#if LV_USE_OS == LV_OS_CUSTOM
|
#if LV_USE_OS == LV_OS_CUSTOM
|
||||||
#define LV_OS_CUSTOM_INCLUDE <stdint.h>
|
#define LV_OS_CUSTOM_INCLUDE <stdint.h>
|
||||||
@@ -574,7 +575,8 @@
|
|||||||
|
|
||||||
/* Enable the multi-touch gesture recognition feature */
|
/* Enable the multi-touch gesture recognition feature */
|
||||||
/* Gesture recognition requires the use of floats */
|
/* Gesture recognition requires the use of floats */
|
||||||
#define LV_USE_GESTURE_RECOGNITION 0
|
// #define LV_USE_GESTURE_RECOGNITION 0
|
||||||
|
#define LV_USE_GESTURE_RECOGNITION 1
|
||||||
|
|
||||||
/*=====================
|
/*=====================
|
||||||
* COMPILER SETTINGS
|
* COMPILER SETTINGS
|
||||||
@@ -617,7 +619,8 @@
|
|||||||
#define LV_ATTRIBUTE_EXTERN_DATA
|
#define LV_ATTRIBUTE_EXTERN_DATA
|
||||||
|
|
||||||
/** Use `float` as `lv_value_precise_t` */
|
/** Use `float` as `lv_value_precise_t` */
|
||||||
#define LV_USE_FLOAT 0
|
// #define LV_USE_FLOAT 0
|
||||||
|
#define LV_USE_FLOAT 1
|
||||||
|
|
||||||
/** Enable matrix support
|
/** Enable matrix support
|
||||||
* - Requires `LV_USE_FLOAT = 1` */
|
* - Requires `LV_USE_FLOAT = 1` */
|
||||||
@@ -1189,7 +1192,8 @@
|
|||||||
|
|
||||||
/** 1: Enable Pinyin input method
|
/** 1: Enable Pinyin input method
|
||||||
* - Requires: lv_keyboard */
|
* - Requires: lv_keyboard */
|
||||||
#define LV_USE_IME_PINYIN 0
|
// #define LV_USE_IME_PINYIN 0
|
||||||
|
#define LV_USE_IME_PINYIN 1
|
||||||
#if LV_USE_IME_PINYIN
|
#if LV_USE_IME_PINYIN
|
||||||
/** 1: Use default thesaurus.
|
/** 1: Use default thesaurus.
|
||||||
* @note If you do not use the default thesaurus, be sure to use `lv_ime_pinyin` after setting the thesaurus. */
|
* @note If you do not use the default thesaurus, be sure to use `lv_ime_pinyin` after setting the thesaurus. */
|
||||||
@@ -1436,10 +1440,12 @@
|
|||||||
*======================*/
|
*======================*/
|
||||||
|
|
||||||
/** Enable examples to be built with the library. */
|
/** Enable examples to be built with the library. */
|
||||||
#define LV_BUILD_EXAMPLES 1
|
// #define LV_BUILD_EXAMPLES 1
|
||||||
|
#define LV_BUILD_EXAMPLES 0
|
||||||
|
|
||||||
/** Build the demos */
|
/** Build the demos */
|
||||||
#define LV_BUILD_DEMOS 1
|
// #define LV_BUILD_DEMOS 1
|
||||||
|
#define LV_BUILD_DEMOS 0
|
||||||
|
|
||||||
/*===================
|
/*===================
|
||||||
* DEMO USAGE
|
* DEMO USAGE
|
||||||
|
|||||||
@@ -1,10 +1,3 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: CC0-1.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@@ -16,18 +9,19 @@
|
|||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
#include "common/constants.h"
|
#include "common/constants.h"
|
||||||
#include "common/queue_defs.h"
|
#include "common/queue_defs.h"
|
||||||
#include "io/nvs_handler.h"
|
#include "io/nvs_handler.h"
|
||||||
#include "info/info.h"
|
#include "info/info.h"
|
||||||
#include "display/display.h"
|
#include "display/display.h"
|
||||||
#include "touch/touch.h"
|
|
||||||
#include <tick/lv_tick.h>
|
#include <tick/lv_tick.h>
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
|
||||||
|
// nvs storage namespaces, 15 characters max
|
||||||
#define DEFAULT_STORAGE_NAMESPACE "storage"
|
#define DEFAULT_STORAGE_NAMESPACE "storage"
|
||||||
#define WIFI_CREDENTIALS_STORAGE_NAMESPACE "wifi_credentials"
|
#define WIFI_CREDENTIALS_STORAGE_NAMESPACE "wifi_cred"
|
||||||
|
#define TAG "Main"
|
||||||
|
|
||||||
extern "C" void app_main(void);
|
extern "C" void app_main(void);
|
||||||
|
|
||||||
@@ -50,7 +44,7 @@ void app_main(void) {
|
|||||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||||
return esp_restart();
|
return esp_restart();
|
||||||
}
|
}
|
||||||
printf("Queues initialized.\n");
|
ESP_LOGI(TAG, "Queues initialized.\n");
|
||||||
SemaphoreHandle_t lvgl_mutex = xSemaphoreCreateMutex();
|
SemaphoreHandle_t lvgl_mutex = xSemaphoreCreateMutex();
|
||||||
if (lvgl_mutex == NULL) {
|
if (lvgl_mutex == NULL) {
|
||||||
ESP_LOGE("Main", "Failed to create LVGL mutex");
|
ESP_LOGE("Main", "Failed to create LVGL mutex");
|
||||||
@@ -58,28 +52,33 @@ void app_main(void) {
|
|||||||
return esp_restart();
|
return esp_restart();
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
WifiHandler wifi_handler(
|
|
||||||
new NVSStorageHandler(WIFI_CREDENTIALS_STORAGE_NAMESPACE)
|
|
||||||
);
|
|
||||||
NetworkHandler* network_handler = new NetworkHandler(std::move(wifi_handler));
|
|
||||||
KVStorageHandler* kv_storage_handler = new NVSStorageHandler(
|
KVStorageHandler* kv_storage_handler = new NVSStorageHandler(
|
||||||
DEFAULT_STORAGE_NAMESPACE
|
DEFAULT_STORAGE_NAMESPACE
|
||||||
);
|
);
|
||||||
DisplayHandler* display_handler = new EInkDisplayHandler(touch_event_queue, lvgl_mutex);
|
|
||||||
TouchHandler* touch_handler = new EInkTouchHandler(touch_event_queue);
|
auto wifi_handler = std::make_unique<WifiHandler>(
|
||||||
|
std::unique_ptr<KVStorageHandler>(new NVSStorageHandler(WIFI_CREDENTIALS_STORAGE_NAMESPACE))
|
||||||
|
);
|
||||||
|
NetworkHandler* network_handler = new NetworkHandler(std::move(wifi_handler));
|
||||||
|
// DisplayHandler* display_handler = new EInkDisplayHandler(touch_event_queue, lvgl_mutex);
|
||||||
//
|
//
|
||||||
network_handler->init(system_event_group);
|
|
||||||
kv_storage_handler->init(system_event_group);
|
kv_storage_handler->init(system_event_group);
|
||||||
display_handler->init(system_event_group);
|
network_handler->init(system_event_group);
|
||||||
touch_handler->init(system_event_group);
|
|
||||||
|
|
||||||
|
// display_handler->init(system_event_group);
|
||||||
//
|
//
|
||||||
// LVGL tick timer
|
// LVGL tick timer
|
||||||
auto lvgl_tick_timer_callback = [](TimerHandle_t xTimer) {
|
auto lvgl_tick_timer_callback = [](TimerHandle_t xTimer) {
|
||||||
lv_tick_inc(5);
|
lv_tick_inc(5);
|
||||||
};
|
};
|
||||||
|
TickType_t lvgl_tick_period = pdMS_TO_TICKS(5);
|
||||||
|
if (lvgl_tick_period == 0) {
|
||||||
|
lvgl_tick_period = 1; // ensure at least 1 tick to avoid FreeRTOS assert
|
||||||
|
}
|
||||||
TimerHandle_t lvgl_tick_timer = xTimerCreate(
|
TimerHandle_t lvgl_tick_timer = xTimerCreate(
|
||||||
"lvgl_tick_timer",
|
"lvgl_tick_timer",
|
||||||
pdMS_TO_TICKS(5),
|
lvgl_tick_period,
|
||||||
pdTRUE,
|
pdTRUE,
|
||||||
NULL,
|
NULL,
|
||||||
lvgl_tick_timer_callback
|
lvgl_tick_timer_callback
|
||||||
@@ -92,20 +91,21 @@ void app_main(void) {
|
|||||||
xTimerStart(lvgl_tick_timer, 0);
|
xTimerStart(lvgl_tick_timer, 0);
|
||||||
|
|
||||||
//
|
//
|
||||||
printf("Waiting for system to be ready...\n");
|
ESP_LOGI(TAG, "Waiting for system to be ready...\n");
|
||||||
xEventGroupWaitBits(
|
xEventGroupWaitBits(
|
||||||
system_event_group,
|
system_event_group,
|
||||||
DISPLAY_READY_BIT | TOUCH_CALIBRATED_BIT | STORAGE_READY_BIT | NETWORK_READY_BIT,
|
// DISPLAY_READY_BIT | TOUCH_CALIBRATED_BIT |
|
||||||
|
STORAGE_READY_BIT | NETWORK_READY_BIT,
|
||||||
// do not clear on exit, require explicit reset
|
// do not clear on exit, require explicit reset
|
||||||
pdFALSE,
|
pdFALSE,
|
||||||
pdTRUE,
|
pdTRUE,
|
||||||
portMAX_DELAY
|
portMAX_DELAY
|
||||||
);
|
);
|
||||||
printf("System is ready. Starting main application...\n");
|
ESP_LOGI(TAG, "System is ready. Starting main application...\n");
|
||||||
// starting event loops
|
// starting event loops
|
||||||
display_handler->start_event_loop();
|
// display_handler->start_event_loop();
|
||||||
touch_handler->start_event_loop();
|
|
||||||
// wait for shutdown signal
|
// wait for shutdown signal
|
||||||
|
ESP_LOGI(TAG, "Waiting for shutdown signal...\n");
|
||||||
EventBits_t bits = xEventGroupWaitBits(
|
EventBits_t bits = xEventGroupWaitBits(
|
||||||
system_lifecycle_event_group,
|
system_lifecycle_event_group,
|
||||||
SYSTEM_SHUTDOWN_BIT | SYSTEM_RESTART_BIT,
|
SYSTEM_SHUTDOWN_BIT | SYSTEM_RESTART_BIT,
|
||||||
@@ -114,27 +114,26 @@ void app_main(void) {
|
|||||||
pdFALSE,
|
pdFALSE,
|
||||||
portMAX_DELAY
|
portMAX_DELAY
|
||||||
);
|
);
|
||||||
printf("Shutdown signal received. Cleaning up...\n");
|
ESP_LOGI(TAG, "Shutdown signal received. Cleaning up...\n");
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
shutdown_display_handlerFunc shutdown_display_handler = display_handler->get_shutdown_display_handler();
|
// shutdown_display_handlerFunc shutdown_display_handler = display_handler->get_shutdown_display_handler();
|
||||||
restart_display_handlerFunc restart_display_handler = display_handler->get_restart_display_handler();
|
// restart_display_handlerFunc restart_display_handler = display_handler->get_restart_display_handler();
|
||||||
delete display_handler;
|
// delete display_handler;
|
||||||
delete touch_handler;
|
|
||||||
vSemaphoreDelete(lvgl_mutex);
|
vSemaphoreDelete(lvgl_mutex);
|
||||||
vEventGroupDelete(system_event_group);
|
vEventGroupDelete(system_event_group);
|
||||||
vQueueDelete(touch_event_queue);
|
vQueueDelete(touch_event_queue);
|
||||||
printf("Cleanup complete.\n");
|
ESP_LOGI(TAG, "Cleanup complete.\n");
|
||||||
|
|
||||||
// handle shutdown or restart
|
// handle shutdown or restart
|
||||||
if (bits & SYSTEM_SHUTDOWN_BIT) {
|
if (bits & SYSTEM_SHUTDOWN_BIT) {
|
||||||
if (shutdown_display_handler != nullptr) {
|
// if (shutdown_display_handler != nullptr) {
|
||||||
printf("Calling display shutdown handler...\n");
|
// ESP_LOGI(TAG, "Calling display shutdown handler...\n");
|
||||||
shutdown_display_handler();
|
// shutdown_display_handler();
|
||||||
} else {
|
// } else {
|
||||||
printf("No display shutdown handler to call.\n");
|
// ESP_LOGI(TAG, "No display shutdown handler to call.\n");
|
||||||
}
|
// }
|
||||||
printf("System is shutting down.\n");
|
ESP_LOGI(TAG, "System is shutting down.\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
// wait for start bit to be set again if future restart is desired, else expect manual power cycle
|
// wait for start bit to be set again if future restart is desired, else expect manual power cycle
|
||||||
EventBits_t bits = xEventGroupWaitBits(
|
EventBits_t bits = xEventGroupWaitBits(
|
||||||
@@ -145,24 +144,24 @@ void app_main(void) {
|
|||||||
portMAX_DELAY
|
portMAX_DELAY
|
||||||
);
|
);
|
||||||
if (bits & SYSTEM_START_BIT) {
|
if (bits & SYSTEM_START_BIT) {
|
||||||
printf("SYSTEM_START_BIT received, restarting system.\n");
|
ESP_LOGI(TAG, "SYSTEM_START_BIT received, restarting system.\n");
|
||||||
} else {
|
} else {
|
||||||
printf("No restart signal received, waiting for manual power cycle.\n");
|
ESP_LOGW(TAG, "No restart signal received, waiting for manual power cycle.\n");
|
||||||
while (true) {
|
while (true) {
|
||||||
vTaskDelay(portMAX_DELAY);
|
vTaskDelay(portMAX_DELAY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (bits & SYSTEM_RESTART_BIT) {
|
} else if (bits & SYSTEM_RESTART_BIT) {
|
||||||
if (restart_display_handler != nullptr) {
|
// if (restart_display_handler != nullptr) {
|
||||||
printf("Calling display restart handler...\n");
|
// ESP_LOGI(TAG, "Calling display restart handler...\n");
|
||||||
restart_display_handler();
|
// restart_display_handler();
|
||||||
} else {
|
// } else {
|
||||||
printf("No display restart handler to call.\n");
|
// ESP_LOGI(TAG, "No display restart handler to call.\n");
|
||||||
}
|
// }
|
||||||
printf("System is restarting.\n");
|
ESP_LOGI(TAG, "System is restarting.\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
} else {
|
} else {
|
||||||
printf("Unknown shutdown signal received. Restarting by default.\n");
|
ESP_LOGW(TAG, "Unknown shutdown signal received. Restarting by default.\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "common/constants.h"
|
#include "common/constants.h"
|
||||||
|
|
||||||
NetworkHandler::NetworkHandler(
|
NetworkHandler::NetworkHandler(
|
||||||
WifiHandler&& wifiHandler
|
std::unique_ptr<WifiHandler> wifiHandler
|
||||||
) : wifiHandler(std::move(wifiHandler)) { }
|
) : wifiHandler(std::move(wifiHandler)) { }
|
||||||
|
|
||||||
NetworkHandler::~NetworkHandler() { }
|
NetworkHandler::~NetworkHandler() { }
|
||||||
@@ -14,7 +14,7 @@ void NetworkHandler::init(EventGroupHandle_t system_event_group) {
|
|||||||
ESP_LOGW("NetworkHandler", "Already initialized, skipping");
|
ESP_LOGW("NetworkHandler", "Already initialized, skipping");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->wifiHandler.init();
|
this->wifiHandler->init();
|
||||||
this->initialized = true;
|
this->initialized = true;
|
||||||
xEventGroupSetBits(
|
xEventGroupSetBits(
|
||||||
system_event_group,
|
system_event_group,
|
||||||
@@ -23,10 +23,10 @@ void NetworkHandler::init(EventGroupHandle_t system_event_group) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WifiHandler& NetworkHandler::get_wifi_handler() {
|
WifiHandler& NetworkHandler::get_wifi_handler() {
|
||||||
return this->wifiHandler;
|
return *this->wifiHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<HttpHandler> NetworkHandler::get_http_handler(const esp_http_client_config_t&& config) {
|
std::unique_ptr<HttpHandler> NetworkHandler::get_http_handler(const esp_http_client_config_t&& config) {
|
||||||
return std::unique_ptr<HttpHandler>(new HttpHandler(std::move(config), &this->wifiHandler));
|
return std::unique_ptr<HttpHandler>(new HttpHandler(std::move(config), this->wifiHandler.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class HttpHandler;
|
|||||||
class NetworkHandler {
|
class NetworkHandler {
|
||||||
public:
|
public:
|
||||||
NetworkHandler(
|
NetworkHandler(
|
||||||
WifiHandler&& wifiHandler
|
std::unique_ptr<WifiHandler> wifiHandler
|
||||||
);
|
);
|
||||||
~NetworkHandler();
|
~NetworkHandler();
|
||||||
|
|
||||||
@@ -22,6 +22,6 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WifiHandler wifiHandler;
|
std::unique_ptr<WifiHandler> wifiHandler;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,38 +6,39 @@
|
|||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
#include "common/semaphore_guard.h"
|
#include "common/semaphore_guard.h"
|
||||||
|
#include "cJSON.h"
|
||||||
|
|
||||||
static const char* TAG = "WifiHandler";
|
static const char* TAG = "WifiHandler";
|
||||||
static const char* WIFI_SSID_KEY = "wifi_ssid";
|
static const char* WIFI_SSID_KEY = "ssid";
|
||||||
static const char* WIFI_PASSWORD_KEY = "wifi_password";
|
static const char* WIFI_PASSWORD_STORE_KEY = "psw";
|
||||||
|
|
||||||
WifiHandler::WifiHandler(
|
WifiHandler::WifiHandler(
|
||||||
// this handler is used to store/retrieve WiFi credentials
|
// this handler is used to store/retrieve WiFi credentials
|
||||||
// should have a unique namespace for WiFi credentials
|
// should have a unique namespace for WiFi credentials
|
||||||
// it will be owned by WifiHandler and deleted in its destructor
|
// it will be owned by WifiHandler and deleted in its destructor
|
||||||
KVStorageHandler* kvs
|
std::unique_ptr<KVStorageHandler> kvs
|
||||||
) : kvs(kvs) {
|
) : kvs(std::move(kvs)) {
|
||||||
this->s_wifi_event_group = xEventGroupCreate();
|
this->s_wifi_event_group = xEventGroupCreate();
|
||||||
|
if (!this->s_wifi_event_group) {
|
||||||
|
ESP_LOGE(TAG, "Failed to create WiFi event group");
|
||||||
|
}
|
||||||
this->scan_mutex = xSemaphoreCreateMutex();
|
this->scan_mutex = xSemaphoreCreateMutex();
|
||||||
|
if (!this->scan_mutex) {
|
||||||
|
ESP_LOGE(TAG, "Failed to create scan mutex");
|
||||||
|
}
|
||||||
this->connection_mutex = xSemaphoreCreateMutex();
|
this->connection_mutex = xSemaphoreCreateMutex();
|
||||||
}
|
if (!this->connection_mutex) {
|
||||||
|
ESP_LOGE(TAG, "Failed to create connection mutex");
|
||||||
// Move constructor: transfer ownership of resources
|
}
|
||||||
WifiHandler::WifiHandler(WifiHandler&& other) noexcept
|
this->credential_mutex = xSemaphoreCreateMutex();
|
||||||
: initialized(other.initialized),
|
if (!this->credential_mutex) {
|
||||||
kvs(other.kvs),
|
ESP_LOGE(TAG, "Failed to create credential mutex");
|
||||||
s_wifi_event_group(other.s_wifi_event_group),
|
}
|
||||||
scan_mutex(other.scan_mutex),
|
if (this->kvs == nullptr) {
|
||||||
connection_mutex(other.connection_mutex),
|
ESP_LOGW(TAG, "KVStorageHandler is null, WiFi credentials will not be stored");
|
||||||
current_ssid(other.current_ssid),
|
} else {
|
||||||
expect_disconnected(other.expect_disconnected) {
|
this->kvs->init(nullptr);
|
||||||
other.kvs = nullptr;
|
}
|
||||||
other.initialized = false;
|
|
||||||
other.s_wifi_event_group = 0;
|
|
||||||
other.scan_mutex = nullptr;
|
|
||||||
other.connection_mutex = nullptr;
|
|
||||||
other.current_ssid = nullptr;
|
|
||||||
other.expect_disconnected = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WifiHandler::~WifiHandler() {
|
WifiHandler::~WifiHandler() {
|
||||||
@@ -46,20 +47,23 @@ WifiHandler::~WifiHandler() {
|
|||||||
// Check if it should be called
|
// Check if it should be called
|
||||||
esp_wifi_deinit();
|
esp_wifi_deinit();
|
||||||
vEventGroupDelete(this->s_wifi_event_group);
|
vEventGroupDelete(this->s_wifi_event_group);
|
||||||
if (this->current_ssid) {
|
if (!this->current_ssid.empty()) {
|
||||||
delete[] this->current_ssid;
|
this->current_ssid.clear();
|
||||||
}
|
}
|
||||||
vSemaphoreDelete(this->scan_mutex);
|
vSemaphoreDelete(this->scan_mutex);
|
||||||
vSemaphoreDelete(this->connection_mutex);
|
vSemaphoreDelete(this->connection_mutex);
|
||||||
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &WifiHandler::wifi_event_handler);
|
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &WifiHandler::wifi_event_handler);
|
||||||
esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &WifiHandler::wifi_event_handler);
|
esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &WifiHandler::wifi_event_handler);
|
||||||
|
this->initialized = false;
|
||||||
|
// unique_ptr will automatically delete the object
|
||||||
|
this->kvs = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WifiHandler::init() {
|
esp_err_t WifiHandler::init() {
|
||||||
if (this->initialized) {
|
if (this->initialized) {
|
||||||
ESP_LOGW(TAG, "Already initialized, skipping");
|
ESP_LOGW(TAG, "Already initialized, skipping");
|
||||||
return;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
|
|
||||||
@@ -67,13 +71,13 @@ void WifiHandler::init() {
|
|||||||
err = esp_netif_init();
|
err = esp_netif_init();
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "esp_netif_init failed: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "esp_netif_init failed: %s", esp_err_to_name(err));
|
||||||
return;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = esp_event_loop_create_default();
|
err = esp_event_loop_create_default();
|
||||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
||||||
ESP_LOGE(TAG, "esp_event_loop_create_default failed: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "esp_event_loop_create_default failed: %s", esp_err_to_name(err));
|
||||||
return;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create default WiFi station
|
// create default WiFi station
|
||||||
@@ -84,32 +88,40 @@ void WifiHandler::init() {
|
|||||||
err = esp_wifi_init(&cfg);
|
err = esp_wifi_init(&cfg);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "esp_wifi_init failed: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "esp_wifi_init failed: %s", esp_err_to_name(err));
|
||||||
return;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// register event handlers for WiFi and IP events
|
// register event handlers for WiFi and IP events
|
||||||
esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &WifiHandler::wifi_event_handler, this);
|
err = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &WifiHandler::wifi_event_handler, this);
|
||||||
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &WifiHandler::wifi_event_handler, this);
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "esp_event_handler_register failed: %s", esp_err_to_name(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
err = esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &WifiHandler::wifi_event_handler, this);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "esp_event_handler_register failed: %s", esp_err_to_name(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
err = esp_wifi_set_mode(WIFI_MODE_STA);
|
err = esp_wifi_set_mode(WIFI_MODE_STA);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "esp_wifi_set_mode failed: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "esp_wifi_set_mode failed: %s", esp_err_to_name(err));
|
||||||
return;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = esp_wifi_start();
|
err = esp_wifi_start();
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "esp_wifi_start failed: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "esp_wifi_start failed: %s", esp_err_to_name(err));
|
||||||
return;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get WiFi credentials from KV storage if available
|
// get WiFi credentials from KV storage if available
|
||||||
char* ssid = nullptr;
|
std::string ssid;
|
||||||
char* password = nullptr;
|
std::string password;
|
||||||
this->get_wifi_credentials(ssid, password);
|
this->get_wifi_credentials(ssid, password);
|
||||||
|
|
||||||
if (ssid && password) {
|
if (!ssid.empty() && !password.empty()) {
|
||||||
ESP_LOGI(TAG, "Found stored WiFi credentials, connecting to SSID: %s", ssid);
|
ESP_LOGI(TAG, "Found stored WiFi credentials, connecting to SSID: %s", ssid.c_str());
|
||||||
err = this->connect(ssid, password);
|
err = this->connect(ssid, password);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Failed to connect to stored WiFi credentials: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Failed to connect to stored WiFi credentials: %s", esp_err_to_name(err));
|
||||||
@@ -118,13 +130,11 @@ void WifiHandler::init() {
|
|||||||
ESP_LOGI(TAG, "No stored WiFi credentials found, not connecting");
|
ESP_LOGI(TAG, "No stored WiFi credentials found, not connecting");
|
||||||
}
|
}
|
||||||
|
|
||||||
delete[] ssid;
|
|
||||||
delete[] password;
|
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t WifiHandler::connect(const char* ssid, const char* password) {
|
esp_err_t WifiHandler::connect(const std::string& ssid, const std::string& password) {
|
||||||
SemaphoreGuard guard(this->connection_mutex);
|
SemaphoreGuard guard(this->connection_mutex);
|
||||||
// wait up to 5 seconds to take the mutex
|
// wait up to 5 seconds to take the mutex
|
||||||
if (!guard.take(5000 / portTICK_PERIOD_MS)) {
|
if (!guard.take(5000 / portTICK_PERIOD_MS)) {
|
||||||
@@ -133,24 +143,21 @@ esp_err_t WifiHandler::connect(const char* ssid, const char* password) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expect_disconnected = false;
|
expect_disconnected = false;
|
||||||
if (this->current_ssid) {
|
if (!this->current_ssid.empty()) {
|
||||||
delete[] this->current_ssid;
|
this->current_ssid.clear();
|
||||||
}
|
}
|
||||||
size_t ssid_len = strlen(ssid);
|
this->current_ssid = ssid;
|
||||||
this->current_ssid = new char[ssid_len + 1];
|
|
||||||
strncpy(this->current_ssid, ssid, ssid_len + 1);
|
|
||||||
this->current_ssid[ssid_len] = '\0';
|
|
||||||
|
|
||||||
//
|
//
|
||||||
wifi_config_t wifi_config = {};
|
wifi_config_t wifi_config = {};
|
||||||
strncpy((char*)wifi_config.sta.ssid, this->current_ssid, sizeof(wifi_config.sta.ssid));
|
strncpy((char*)wifi_config.sta.ssid, this->current_ssid.c_str(), sizeof(wifi_config.sta.ssid));
|
||||||
wifi_config.sta.ssid[sizeof(wifi_config.sta.ssid) - 1] = '\0';
|
wifi_config.sta.ssid[sizeof(wifi_config.sta.ssid) - 1] = '\0';
|
||||||
strncpy((char*)wifi_config.sta.password, password, sizeof(wifi_config.sta.password));
|
strncpy((char*)wifi_config.sta.password, password.c_str(), sizeof(wifi_config.sta.password));
|
||||||
wifi_config.sta.password[sizeof(wifi_config.sta.password) - 1] = '\0';
|
wifi_config.sta.password[sizeof(wifi_config.sta.password) - 1] = '\0';
|
||||||
// set auth mode to WPA2_PSK minimum
|
// set auth mode to WPA2_PSK minimum
|
||||||
wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
|
wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Connecting to SSID: %s", this->current_ssid);
|
ESP_LOGI(TAG, "Connecting to SSID: %s", this->current_ssid.c_str());
|
||||||
esp_err_t err = esp_wifi_set_config(wifi_interface_t::WIFI_IF_STA, &wifi_config);
|
esp_err_t err = esp_wifi_set_config(wifi_interface_t::WIFI_IF_STA, &wifi_config);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Failed to set WiFi config: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Failed to set WiFi config: %s", esp_err_to_name(err));
|
||||||
@@ -162,40 +169,26 @@ esp_err_t WifiHandler::connect(const char* ssid, const char* password) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// store credentials
|
// store credentials after successful connection attempt
|
||||||
this->kvs->put(WIFI_SSID_KEY, this->current_ssid);
|
this->store_wifi_credentials(this->current_ssid, password);
|
||||||
// store password under key derived from SSID
|
|
||||||
char* password_key = this->build_password_key(this->current_ssid);
|
|
||||||
this->kvs->put(password_key, password);
|
|
||||||
delete[] password_key;
|
|
||||||
|
|
||||||
// set connected bit on successful connection
|
|
||||||
xEventGroupSetBits(
|
|
||||||
this->s_wifi_event_group,
|
|
||||||
WIFI_CONNECTED_BIT
|
|
||||||
);
|
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t WifiHandler::connect(const char* ssid) {
|
esp_err_t WifiHandler::connect(const std::string& ssid) {
|
||||||
char* stored_ssid = nullptr;
|
std::string stored_ssid;
|
||||||
char* stored_password = nullptr;
|
std::string stored_password;
|
||||||
this->get_wifi_credentials(stored_ssid, stored_password);
|
this->get_wifi_credentials(stored_ssid, stored_password);
|
||||||
if (!stored_ssid || strcmp(stored_ssid, ssid) != 0) {
|
if (stored_ssid.empty() || stored_ssid != ssid) {
|
||||||
ESP_LOGE(TAG, "No stored credentials for SSID: %s", ssid);
|
ESP_LOGE(TAG, "No stored credentials for SSID: %s", ssid.c_str());
|
||||||
delete[] stored_ssid;
|
|
||||||
delete[] stored_password;
|
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
esp_err_t err = this->connect(stored_ssid, stored_password ? stored_password : "");
|
esp_err_t err = this->connect(stored_ssid, stored_password);
|
||||||
delete[] stored_ssid;
|
|
||||||
delete[] stored_password;
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t WifiHandler::reconnect() {
|
esp_err_t WifiHandler::reconnect() {
|
||||||
if (!this->current_ssid) {
|
if (this->current_ssid.empty()) {
|
||||||
ESP_LOGE(TAG, "No current SSID set, cannot reconnect");
|
ESP_LOGE(TAG, "No current SSID set, cannot reconnect");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -270,10 +263,15 @@ void WifiHandler::wifi_event_handler(void* arg, esp_event_base_t event_base, int
|
|||||||
case WIFI_EVENT_STA_START:
|
case WIFI_EVENT_STA_START:
|
||||||
// When the station starts, attempt to connect
|
// When the station starts, attempt to connect
|
||||||
ESP_LOGI(TAG, "WIFI_EVENT_STA_START");
|
ESP_LOGI(TAG, "WIFI_EVENT_STA_START");
|
||||||
if (!self->expect_disconnected && self->current_ssid) {
|
if (!self->expect_disconnected && !self->current_ssid.empty()) {
|
||||||
ESP_LOGI(TAG, "Station started, attempting to connect to SSID: %s", self->current_ssid);
|
ESP_LOGI(TAG, "Station started, attempting to connect to SSID: %s", self->current_ssid.c_str());
|
||||||
self->reconnect();
|
self->reconnect();
|
||||||
}
|
}
|
||||||
|
// set the event bit to indicate started
|
||||||
|
xEventGroupSetBits(
|
||||||
|
self->s_wifi_event_group,
|
||||||
|
WIFI_STARTED_BIT
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case WIFI_EVENT_STA_DISCONNECTED:
|
case WIFI_EVENT_STA_DISCONNECTED:
|
||||||
ESP_LOGI(TAG, "WIFI_EVENT_STA_DISCONNECTED");
|
ESP_LOGI(TAG, "WIFI_EVENT_STA_DISCONNECTED");
|
||||||
@@ -306,29 +304,106 @@ void WifiHandler::wifi_event_handler(void* arg, esp_event_base_t event_base, int
|
|||||||
// private methods
|
// private methods
|
||||||
//
|
//
|
||||||
|
|
||||||
char* WifiHandler::build_password_key(const char* ssid) {
|
void WifiHandler::store_wifi_credentials(const std::string& ssid, const std::string& password) {
|
||||||
// `{WIFI_PASSWORD_KEY}_{ssid}`
|
if (!kvs) {
|
||||||
size_t password_key_len = strlen(WIFI_PASSWORD_KEY) + 1 + strlen(ssid) + 1;
|
ESP_LOGW(TAG, "KVStorageHandler not set, cannot store WiFi credentials");
|
||||||
char* password_key_buff = new char[password_key_len];
|
return;
|
||||||
snprintf(password_key_buff, password_key_len, "%s_%s", WIFI_PASSWORD_KEY, ssid);
|
}
|
||||||
return password_key_buff;
|
SemaphoreGuard guard(this->credential_mutex);
|
||||||
|
// wait up to 5 seconds to take the mutex
|
||||||
|
if (!guard.take(5000 / portTICK_PERIOD_MS)) {
|
||||||
|
ESP_LOGE(TAG, "Failed to take credential mutex");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// store the password according to the JSON structure
|
||||||
|
std::string password_key_store = kvs->get(WIFI_PASSWORD_STORE_KEY);
|
||||||
|
cJSON* json = nullptr;
|
||||||
|
if (password_key_store.empty()) {
|
||||||
|
// create new JSON object
|
||||||
|
json = cJSON_CreateObject();
|
||||||
|
} else {
|
||||||
|
// parse existing JSON
|
||||||
|
json = cJSON_Parse(password_key_store.c_str());
|
||||||
|
if (json == nullptr) {
|
||||||
|
ESP_LOGE(TAG, "Failed to parse existing WiFi password JSON, creating new");
|
||||||
|
json = cJSON_CreateObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cJSON* credentials = cJSON_GetObjectItem(json, "credentials");
|
||||||
|
if (credentials == nullptr || !cJSON_IsObject(credentials)) {
|
||||||
|
// create credentials object if it doesn't exist
|
||||||
|
credentials = cJSON_CreateObject();
|
||||||
|
cJSON_AddItemToObject(json, "credentials", credentials);
|
||||||
|
}
|
||||||
|
// create SSID object
|
||||||
|
cJSON* ssid_item = cJSON_CreateObject();
|
||||||
|
// add password field
|
||||||
|
cJSON_AddStringToObject(ssid_item, "password", password.c_str());
|
||||||
|
// add SSID object to credentials
|
||||||
|
cJSON_AddItemToObject(credentials, ssid.c_str(), ssid_item);
|
||||||
|
// store updated JSON string
|
||||||
|
char* updated_json_str = cJSON_PrintUnformatted(json);
|
||||||
|
if (updated_json_str) {
|
||||||
|
kvs->put(WIFI_PASSWORD_STORE_KEY, std::string(updated_json_str));
|
||||||
|
cJSON_free(updated_json_str);
|
||||||
|
}
|
||||||
|
cJSON_Delete(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WifiHandler::get_wifi_credentials(char*& ssid, char*& password) {
|
void WifiHandler::get_wifi_credentials(std::string& out_ssid, std::string& out_password) {
|
||||||
if (!kvs) {
|
if (!kvs) {
|
||||||
ESP_LOGW(TAG, "KVStorageHandler not set, cannot get WiFi credentials");
|
ESP_LOGW(TAG, "KVStorageHandler not set, cannot get WiFi credentials");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ssid = kvs->get(WIFI_SSID_KEY).get();
|
SemaphoreGuard guard(this->credential_mutex);
|
||||||
if (!ssid) {
|
// wait up to 5 seconds to take the mutex
|
||||||
ssid = nullptr;
|
if (!guard.take(5000 / portTICK_PERIOD_MS)) {
|
||||||
password = nullptr;
|
ESP_LOGE(TAG, "Failed to take credential mutex");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
out_ssid = kvs->get(WIFI_SSID_KEY);
|
||||||
|
if (out_ssid.empty()) {
|
||||||
|
out_ssid = "";
|
||||||
|
out_password = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// password is from KV storage, may be nullptr
|
// password is from KV storage, may be nullptr
|
||||||
char* password_key = this->build_password_key(ssid);
|
std::string password_key_store = kvs->get(WIFI_PASSWORD_STORE_KEY);
|
||||||
password = kvs->get(password_key).get();
|
if (password_key_store.empty()) {
|
||||||
delete[] password_key;
|
out_password = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// parse from json
|
||||||
|
cJSON* json = cJSON_Parse(password_key_store.c_str());
|
||||||
|
if (json == nullptr) {
|
||||||
|
ESP_LOGE(TAG, "Failed to parse WiFi password JSON");
|
||||||
|
out_password = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cJSON* credentials = cJSON_GetObjectItem(json, "credentials");
|
||||||
|
if (credentials == nullptr || !cJSON_IsObject(credentials)) {
|
||||||
|
ESP_LOGE(TAG, "WiFi password JSON does not contain valid 'credentials' object");
|
||||||
|
out_password = "";
|
||||||
|
cJSON_Delete(json);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// get the ssid value
|
||||||
|
cJSON* ssid_item = cJSON_GetObjectItem(credentials, out_ssid.c_str());
|
||||||
|
if (ssid_item == nullptr || !cJSON_IsObject(ssid_item)) {
|
||||||
|
ESP_LOGE(TAG, "WiFi password JSON does not contain valid SSID field for SSID: %s", out_ssid.c_str());
|
||||||
|
out_password = "";
|
||||||
|
cJSON_Delete(json);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cJSON* password = cJSON_GetObjectItem(ssid_item, "password");
|
||||||
|
if (password == nullptr || !cJSON_IsString(password)) {
|
||||||
|
ESP_LOGE(TAG, "WiFi password JSON does not contain valid 'password' field for SSID: %s", out_ssid.c_str());
|
||||||
|
out_password = "";
|
||||||
|
cJSON_Delete(json);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
out_password = password->valuestring;
|
||||||
|
cJSON_Delete(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventBits_t WifiHandler::wait_for_connection(TickType_t ticks_to_wait) {
|
EventBits_t WifiHandler::wait_for_connection(TickType_t ticks_to_wait) {
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
#include "esp_wifi.h"
|
#include "esp_wifi.h"
|
||||||
#include "freertos/event_groups.h"
|
#include "freertos/event_groups.h"
|
||||||
|
|
||||||
#define WIFI_CONNECTED_BIT (1 << 0)
|
#define WIFI_STARTED_BIT (1 << 0)
|
||||||
|
#define WIFI_CONNECTED_BIT (1 << 1)
|
||||||
|
|
||||||
|
|
||||||
class WifiHandler {
|
class WifiHandler {
|
||||||
public:
|
public:
|
||||||
@@ -11,16 +13,13 @@ public:
|
|||||||
// this handler is used to store/retrieve WiFi credentials
|
// this handler is used to store/retrieve WiFi credentials
|
||||||
// should have a unique namespace for WiFi credentials
|
// should have a unique namespace for WiFi credentials
|
||||||
// it will be owned by WifiHandler and deleted in its destructor
|
// it will be owned by WifiHandler and deleted in its destructor
|
||||||
KVStorageHandler* kvs
|
std::unique_ptr<KVStorageHandler> kvs
|
||||||
);
|
);
|
||||||
~WifiHandler();
|
~WifiHandler();
|
||||||
|
|
||||||
// move semantics
|
esp_err_t init();
|
||||||
WifiHandler(WifiHandler&& other) noexcept;
|
esp_err_t connect(const std::string& ssid, const std::string& password);
|
||||||
|
esp_err_t connect(const std::string& ssid); // connect using stored password
|
||||||
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
|
esp_err_t reconnect(); // reconnect to current SSID
|
||||||
void disconnect();
|
void disconnect();
|
||||||
EventBits_t wait_for_connection(TickType_t ticks_to_wait);
|
EventBits_t wait_for_connection(TickType_t ticks_to_wait);
|
||||||
@@ -37,17 +36,21 @@ private:
|
|||||||
// prevent copying
|
// prevent copying
|
||||||
WifiHandler(const WifiHandler&) = delete;
|
WifiHandler(const WifiHandler&) = delete;
|
||||||
WifiHandler& operator=(const WifiHandler&) = delete;
|
WifiHandler& operator=(const WifiHandler&) = delete;
|
||||||
|
// prevent moving
|
||||||
|
WifiHandler(WifiHandler&& other) = delete;
|
||||||
|
WifiHandler& operator=(WifiHandler&& other) = delete;
|
||||||
|
|
||||||
char* build_password_key(const char* ssid);
|
void store_wifi_credentials(const std::string& ssid, const std::string& password);
|
||||||
void get_wifi_credentials(char*& ssid, char*& password);
|
void get_wifi_credentials(std::string& out_ssid, std::string& out_password);
|
||||||
|
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
KVStorageHandler* kvs = nullptr;
|
std::unique_ptr<KVStorageHandler> kvs = nullptr;
|
||||||
EventGroupHandle_t s_wifi_event_group = 0;
|
EventGroupHandle_t s_wifi_event_group = 0;
|
||||||
SemaphoreHandle_t scan_mutex = nullptr;
|
SemaphoreHandle_t scan_mutex = nullptr;
|
||||||
SemaphoreHandle_t connection_mutex = nullptr;
|
SemaphoreHandle_t connection_mutex = nullptr;
|
||||||
|
SemaphoreHandle_t credential_mutex = nullptr;
|
||||||
// current connected / preferred SSID
|
// current connected / preferred SSID
|
||||||
char* current_ssid = nullptr;
|
std::string current_ssid;
|
||||||
// prevent auto-reconnect on expected disconnection, e.g. when user calls disconnect()
|
// prevent auto-reconnect on expected disconnection, e.g. when user calls disconnect()
|
||||||
// should be reset to false after connect()
|
// should be reset to false after connect()
|
||||||
bool expect_disconnected = false;
|
bool expect_disconnected = false;
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
#include "touch.h"
|
|
||||||
#include "common/constants.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "freertos/event_groups.h"
|
|
||||||
// TODO: implement actual touch functionality
|
|
||||||
|
|
||||||
TouchHandler::TouchHandler(QueueHandle_t touch_queue) {
|
|
||||||
(void)touch_queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
TouchHandler::~TouchHandler() { }
|
|
||||||
|
|
||||||
EInkTouchHandler::EInkTouchHandler(QueueHandle_t touch_queue)
|
|
||||||
: TouchHandler(touch_queue) { }
|
|
||||||
|
|
||||||
EInkTouchHandler::~EInkTouchHandler() { }
|
|
||||||
|
|
||||||
void EInkTouchHandler::init(EventGroupHandle_t system_event_group) {
|
|
||||||
if (system_event_group != NULL) {
|
|
||||||
xEventGroupSetBits(system_event_group, TOUCH_CALIBRATED_BIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EInkTouchHandler::start_event_loop() {
|
|
||||||
// Minimal background task to represent touch processing
|
|
||||||
xTaskCreate(
|
|
||||||
// use static adapter and pass `this` as task parameter
|
|
||||||
EInkTouchHandler::task_adapter,
|
|
||||||
"touch_task",
|
|
||||||
2048,
|
|
||||||
this,
|
|
||||||
tskIDLE_PRIORITY + 1,
|
|
||||||
nullptr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
void EInkTouchHandler::task_adapter(void* arg) {
|
|
||||||
EInkTouchHandler* self = static_cast<EInkTouchHandler*>(arg);
|
|
||||||
if (self) {
|
|
||||||
self->run_event_loop();
|
|
||||||
} else {
|
|
||||||
printf("EInkTouchHandler::task_adapter received null pointer\n");
|
|
||||||
}
|
|
||||||
vTaskDelete(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EInkTouchHandler::run_event_loop() {
|
|
||||||
for (;;) {
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "esp_system.h"
|
|
||||||
|
|
||||||
class TouchHandler {
|
|
||||||
public:
|
|
||||||
TouchHandler(QueueHandle_t touch_queue);
|
|
||||||
// the system_event_group is used to set touch-calibrated bit
|
|
||||||
virtual void init(EventGroupHandle_t system_event_group) = 0;
|
|
||||||
virtual void start_event_loop() = 0;
|
|
||||||
virtual ~TouchHandler() = 0;
|
|
||||||
private:
|
|
||||||
TouchHandler(const TouchHandler&) = delete;
|
|
||||||
TouchHandler& operator=(const TouchHandler&) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EInkTouchHandler : public TouchHandler {
|
|
||||||
public:
|
|
||||||
EInkTouchHandler(QueueHandle_t touch_queue);
|
|
||||||
void init(EventGroupHandle_t system_event_group) override;
|
|
||||||
void start_event_loop() override;
|
|
||||||
~EInkTouchHandler() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Task adapter used for FreeRTOS task creation. Forwards to
|
|
||||||
// `run_event_loop()` using the `this` pointer passed as the task param.
|
|
||||||
static void task_adapter(void* arg);
|
|
||||||
|
|
||||||
// Instance method implementing the touch event loop.
|
|
||||||
void run_event_loop();
|
|
||||||
// prevent copying
|
|
||||||
EInkTouchHandler(const EInkTouchHandler&) = delete;
|
|
||||||
EInkTouchHandler& operator=(const EInkTouchHandler&) = delete;
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user