Add config and wifi

This commit is contained in:
2022-01-30 00:51:47 +01:00
parent fe1904cc51
commit 70f5d647fb
12 changed files with 837 additions and 1 deletions

View File

@ -1,8 +1,18 @@
set(headers
config.h
debugconsole.h
ota.h
taskmanager.h
wifi.h
)
set(sources
config.cpp
debugconsole.cpp
main.cpp
ota.cpp
taskmanager.cpp
wifi.cpp
)
set(dependencies

33
main/config.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "config.h"
#include "sdkconfig.h"
// esp-idf includes
#include <esp_log.h>
// 3rdparty lib includes
#include <configmanager_priv.h>
#include <fmt/core.h>
#include <espwifistack.h>
// local includes
#include "configmanager_priv.h"
using namespace std::chrono_literals;
namespace {
//constexpr const char * const TAG = "CONFIG";
} // namespace
std::string defaultHostname()
{
if (const auto result = wifi_stack::get_default_mac_addr())
return fmt::format("bobby_{:02x}{:02x}{:02x}", result->at(3), result->at(4), result->at(5));
else
ESP_LOGE(TAG, "get_default_mac_addr() failed: %.*s", result.error().size(), result.error().data());
return "bobby";
}
ConfigManager<ConfigContainer> configs;
INSTANTIATE_CONFIGMANAGER_TEMPLATES(ConfigContainer)

168
main/config.h Normal file
View File

@ -0,0 +1,168 @@
#pragma once
#include "sdkconfig.h"
// system includes
#include <string>
#include <array>
#include <optional>
// esp-idf includes
#include <esp_sntp.h>
// 3rdparty lib includes
#include <fmt/core.h>
#include <configmanager.h>
#include <configconstraints_base.h>
#include <configconstraints_espchrono.h>
#include <configwrapper.h>
#include <espwifiutils.h>
#include <espchrono.h>
#include <makearray.h>
// local includes
using namespace espconfig;
std::string defaultHostname();
class WiFiConfig
{
public:
WiFiConfig(const char *ssidNvsKey, const char *keyNvsKey,
const char *useStaticIpKey, const char *staticIpKey, const char *staticSubnetKey, const char *staticGatewayKey,
const char *useStaticDnsKey, const char *staticDns0Key, const char *staticDns1Key, const char *staticDns2Key) :
ssid {std::string{}, DoReset, StringMaxSize<32>, ssidNvsKey },
key {std::string{}, DoReset, StringOr<StringEmpty, StringMinMaxSize<8, 64>>, keyNvsKey },
useStaticIp {false, DoReset, {}, useStaticIpKey },
staticIp {wifi_stack::ip_address_t{}, DoReset, {}, staticIpKey },
staticSubnet {wifi_stack::ip_address_t{}, DoReset, {}, staticSubnetKey },
staticGateway{wifi_stack::ip_address_t{}, DoReset, {}, staticGatewayKey },
useStaticDns {false, DoReset, {}, useStaticDnsKey },
staticDns0 {wifi_stack::ip_address_t{}, DoReset, {}, staticDns0Key },
staticDns1 {wifi_stack::ip_address_t{}, DoReset, {}, staticDns1Key },
staticDns2 {wifi_stack::ip_address_t{}, DoReset, {}, staticDns2Key }
{}
ConfigWrapper<std::string> ssid;
ConfigWrapper<std::string> key;
ConfigWrapper<bool> useStaticIp;
ConfigWrapper<wifi_stack::ip_address_t> staticIp;
ConfigWrapper<wifi_stack::ip_address_t> staticSubnet;
ConfigWrapper<wifi_stack::ip_address_t> staticGateway;
ConfigWrapper<bool> useStaticDns;
ConfigWrapper<wifi_stack::ip_address_t> staticDns0;
ConfigWrapper<wifi_stack::ip_address_t> staticDns1;
ConfigWrapper<wifi_stack::ip_address_t> staticDns2;
};
class ConfigContainer
{
using mac_t = wifi_stack::mac_t;
public:
// default allowReset constraints nvsName
ConfigWrapper<std::optional<mac_t>> baseMacAddressOverride{std::nullopt, DoReset, {}, "baseMacAddrOver" };
ConfigWrapper<std::string> hostname {defaultHostname, DoReset, StringMinMaxSize<4, 32>, "hostname" };
#ifdef CONFIG_ETH_ENABLED
ConfigWrapper<bool> ethEnabled {true, DoReset, {}, "ethEnabled" };
ConfigWrapper<bool> ethUseStaticIp {false, DoReset, {}, "ethUseStatIp" };
ConfigWrapper<ip_address_t> ethStaticIp {ip_address_t{}, DoReset, {}, "ethStaticIp" };
ConfigWrapper<ip_address_t> ethStaticSubnet {ip_address_t{}, DoReset, {}, "ethStaticSub" };
ConfigWrapper<ip_address_t> ethStaticGateway {ip_address_t{}, DoReset, {}, "ethStaticGw" };
ConfigWrapper<bool> ethUseStaticDns {false, DoReset, {}, "ethUseStatDns" };
ConfigWrapper<ip_address_t> ethStaticDns0 {ip_address_t{}, DoReset, {}, "ethStaticDns0" };
ConfigWrapper<ip_address_t> ethStaticDns1 {ip_address_t{}, DoReset, {}, "ethStaticDns1" };
ConfigWrapper<ip_address_t> ethStaticDns2 {ip_address_t{}, DoReset, {}, "ethStaticDns2" };
#endif
ConfigWrapper<bool> wifiStaEnabled {true, DoReset, {}, "wifiStaEnabled" };
std::array<WiFiConfig, 10> wifi_configs {
WiFiConfig {"wifi_ssid0", "wifi_key0", "wifi_usestatic0", "wifi_static_ip0", "wifi_stati_sub0", "wifi_stat_gate0", "wifi_usestadns0", "wifi_stat_dnsA0", "wifi_stat_dnsB0", "wifi_stat_dnsC0"},
WiFiConfig {"wifi_ssid1", "wifi_key1", "wifi_usestatic1", "wifi_static_ip1", "wifi_stati_sub1", "wifi_stat_gate1", "wifi_usestadns1", "wifi_stat_dnsA1", "wifi_stat_dnsB1", "wifi_stat_dnsC1"},
WiFiConfig {"wifi_ssid2", "wifi_key2", "wifi_usestatic2", "wifi_static_ip2", "wifi_stati_sub2", "wifi_stat_gate2", "wifi_usestadns2", "wifi_stat_dnsA2", "wifi_stat_dnsB2", "wifi_stat_dnsC2"},
WiFiConfig {"wifi_ssid3", "wifi_key3", "wifi_usestatic3", "wifi_static_ip3", "wifi_stati_sub3", "wifi_stat_gate3", "wifi_usestadns3", "wifi_stat_dnsA3", "wifi_stat_dnsB3", "wifi_stat_dnsC3"},
WiFiConfig {"wifi_ssid4", "wifi_key4", "wifi_usestatic4", "wifi_static_ip4", "wifi_stati_sub4", "wifi_stat_gate4", "wifi_usestadns4", "wifi_stat_dnsA4", "wifi_stat_dnsB4", "wifi_stat_dnsC4"},
WiFiConfig {"wifi_ssid5", "wifi_key5", "wifi_usestatic5", "wifi_static_ip5", "wifi_stati_sub5", "wifi_stat_gate5", "wifi_usestadns5", "wifi_stat_dnsA5", "wifi_stat_dnsB5", "wifi_stat_dnsC5"},
WiFiConfig {"wifi_ssid6", "wifi_key6", "wifi_usestatic6", "wifi_static_ip6", "wifi_stati_sub6", "wifi_stat_gate6", "wifi_usestadns6", "wifi_stat_dnsA6", "wifi_stat_dnsB6", "wifi_stat_dnsC6"},
WiFiConfig {"wifi_ssid7", "wifi_key7", "wifi_usestatic7", "wifi_static_ip7", "wifi_stati_sub7", "wifi_stat_gate7", "wifi_usestadns7", "wifi_stat_dnsA7", "wifi_stat_dnsB7", "wifi_stat_dnsC7"},
WiFiConfig {"wifi_ssid8", "wifi_key8", "wifi_usestatic8", "wifi_static_ip8", "wifi_stati_sub8", "wifi_stat_gate8", "wifi_usestadns8", "wifi_stat_dnsA8", "wifi_stat_dnsB8", "wifi_stat_dnsC8"},
WiFiConfig {"wifi_ssid9", "wifi_key9", "wifi_usestatic9", "wifi_static_ip9", "wifi_stati_sub9", "wifi_stat_gate9", "wifi_usestadns9", "wifi_stat_dnsA9", "wifi_stat_dnsB9", "wifi_stat_dnsC9"}
};
ConfigWrapper<int8_t> wifiStaMinRssi {-90, DoReset, {}, "wifiStaMinRssi" };
ConfigWrapper<bool> wifiApEnabled {true, DoReset, {}, "wifiApEnabled" };
ConfigWrapper<std::string> wifiApName {defaultHostname, DoReset, StringMinMaxSize<4, 32>, "wifiApName" };
ConfigWrapper<std::string> wifiApKey {"Passwort_123", DoReset, StringOr<StringEmpty, StringMinMaxSize<8, 64>>, "wifiApKey" };
ConfigWrapper<wifi_stack::ip_address_t> wifiApIp{wifi_stack::ip_address_t{10, 0, 0, 1},DoReset, {}, "wifiApIp" };
ConfigWrapper<wifi_stack::ip_address_t> wifiApMask{wifi_stack::ip_address_t{255, 255, 255, 0},DoReset, {}, "wifiApMask" };
ConfigWrapper<uint8_t> wifiApChannel {1, DoReset, MinMaxValue<uint8_t, 1, 14>, "wifiApChannel" };
ConfigWrapper<wifi_auth_mode_t> wifiApAuthmode{WIFI_AUTH_WPA2_PSK, DoReset, {}, "wifiApAuthmode" };
ConfigWrapper<bool> timeServerEnabled {true, DoReset, {}, "timeServerEnabl" };
ConfigWrapper<std::string> timeServer {"europe.pool.ntp.org", DoReset, StringMaxSize<64>, "timeServer" };
ConfigWrapper<sntp_sync_mode_t> timeSyncMode {SNTP_SYNC_MODE_IMMED, DoReset, {}, "timeSyncMode" };
ConfigWrapper<espchrono::milliseconds32> timeSyncInterval{espchrono::milliseconds32{CONFIG_LWIP_SNTP_UPDATE_DELAY}, DoReset, MinTimeSyncInterval, "timeSyncInterva" };
ConfigWrapper<espchrono::minutes32> timezoneOffset{espchrono::minutes32{60}, DoReset, {}, "timezoneOffset" }; // MinMaxValue<minutes32, -1440m, 1440m>
ConfigWrapper<espchrono::DayLightSavingMode>timeDst{espchrono::DayLightSavingMode::EuropeanSummerTime, DoReset, {}, "time_dst" };
template<typename T>
void callForEveryConfig(T &&callable)
{
#define REGISTER_CONFIG(name) \
if (callable(name)) return;
REGISTER_CONFIG(baseMacAddressOverride)
REGISTER_CONFIG(hostname)
#ifdef CONFIG_ETH_ENABLED
REGISTER_CONFIG(ethEnabled)
REGISTER_CONFIG(ethUseStaticIp)
REGISTER_CONFIG(ethStaticIp)
REGISTER_CONFIG(ethStaticSubnet)
REGISTER_CONFIG(ethStaticGateway)
REGISTER_CONFIG(ethUseStaticDns)
REGISTER_CONFIG(ethStaticDns0)
REGISTER_CONFIG(ethStaticDns1)
REGISTER_CONFIG(ethStaticDns2)
#endif
REGISTER_CONFIG(wifiStaEnabled)
for (auto &entry : wifi_configs)
{
REGISTER_CONFIG(entry.ssid)
REGISTER_CONFIG(entry.key)
REGISTER_CONFIG(entry.useStaticIp)
REGISTER_CONFIG(entry.staticIp)
REGISTER_CONFIG(entry.staticSubnet)
REGISTER_CONFIG(entry.staticGateway)
REGISTER_CONFIG(entry.useStaticDns)
REGISTER_CONFIG(entry.staticDns0)
REGISTER_CONFIG(entry.staticDns1)
REGISTER_CONFIG(entry.staticDns2)
}
REGISTER_CONFIG(wifiStaMinRssi)
REGISTER_CONFIG(wifiApEnabled)
REGISTER_CONFIG(wifiApName)
REGISTER_CONFIG(wifiApKey)
REGISTER_CONFIG(wifiApIp)
REGISTER_CONFIG(wifiApMask)
REGISTER_CONFIG(wifiApChannel)
REGISTER_CONFIG(wifiApAuthmode)
REGISTER_CONFIG(timeServerEnabled)
REGISTER_CONFIG(timeServer)
REGISTER_CONFIG(timeSyncMode)
REGISTER_CONFIG(timeSyncInterval)
REGISTER_CONFIG(timezoneOffset)
REGISTER_CONFIG(timeDst)
#undef REGISTER_API_VALUE
}
};
extern ConfigManager<ConfigContainer> configs;

141
main/debugconsole.cpp Normal file
View File

@ -0,0 +1,141 @@
#include "debugconsole.h"
// system includes
#include <string_view>
// esp-idf includes
#include <driver/uart.h>
#include <esp_log.h>
// 3rdparty lib includes
#include <espstrutils.h>
namespace {
constexpr const char * const TAG = "DEBUG";
uint8_t consoleControlCharsReceived{};
bool uart0Initialized{};
void handleNormalChar(char c);
void handleSpecialChar(char c);
} // namespace
MemoryDebug memoryDebug{Off};
espchrono::millis_clock::time_point lastMemoryDebug;
void init_debugconsole()
{
if (const auto result = uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, 3, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); result != ESP_OK)
{
ESP_LOGE(TAG, "uart_set_pin() failed with %s", esp_err_to_name(result));
}
if (const auto result = uart_driver_install(UART_NUM_0, SOC_UART_FIFO_LEN + 1, 0, 10, nullptr, 0); result != ESP_OK)
ESP_LOGE(TAG, "uart_driver_install() failed with %s", esp_err_to_name(result));
else
uart0Initialized = true;
}
void update_debugconsole()
{
if (!uart0Initialized)
return;
size_t length{};
if (const auto result = uart_get_buffered_data_len(UART_NUM_0, &length); result != ESP_OK)
{
ESP_LOGW(TAG, "uart_get_buffered_data_len() failed with %s", esp_err_to_name(result));
}
else if (length)
{
char data[length];
length = uart_read_bytes(UART_NUM_0, data, length, 0);
for (char c : std::string_view{data, length})
{
if (consoleControlCharsReceived < 2)
{
switch (c)
{
case '\x1b':
if (consoleControlCharsReceived == 0)
consoleControlCharsReceived = 1;
else
consoleControlCharsReceived = 0;
break;
case '\x5b':
if (consoleControlCharsReceived == 1)
consoleControlCharsReceived = 2;
else
consoleControlCharsReceived = 0;
break;
default:
consoleControlCharsReceived = 0;
handleNormalChar(c);
}
}
else
{
consoleControlCharsReceived = 0;
handleSpecialChar(c);
}
}
}
}
namespace {
void handleNormalChar(char c)
{
constexpr auto rotateLogLevel = [](const char *tag){
const auto oldLogLevel = esp_log_level_get(tag);
const auto newLogLevel = oldLogLevel == ESP_LOG_INFO ? ESP_LOG_DEBUG : (oldLogLevel == ESP_LOG_DEBUG ? ESP_LOG_VERBOSE : ESP_LOG_INFO);
esp_log_level_set(tag, newLogLevel);
ESP_LOGI(TAG, "%s loglevel set to %s (previous=%s)", tag, espcpputils::toString(newLogLevel).c_str(), espcpputils::toString(oldLogLevel).c_str());
};
switch (c)
{
case 'r': case 'R':
ESP_LOGI(TAG, "Rebooting...");
esp_restart();
break;
case 'm': case 'M':
switch (memoryDebug)
{
case Off:
memoryDebug = Normal;
ESP_LOGI(TAG, "memory debug set to %s", "Normal");
break;
case Normal:
memoryDebug = Fast;
ESP_LOGI(TAG, "memory debug set to %s", "Fast");
break;
case Fast:
memoryDebug = Off;
ESP_LOGI(TAG, "memory debug set to %s", "Off");
break;
}
break;
case 'w': case 'W':
rotateLogLevel("WEBSERVER");
break;
}
}
void handleSpecialChar(char c)
{
switch (c)
{
case 'A': // Up arrow pressed
break;
case 'B': // Down arrow pressed
break;
case 'C': // Right arrow pressed
break;
case 'D': // Left arrow pressed
break;
default:
ESP_LOGI(TAG, "unknown control char received: %hhx", c);
}
}
} // namespace

