Firmware  0.4.1
Loading...
Searching...
No Matches
utility.hpp
Go to the documentation of this file.
1// Copyright (C) 2025 Vincent Hamp
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program. If not, see <https://www.gnu.org/licenses/>.
15
21
22#pragma once
23
24#include <esp_heap_caps.h>
25#include <bit>
26#include <charconv>
27#include <dcc/dcc.hpp>
28#include <functional>
29#include <iterator>
30#include <memory>
31#include <numeric>
32#include <span>
33#include <string_view>
34#include "intf/http/message.hpp"
35#include "log.h"
36
38
39bool validate_json(std::string_view json);
40
41// https://stackoverflow.com/questions/81870/is-it-possible-to-print-a-variables-type-in-standard-c
42template<typename T>
43consteval std::string_view type_name() {
44 using namespace std;
45#if defined(__clang__)
46 string_view p{__PRETTY_FUNCTION__};
47 return string_view(data(p) + 34, size(p) - 34 - 1);
48#elif defined(__GNUC__)
49 string_view p{__PRETTY_FUNCTION__};
50# if __cplusplus < 201402
51 return string_view(data(p) + 36, size(p) - 36 - 1);
52# else
53 return string_view(data(p) + 49, p.find(';', 49) - 49);
54# endif
55#elif defined(_MSC_VER)
56 string_view p{__FUNCSIG__};
57 return string_view(data(p) + 84, size(p) - 84 - 7);
58#endif
59}
60
61std::optional<dcc::Address::value_type> uri2address(std::string_view uri);
62
63std::optional<dcc::Address> uri2loco_address(std::string_view uri);
64
66template<std::output_iterator<char> OutputIt>
67OutputIt decode_uri(std::string_view uri, OutputIt out) {
68 auto first{begin(uri)};
69 auto const last{cend(uri)};
70 while (first < last) {
71 auto c{*first++};
72 if (c == '+') c = ' ';
73 else if (c == '%') {
74 std::from_chars(first, first + 2, c, 16);
75 first += 2;
76 }
77 *out++ = c;
78 }
79 return out;
80}
81
83template<typename T>
84using unique_caps_ptr = std::unique_ptr<T, decltype(heap_caps_free)*>;
85
87template<typename T>
88constexpr auto make_unique_caps(size_t size, uint32_t caps) {
89 return unique_caps_ptr<T>{std::bit_cast<T*>(heap_caps_malloc(size, caps)),
90 heap_caps_free};
91}
92
95
97template<typename F, typename... Ts>
98auto invoke_on_core(BaseType_t core_id, F&& f, Ts&&... ts) {
99 using R = decltype(f(std::forward<Ts>(ts)...));
100
101 // Pinned and current core are the same
102 if (core_id == xPortGetCoreID())
103 return std::invoke(std::forward<F>(f), std::forward<Ts>(ts)...);
104 // Pinned core is different, return type is void
105 else if constexpr (constexpr auto default_stacksize{4096uz};
106 std::is_void_v<R>) {
107 // Create tuple to pass to task
108 std::tuple<F, std::tuple<Ts...>> t{
109 std::forward<F>(f), std::tuple<Ts...>{std::forward<Ts>(ts)...}};
110
111 // Create task and wait for it's deletion
112 TaskHandle_t handle;
113 if (!xTaskCreatePinnedToCore(
114 [](void* pv) {
115 auto& _t{*static_cast<decltype(t)*>(pv)};
116 std::apply(std::get<0uz>(_t), std::get<1uz>(_t));
117 vTaskDelete(NULL);
118 },
119 NULL,
120 default_stacksize,
121 &t,
122 ESP_TASK_PRIO_MAX - 1u,
123 &handle,
124 core_id))
125 assert(false);
126 while (eTaskGetState(handle) < eDeleted) vTaskDelay(1u);
127 }
128 // Pinned core is different, return type isn't void
129 else {
130 // Create tuple to pass to task
131 std::tuple<R, F, std::tuple<Ts...>> t{
132 {}, std::forward<F>(f), std::tuple<Ts...>{std::forward<Ts>(ts)...}};
133
134 // Create task and wait for it's deletion
135 TaskHandle_t handle;
136 if (!xTaskCreatePinnedToCore(
137 [](void* pv) {
138 auto& _t{*static_cast<decltype(t)*>(pv)};
139 std::get<0uz>(_t) =
140 std::apply(std::get<1uz>(_t), std::get<2uz>(_t));
141 vTaskDelete(NULL);
142 },
143 NULL,
144 default_stacksize,
145 &t,
146 ESP_TASK_PRIO_MAX - 1u,
147 &handle,
148 core_id))
149 assert(false);
150 while (eTaskGetState(handle) < eDeleted) vTaskDelay(1u);
151
152 return std::get<0uz>(t);
153 }
154}
155
157template<typename... Ts>
158auto httpd_sess_trigger_close(Ts&&... ts) {
159 return httpd_sess_trigger_close(intf::http::handle, std::forward<Ts>(ts)...);
160}
161
164 return httpd_queue_work(
166 [](void* arg) {
167 auto msg{std::bit_cast<intf::http::Message*>(arg)};
168
169 // Wrap message in httpd_ws_frame_t
170 httpd_ws_frame_t frame{
171 .type = msg->type,
172 .payload = data(msg->payload),
173 .len = size(msg->payload),
174 };
175 if (auto const err{httpd_ws_send_frame_async(
176 intf::http::handle, msg->sock_fd, &frame)})
177 LOGD("httpd_ws_send_frame_async failed %s", esp_err_to_name(err));
178
179 // Delete
180 delete msg;
181 },
182 msg);
183}
Log macros.
#define LOGD(...)
Definition log.h:46
HTTP websocket message.
httpd_handle_t handle
Handle to server instance.
Definition config.hpp:445
Definition message.hpp:29
httpd_ws_type_t type
Definition message.hpp:31
int sock_fd
Definition message.hpp:30
std::vector< uint8_t > payload
Definition message.hpp:32
std::optional< dcc::Address > uri2loco_address(std::string_view uri)
Definition utility.cpp:62
void esp_delayed_restart()
Definition utility.cpp:38
bool validate_json(std::string_view json)
Definition utility.cpp:44
auto httpd_sess_trigger_close(Ts &&... ts)
Definition utility.hpp:158
constexpr auto make_unique_caps(size_t size, uint32_t caps)
Definition utility.hpp:88
auto httpd_queue_work(intf::http::Message *msg)
Definition utility.hpp:163
uint32_t http_receive_timeout2ms()
Definition utility.cpp:72
OutputIt decode_uri(std::string_view uri, OutputIt out)
https://rosettacode.org/wiki/URL_decoding#C
Definition utility.hpp:67
std::unique_ptr< T, decltype(heap_caps_free) * > unique_caps_ptr
Definition utility.hpp:84
consteval std::string_view type_name()
Definition utility.hpp:43
std::optional< dcc::Address::value_type > uri2address(std::string_view uri)
Definition utility.cpp:51
auto invoke_on_core(BaseType_t core_id, F &&f, Ts &&... ts)
Definition utility.hpp:98