Compare commits

..

6 Commits

Author SHA1 Message Date
Erki
b1ae5dcd48 Fix some runtime issues 2024-02-16 17:14:21 +02:00
Erki
bbdcd9b5ec Firmware: rework string actions a bit 2024-02-16 16:52:26 +02:00
Erki
509909625c Firmware: Integrate skullc 2024-02-16 16:52:10 +02:00
Erki
585f219b38 Firmware: pull skullc 2024-02-11 13:10:51 +02:00
Erki
2240213efd Firmware: Refactor events a little 2024-02-11 11:23:19 +02:00
Erki
a763095f96 Firmware: fix lint 2024-02-11 10:29:43 +02:00
8 changed files with 140 additions and 34 deletions

3
.gitmodules vendored
View File

@ -4,3 +4,6 @@
[submodule "firmware/components/etlcpp/etl"]
path = firmware/components/etlcpp/etl
url = https://github.com/ETLCPP/etl.git
[submodule "firmware/components/skullc/skullc-peripherals"]
path = firmware/components/skullc/skullc-peripherals
url = https://git.skullnet.me/erki/skullc-peripherals.git

View File

@ -0,0 +1,6 @@
idf_component_register(INCLUDE_DIRS
"skullc-peripherals/Peripherals/Inc"
"skullc-peripherals/Utility/Inc"
SRC_DIRS
"skullc-peripherals/Utility/Src"
REQUIRES etlcpp driver)

@ -0,0 +1 @@
Subproject commit 470ad7537695229e57f2332fdd54a96fed3e556a

View File

@ -1,6 +1,11 @@
idf_component_register(
SRCS "main.cpp" "wifi_provisioner.cpp" "clock_core.cpp"
INCLUDE_DIRS ""
REQUIRES nvs_flash esp_wifi esp_http_server etlcpp json
REQUIRES nvs_flash esp_wifi esp_http_server etlcpp json skullc
EMBED_FILES "${CMAKE_CURRENT_LIST_DIR}/static/index.html"
)
component_compile_definitions(
SKULLC_WITH_HAL
SKULLC_USE_HAL_ESP
)

View File