11
main/debugconsole.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
// 3rdparty lib includes
#include <espchrono.h>
enum MemoryDebug {Off,Normal,Fast};
extern MemoryDebug memoryDebug;
extern espchrono::millis_clock::time_point lastMemoryDebug;
void init_debugconsole();
void update_debugconsole();

View File

@ -1,10 +1,191 @@
#include "sdkconfig.h"
// esp-idf includes
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#if defined(CONFIG_ESP_TASK_WDT_PANIC) || defined(CONFIG_ESP_TASK_WDT)
#include <freertos/task.h>
#include <esp_task_wdt.h>
#endif
#ifdef CONFIG_APP_ROLLBACK_ENABLE
#include <esp_ota_ops.h>
#endif
#include <esp_heap_caps.h>
// Arduino includes
#include <esp32-hal-gpio.h>
// 3rdparty lib includes
#include <schedulertask.h>
#include <espchrono.h>
#include <espasyncota.h>
#include <espstrutils.h>
#include <esprandom.h>
#include <strutils.h>
// local includes
#include "config.h"
#include "debugconsole.h"
#include "taskmanager.h"
#include "ota.h"
#include "wifi.h"
using namespace std::chrono_literals;
namespace {
constexpr const char * const TAG = "MAIN";
espchrono::millis_clock::time_point lastLoopCount;
int _loopCount{};
int loopCountTemp{};
} // namespace
const int &loopCount{_loopCount};
extern "C" void app_main()
{
ESP_LOGI(TAG, "hello world");
#if defined(CONFIG_ESP_TASK_WDT_PANIC) || defined(CONFIG_ESP_TASK_WDT)
{
const auto taskHandle = xTaskGetCurrentTaskHandle();
if (!taskHandle)
{
ESP_LOGE(TAG, "could not get handle to current main task!");
}
else if (const auto result = esp_task_wdt_add(taskHandle); result != ESP_OK)
{
ESP_LOGE(TAG, "could not add main task to watchdog: %s", esp_err_to_name(result));
}
}
bool wasPreviouslyUpdating{};
#endif
#ifdef CONFIG_APP_ROLLBACK_ENABLE
esp_ota_img_states_t ota_state;
if (const esp_partition_t * const running = esp_ota_get_running_partition())
{
if (const auto result = esp_ota_get_state_partition(running, &ota_state); result == ESP_ERR_NOT_FOUND)
ota_state = ESP_OTA_IMG_VALID;
else if (result != ESP_OK)
{
ESP_LOGE(TAG, "esp_ota_get_state_partition() failed with %s", esp_err_to_name(result));
ota_state = ESP_OTA_IMG_UNDEFINED;
}
}
else
{
ESP_LOGE(TAG, "esp_ota_get_running_partition() returned nullptr");
ota_state = ESP_OTA_IMG_UNDEFINED;
}
#endif
//init proper ref tick value for PLL (uncomment if REF_TICK is different than 1MHz)
//ESP_REG(APB_CTRL_PLL_TICK_CONF_REG) = APB_CLK_FREQ / REF_CLK_FREQ - 1;
pinMode(3, INPUT_PULLUP);
if (const auto result = configs.init("dmxnode"); result != ESP_OK)
ESP_LOGE(TAG, "config_init_settings() failed with %s", esp_err_to_name(result));
for (const auto &task : schedulerTasks)
task.setup();
while (true)
{
bool pushStats = espchrono::ago(lastLoopCount) >= 1s;
if (pushStats)
{
lastLoopCount = espchrono::millis_clock::now();
_loopCount = loopCountTemp;
loopCountTemp = 0;
}
loopCountTemp++;
for (auto &task : schedulerTasks)
{
task.loop();
#if defined(CONFIG_ESP_TASK_WDT_PANIC) || defined(CONFIG_ESP_TASK_WDT)
if (wasPreviouslyUpdating)
{
if (const auto result = esp_task_wdt_reset(); result != ESP_OK)
ESP_LOGE(TAG, "esp_task_wdt_reset() failed with %s", esp_err_to_name(result));
//vPortYield();
vTaskDelay(1);
}
#endif
}
if (pushStats)
{
sched_pushStats(memoryDebug == Fast);
}
if constexpr (LOG_LOCAL_LEVEL >= ESP_LOG_WARN)
{
const auto free8 = heap_caps_get_free_size(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
if (free8 < 25000)
{
lastMemoryDebug = espchrono::millis_clock::now();
ESP_LOGW(TAG, "MEMORY heap8=%zd (largest block: %zd) heap32=%zd lps=%i",
free8,
heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT),
heap_caps_get_free_size(MALLOC_CAP_INTERNAL|MALLOC_CAP_32BIT),
_loopCount
);
}
else if constexpr (LOG_LOCAL_LEVEL >= ESP_LOG_INFO)
{
if (memoryDebug != Off &&
espchrono::ago(lastMemoryDebug) >= (memoryDebug == Fast ? 100ms : 1000ms))
{
lastMemoryDebug = espchrono::millis_clock::now();
ESP_LOGI(TAG, "MEMORY heap8=%zd (largest block: %zd) heap32=%zd lps=%i",
free8,
heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT),
heap_caps_get_free_size(MALLOC_CAP_INTERNAL|MALLOC_CAP_32BIT),
_loopCount
);
}
}
}
#if defined(CONFIG_ESP_TASK_WDT_PANIC) || defined(CONFIG_ESP_TASK_WDT)
if (const auto result = esp_task_wdt_reset(); result != ESP_OK)
ESP_LOGE(TAG, "esp_task_wdt_reset() failed with %s", esp_err_to_name(result));
if (const auto isUpdating = otaClient.status() == OtaCloudUpdateStatus::Updating; isUpdating != wasPreviouslyUpdating)
{
wasPreviouslyUpdating = isUpdating;
constexpr bool panic =
#ifdef CONFIG_ESP_TASK_WDT_PANIC
true
#else
false
#endif
;
const uint32_t timeout = isUpdating ?
CONFIG_ESP_TASK_WDT_TIMEOUT_S * 4 :
CONFIG_ESP_TASK_WDT_TIMEOUT_S;
const auto result = esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, panic);
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "esp_task_wdt_init() with new timeout %u returned: %s", timeout, esp_err_to_name(result));
}
#endif
#ifdef CONFIG_APP_ROLLBACK_ENABLE
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY)
{
const auto result = esp_ota_mark_app_valid_cancel_rollback();
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "esp_ota_mark_app_valid_cancel_rollback() returned: %s", esp_err_to_name(result));
ota_state = ESP_OTA_IMG_VALID;
}
#endif
//vPortYield();
vTaskDelay(1);
}
}

