Firmware  0.0.0
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
35template<typename>
36struct signature;
37
38template<typename R, typename... Args>
39struct signature<std::function<R(Args...)>> {
40 using type = R(Args...);
41 using return_type = R;
42 using args = std::tuple<Args...>;
43};
44
45template<typename R, typename T, typename... Args>
46struct signature<R (T::*)(Args...)> {
47 using type = R(Args...);
48 using return_type = R;
49 using args = std::tuple<Args...>;
50};
51
52template<[[maybe_unused]] auto Unique = [] {}, typename F>
53auto make_tramp(F&& f) {
54 using Args =
55 typename signature<decltype(std::function{std::declval<F>()})>::args;
56 static auto _f{f};
57 return []<size_t... Is>(std::index_sequence<Is...>) {
58 return [](std::tuple_element_t<Is, Args>... args) {
59 return std::invoke(_f, std::forward<decltype(args)>(args)...);
60 };
61 }(std::make_index_sequence<std::tuple_size_v<Args>>{});
62}
63
64template<[[maybe_unused]] auto Unique = [] {}, typename Self, typename F>
65auto make_tramp(Self&& self, F&& f) {
66 using Args = typename signature<F>::args;
67 static auto _self{self};
68 static auto _f{f};
69 return []<size_t... Is>(std::index_sequence<Is...>) {
70 return [](std::tuple_element_t<Is, Args>... args) {
71 return std::invoke(_f, _self, std::forward<decltype(args)>(args)...);
72 };
73 }(std::make_index_sequence<std::tuple_size_v<Args>>{});
74}
75
77
78bool validate_json(std::string_view json);
79
80// https://stackoverflow.com/questions/81870/is-it-possible-to-print-a-variables-type-in-standard-c
81template<typename T>
82consteval std::string_view type_name() {
83 using namespace std;
84#if defined(__clang__)
85 string_view p{__PRETTY_FUNCTION__};
86 return string_view(data(p) + 34, size(p) - 34 - 1);
87#elif defined(__GNUC__)
88 string_view p{__PRETTY_FUNCTION__};
89# if __cplusplus < 201402
90 return string_view(data(p) + 36, size(p) - 36 - 1);
91# else
92 return string_view(data(p) + 49, p.find(';', 49) - 49);
93# endif
94#elif defined(_MSC_VER)
95 string_view p{__FUNCSIG__};
96 return string_view(data(p) + 84, size(p) - 84 - 7);
97#endif
98}
99
100namespace detail {
101
102template<std::unsigned_integral T>
103constexpr T prime{sizeof(T) <= 4uz ? 16777619ull : 1099511628211ull};
104
105template<std::unsigned_integral T>
106constexpr T offset{sizeof(T) <= 4uz ? 2166136261ull : 14695981039346656037ull};
107
108} // namespace detail
109
110// http://www.isthe.com/chongo/tech/comp/fnv/index.html
111template<std::unsigned_integral T = uint32_t>
112constexpr T fnv1a(uint8_t byte, T hash = ::detail::offset<T>) {
113 return (hash ^ byte) * ::detail::prime<T>;
114}
115
116template<std::unsigned_integral T = uint32_t>
117constexpr T fnv1a(std::span<char const> str) {
118 return std::accumulate(cbegin(str),
119 cend(str),
121 [](T a, char b) { return fnv1a(b, a); });
122}
123
124std::optional<dcc::Address::value_type> uri2address(std::string_view uri);
125
126std::optional<dcc::Address> uri2loco_address(std::string_view uri);
127
129template<std::output_iterator<char> OutputIt>
130OutputIt decode_uri(std::string_view uri, OutputIt out) {
131 auto first{begin(uri)};
132 auto const last{cend(uri)};
133 while (first < last) {
134 auto c{*first++};
135 if (c == '+') c = ' ';
136 else if (c == '%') {
137 std::from_chars(first, first + 2, c, 16);
138 first += 2;
139 }
140 *out++ = c;
141 }
142 return out;
143}
144
146template<typename T>
147using unique_caps_ptr = std::unique_ptr<T, decltype(heap_caps_free)*>;
148
150template<typename T>
151constexpr auto make_unique_caps(size_t size, uint32_t caps) {
152 return unique_caps_ptr<T>{std::bit_cast<T*>(heap_caps_malloc(size, caps)),
153 heap_caps_free};
154}
155
157uint32_t http_receive_timeout2ms();
158
160template<typename F, typename... Ts>
161auto invoke_on_core(BaseType_t core_id, F&& f, Ts&&... ts) {
162 using R = decltype(f(std::forward<Ts>(ts)...));
163
164 // Pinned and current core are the same
165 if (core_id == xPortGetCoreID())
166 return std::invoke(std::forward<F>(f), std::forward<Ts>(ts)...);
167 // Pinned core is different, return type is void
168 else if constexpr (constexpr auto default_stacksize{4096uz};
169 std::is_void_v<R>) {
170 // Create tuple to pass to task
171 std::tuple<F, std::tuple<Ts...>> t{
172 std::forward<F>(f), std::tuple<Ts...>{std::forward<Ts>(ts)...}};
173
174 // Create task and wait for it's deletion
175 TaskHandle_t handle;
176 if (!xTaskCreatePinnedToCore(
177 [](void* pv) {
178 auto& _t{*static_cast<decltype(t)*>(pv)};
179 std::apply(std::get<0uz>(_t), std::get<1uz>(_t));
180 vTaskDelete(NULL);
181 },
182 NULL,
183 default_stacksize,
184 &t,
185 ESP_TASK_PRIO_MAX - 1u,
186 &handle,
187 core_id))
188 assert(false);
189 while (eTaskGetState(handle) < eDeleted) vTaskDelay(1u);
190 }
191 // Pinned core is different, return type isn't void
192 else {
193 // Create tuple to pass to task
194 std::tuple<R, F, std::tuple<Ts...>> t{
195 {}, std::forward<F>(f), std::tuple<Ts...>{std::forward<Ts>(ts)...}};
196
197 // Create task and wait for it's deletion
198 TaskHandle_t handle;
199 if (!xTaskCreatePinnedToCore(
200 [](void* pv) {
201 auto& _t{*static_cast<decltype(t)*>(pv)};
202 std::get<0uz>(_t) =
203 std::apply(std::get<1uz>(_t), std::get<2uz>(_t));
204 vTaskDelete(NULL);
205 },
206 NULL,
207 default_stacksize,
208 &t,
209 ESP_TASK_PRIO_MAX - 1u,
210 &handle,
211 core_id))
212 assert(false);
213 while (eTaskGetState(handle) < eDeleted) vTaskDelay(1u);
214
215 return std::get<0uz>(t);
216 }
217}
218
220template<typename... Ts>
222 return httpd_ws_send_frame_async(http::handle, std::forward<Ts>(ts)...);
223}
224
226template<typename... Ts>
227auto httpd_sess_trigger_close(Ts&&... ts) {
228 return httpd_sess_trigger_close(http::handle, std::forward<Ts>(ts)...);
229}
Definition utility.hpp:100
constexpr T offset
Definition utility.hpp:106
constexpr T prime
Definition utility.hpp:103
httpd_handle_t handle
Handle to server instance.
Definition config.hpp:302
Definition config.hpp:358
R(Args...) type
Definition utility.hpp:47
R return_type
Definition utility.hpp:48
std::tuple< Args... > args
Definition utility.hpp:49
std::tuple< Args... > args
Definition utility.hpp:42
R(Args...) type
Definition utility.hpp:40
R return_type
Definition utility.hpp:41
Definition utility.hpp:36
std::optional< dcc::Address > uri2loco_address(std::string_view uri)
Definition utility.cpp:62
auto httpd_ws_send_frame_async(Ts &&... ts)
Definition utility.hpp:221
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:227
constexpr auto make_unique_caps(size_t size, uint32_t caps)
Definition utility.hpp:151
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:130
auto make_tramp(F &&f)
Definition utility.hpp:53
std::unique_ptr< T, decltype(heap_caps_free) * > unique_caps_ptr
Definition utility.hpp:147
consteval std::string_view type_name()
Definition utility.hpp:82
std::optional< dcc::Address::value_type > uri2address(std::string_view uri)
Definition utility.cpp:51
constexpr T fnv1a(uint8_t byte, T hash=::detail::offset< T >)
Definition utility.hpp:112
auto invoke_on_core(BaseType_t core_id, F &&f, Ts &&... ts)
Definition utility.hpp:161