@ -5,9 +5,12 @@
#include "clock_core.hpp"
#include "esp_expected.hpp"
#include "clock_core_event.hpp"
#include "string_helpers.hpp"
#include <cstring>
#include <ctime>
#include <etl/string.h>
#include <esp_event.h>
#include <esp_log.h>
@ -15,21 +18,37 @@
#include <esp_netif_sntp.h>
#include <esp_wifi.h>
#include <peripherals_hal_esp.hpp>
namespace
{
const char* TAG = "clock_core";
constexpr EventBits_t WIFI_FAIL_BIT = BIT0;
constexpr EventBits_t WIFI_CONNECTED_BIT = BIT1;
constexpr EventBits_t SNTP_SYNCED_BIT = BIT2;
constexpr EventBits_t CLOCK_UPDATE_BIT = BIT3;
EventGroupHandle_t clock_core_event_group_;
struct Context
{
clock_core::EventGroup* events = nullptr;
Context(const Context&) = delete;
Context(Context&&) = delete;
Context& operator=(const Context&) = delete;
Context& operator=(Context&&) = delete;
static Context* getContext()
{
static Context ctx;
return &ctx;
}
private:
Context() = default;
};
void wifiEventHandler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
static int retry_num = 0;
auto* ctx = Context::getContext();
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
{
@ -45,7 +64,7 @@ void wifiEventHandler(void* arg, esp_event_base_t event_base,
}
else
{
xEventGroupSetBits(clock_core_event_group_, WIFI_FAIL_BIT);
ctx->events->setEvent(clock_core::EventGroup::WIFI_FAILED);
}
ESP_LOGW(TAG, "Connection to AP failed.");
}
@ -54,19 +73,20 @@ void wifiEventHandler(void* arg, esp_event_base_t event_base,
auto* event = static_cast<ip_event_got_ip_t*>(event_data);
ESP_LOGI(TAG, "Connected to AP. Got IP: " IPSTR, IP2STR(&event->ip_info.ip));
retry_num = 0;
xEventGroupSetBits(clock_core_event_group_, WIFI_CONNECTED_BIT);
ESP_LOGI(TAG, "FOLLOW: Events: %p, context: %p", ctx->events, ctx);
ctx->events->setEvent(clock_core::EventGroup::WIFI_CONNECTED);
}
}
void sntpEventHandler(struct timeval*)
{
xEventGroupSetBits(clock_core_event_group_, SNTP_SYNCED_BIT);
Context::getContext()->events->setEvent(clock_core::EventGroup::SNTP_SYNCED);
}
void timerEventHandler(TimerHandle_t)
void timerEventHandler(TimerHandle_t timer)
{
xEventGroupSetBits(clock_core_event_group_, CLOCK_UPDATE_BIT);
auto context = static_cast<Context*>(pvTimerGetTimerID(timer));
context->events->setEvent(clock_core::EventGroup::CLOCK_UPDATE);
}
esp_err_t sntpInitialize()
@ -98,12 +118,12 @@ std::expected<void, esp_err_t> wifiInitialize(const char* wifi_ssid, const char*
TRY_ESP(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&wifiEventHandler,
nullptr,
Context::getContext(),
&instance_any_id));
TRY_ESP(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&wifiEventHandler,
nullptr,
Context::getContext(),
&instance_got_ip));
wifi_sta_config_t sta_config;
@ -121,6 +141,22 @@ std::expected<void, esp_err_t> wifiInitialize(const char* wifi_ssid, const char*
return {};
}
etl::string<6> getCurrentTimeString()
{
std::time_t time_now;
std::tm time_info{};
std::time(&time_now);
localtime_r(&time_now, &time_info);
etl::string<6> buffer;
wrapUnsafeStringOps(buffer, [&time_info](char* string, const int available)
{
std::strftime(string, available, "%H:%M", &time_info);
});
return buffer;
}
}
namespace clock_core
@ -128,11 +164,14 @@ namespace clock_core
void run(const char* wifi_ssid, const char* wifi_password)
{
clock_core_event_group_ = xEventGroupCreate();
EventGroup events;
Context::getContext()->events = &events;
ESP_LOGI(TAG, "INITIAL: Events: %p, context: %p", &events, Context::getContext());
auto clock_timer = xTimerCreate("clock_core",
pdMS_TO_TICKS(60'000),
pdTRUE,
nullptr,
Context::getContext(),
timerEventHandler);
if (const auto res = wifiInitialize(wifi_ssid, wifi_password);
@ -144,13 +183,9 @@ void run(const char* wifi_ssid, const char* wifi_password)
while (true)
{
const EventBits_t bits = xEventGroupWaitBits(clock_core_event_group_,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT | SNTP_SYNCED_BIT | CLOCK_UPDATE_BIT,
pdTRUE,
pdFALSE,
portMAX_DELAY);
const EventBits_t bits = events.waitForEvent();
if (bits & WIFI_CONNECTED_BIT)
if (bits & EventGroup::WIFI_CONNECTED)
{
ESP_LOGI(TAG, "WiFi setup in clock_core::run successful.");
if (const auto res = esp_netif_sntp_start();
@ -162,24 +197,18 @@ void run(const char* wifi_ssid, const char* wifi_password)
xTimerStart(clock_timer, pdMS_TO_TICKS(10));
}
else if (bits & WIFI_FAIL_BIT)
else if (bits & EventGroup::WIFI_FAILED)
{
ESP_LOGE(TAG, "WiFi setup in clock_core::run failed.");
}
else if (bits & SNTP_SYNCED_BIT)
else if (bits & EventGroup::SNTP_SYNCED)
{
ESP_LOGI(TAG, "SNTP sync successful.");
}
else if (bits & CLOCK_UPDATE_BIT)
else if (bits & EventGroup::CLOCK_UPDATE)
{
char time_buf[64];
std::time_t time_now;
std::tm time_info;
std::time(&time_now);
localtime_r(&time_now, &time_info);
std::strftime(time_buf, sizeof(time_buf), "%c", &time_info);
ESP_LOGI(TAG, "Current time: %s", time_buf);
const auto time = getCurrentTimeString();
ESP_LOGI(TAG, "Current time: %s", time.c_str());
}
else
{

View File

@ -0,0 +1,45 @@
//
// Created by erki on 11/02/24.
//
#pragma once
#include <freertos/FreeRTOS.h>
namespace clock_core
{
struct EventGroup
{
static constexpr EventBits_t WIFI_FAILED = BIT0;
static constexpr EventBits_t WIFI_CONNECTED = BIT1;
static constexpr EventBits_t SNTP_SYNCED = BIT2;
static constexpr EventBits_t CLOCK_UPDATE = BIT3;
static constexpr EventBits_t ALL_EVENTS = WIFI_FAILED | WIFI_CONNECTED | SNTP_SYNCED | CLOCK_UPDATE;
EventGroupHandle_t rtos_event_group = nullptr;
EventGroup()
: rtos_event_group(xEventGroupCreate())
{ }
EventGroup(const EventGroup&) = delete;
EventGroup(EventGroup&&) = delete;
EventGroup& operator=(const EventGroup&) = delete;
EventGroup& operator=(EventGroup&&) = delete;
void setEvent(const EventBits_t& bits)
{
xEventGroupSetBits(rtos_event_group, bits);
}
EventBits_t waitForEvent()
{
return xEventGroupWaitBits(rtos_event_group,
ALL_EVENTS,
pdTRUE,
pdFALSE,
portMAX_DELAY);
}
};
}

View File

@ -0,0 +1,16 @@
//
// Created by erki on 16/02/24.
//
#pragma once
template<typename T, typename F>
auto wrapUnsafeStringOps(T& string, F&& operation)
{
string.initialize_free_space();
operation(string.data_end(), string.available());
string.trim_to_terminator();
return string;
}

View File

@ -88,7 +88,8 @@ esp_err_t rootPostHandler_(httpd_req_t* req)
};
etl::string<100> content_type;
if (const auto err = httpd_req_get_hdr_value_str(req, "Content-Type", content_type.data(), content_type.max_size() - 1);
content_type.initialize_free_space();
if (const auto err = httpd_req_get_hdr_value_str(req, "Content-Type", content_type.data_end(), content_type.available() - 1);
err != ESP_OK)
{
dispatch_error("Cannot parse header.");