58
main/ota.cpp Normal file
View File

@ -0,0 +1,58 @@
#include "ota.h"
// system includes
#include <chrono>
#include <string>
// esp-idf includes
#include <esp_log.h>
// 3rdparty lib includes
#include <fmt/core.h>
#include <delayedconstruction.h>
#include <espasyncota.h>
#include <espwifistack.h>
#include <recursivelockhelper.h>
// local includes
#include "config.h"
using namespace std::chrono_literals;
namespace {
constexpr const char * const TAG = "OTA_CLOUD";
cpputils::DelayedConstruction<EspAsyncOta> _otaClient;
} // namespace
EspAsyncOta &otaClient{_otaClient.getUnsafe()};
void ota_cloud_init()
{
ESP_LOGI(TAG, "called");
_otaClient.construct("asyncOtaTask", 8192u);
}
void ota_cloud_update()
{
_otaClient->update();
}
tl::expected<void, std::string> otaClientTrigger(std::string_view url)
{
if (auto result = _otaClient->trigger(url, {}, {}, {}); !result)
return tl::make_unexpected(std::move(result).error());
wifi_stack::delete_scan_result();
return {};
}
tl::expected<void, std::string> otaClientAbort()
{
if (auto result = _otaClient->abort(); !result)
return tl::make_unexpected(std::move(result).error());
return {};
}

20
main/ota.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
// system includes
#include <string>
#include <string_view>
#include <map>
// 3rdparty lib includes
#include <tl/expected.hpp>
// forward declares
class EspAsyncOta;
extern EspAsyncOta &otaClient;
void ota_cloud_init();
void ota_cloud_update();
tl::expected<void, std::string> otaCloudTrigger(std::string_view url);
tl::expected<void, std::string> otaCloudAbort();

44
main/taskmanager.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "taskmanager.h"
// system includes
#include <iterator>
#include <chrono>
// esp-idf includes
#include <esp_log.h>
// 3rdparty lib includes
#include <schedulertask.h>
// local includes
#include "wifi.h"
#include "debugconsole.h"
#include "ota.h"
using namespace std::chrono_literals;
namespace {
constexpr const char * const TAG = "TASKS";
void not_needed() {}
espcpputils::SchedulerTask schedulerTasksArr[] {
espcpputils::SchedulerTask { "wifi", wifi_begin, wifi_update, 100ms },
espcpputils::SchedulerTask { "debugconsole", init_debugconsole, update_debugconsole, 50ms },
espcpputils::SchedulerTask { "ota_cloud", ota_cloud_init, ota_cloud_update, 100ms },
};
} // namespace
cpputils::ArrayView<espcpputils::SchedulerTask> schedulerTasks{std::begin(schedulerTasksArr), std::end(schedulerTasksArr)};
void sched_pushStats(bool printTasks)
{
if (printTasks)
ESP_LOGI(TAG, "begin listing tasks...");
for (auto &schedulerTask : schedulerTasks)
schedulerTask.pushStats(printTasks);
if (printTasks)
ESP_LOGI(TAG, "end listing tasks");
}

11
main/taskmanager.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
// 3rdparty lib includes
#include <arrayview.h>
// forward declares
namespace espcpputils { class SchedulerTask; }
extern cpputils::ArrayView<espcpputils::SchedulerTask> schedulerTasks;
void sched_pushStats(bool printTasks);

146
main/wifi.cpp Normal file
View File

@ -0,0 +1,146 @@
#include "wifi.h"
// system includes
#include <optional>
// esp-idf includes
#include <esp_log.h>
// 3rdparty lib includes
#include <espwifistack.h>
// local includes
#include "config.h"
namespace {
wifi_stack::config createConfig();
std::optional<wifi_stack::sta_config> createStaConfig();
wifi_stack::wifi_entry createWifiEntry(const WiFiConfig &wifi_config);
std::optional<wifi_stack::ap_config> createApConfig();
} // namespace
void wifi_begin()
{
wifi_stack::init(createConfig());
}
void wifi_update()
{
wifi_stack::update(createConfig());
}
esp_err_t wifi_scan()
{
const auto &sta_config = createStaConfig();
if (!sta_config)
{
ESP_LOGE("BOBBY", "no sta enabled");
return ESP_FAIL;
}
if (const auto result = wifi_stack::begin_scan(*sta_config); !result)
{
ESP_LOGE("BOBBY", "begin_scan() failed with %.*s", result.error().size(), result.error().data());
return ESP_FAIL;
}
return ESP_OK;
}
namespace {
wifi_stack::config createConfig()
{
return wifi_stack::config {
.base_mac_override = configs.baseMacAddressOverride.value,
//.dual_ant = dual_ant_config{},
.sta = createStaConfig(),
.ap = createApConfig(),
#ifdef CONFIG_ETH_ENABLED
.eth = createEthConfig()
#endif
};
}
std::optional<wifi_stack::sta_config> createStaConfig()
{
if (!configs.wifiStaEnabled.value)
return std::nullopt;
return wifi_stack::sta_config{
.hostname = configs.hostname.value,
.wifis = std::array<wifi_stack::wifi_entry, 10> {
createWifiEntry(configs.wifi_configs[0]),
createWifiEntry(configs.wifi_configs[1]),
createWifiEntry(configs.wifi_configs[2]),
createWifiEntry(configs.wifi_configs[3]),
createWifiEntry(configs.wifi_configs[4]),
createWifiEntry(configs.wifi_configs[5]),
createWifiEntry(configs.wifi_configs[6]),
createWifiEntry(configs.wifi_configs[7]),
createWifiEntry(configs.wifi_configs[8]),
createWifiEntry(configs.wifi_configs[9])
},
.min_rssi = configs.wifiStaMinRssi.value,
.long_range = false
};
}
wifi_stack::wifi_entry createWifiEntry(const WiFiConfig &wifi_config)
{
std::optional<wifi_stack::static_ip_config> static_ip;
if (wifi_config.useStaticIp.value)
static_ip = wifi_stack::static_ip_config {
.ip = wifi_config.staticIp.value,
.subnet = wifi_config.staticSubnet.value,
.gateway = wifi_config.staticGateway.value
};
wifi_stack::static_dns_config static_dns;
if (wifi_config.useStaticDns.value)
{
if (wifi_config.staticDns0.value.value())
static_dns.main = wifi_config.staticDns0.value;
if (wifi_config.staticDns1.value.value())
static_dns.backup = wifi_config.staticDns1.value;
if (wifi_config.staticDns2.value.value())
static_dns.fallback = wifi_config.staticDns2.value;
}
return wifi_stack::wifi_entry {
.ssid = wifi_config.ssid.value,
.key = wifi_config.key.value,
.static_ip = static_ip,
.static_dns = static_dns
};
}
std::optional<wifi_stack::ap_config> createApConfig()
{
if (!configs.wifiApEnabled.value)
return std::nullopt;
// if (configs.wifiDisableApWhenOnline.value &&
// cloudStarted &&
// cloudConnected &&
// lastCloudConnectedToggled &&
// espchrono::ago(*lastCloudConnectedToggled) >= 30s)
// return std::nullopt;
return wifi_stack::ap_config {
.hostname = configs.hostname.value,
.ssid = configs.wifiApName.value,
.key = configs.wifiApKey.value,
.static_ip = {
.ip = configs.wifiApIp.value,
.subnet = configs.wifiApMask.value,
.gateway = configs.wifiApIp.value,
},
.channel = configs.wifiApChannel.value,
.authmode = configs.wifiApAuthmode.value,
.ssid_hidden = false,
.max_connection = 4,
.beacon_interval = 100,
.long_range = false
};
}
} // namespace

13
main/wifi.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
// esp-idf includes
#include <esp_err.h>
// 3rdparty lib includes
#include <espwifiutils.h>
void wifi_begin();
void wifi_update();
esp_err_t wifi_scan();