SensESP 2.7.2
Universal Signal K sensor toolkit ESP32
Loading...
Searching...
No Matches
lambda_transform.h
Go to the documentation of this file.
1#ifndef _lambda_transform_H_
2#define _lambda_transform_H_
3
4#include "transform.h"
5
6namespace sensesp {
7
8// template snippets for configuration schema
9
10static const char kLambdaTransformSchemaHead[] PROGMEM = R"({
11 "type": "object",
12 "properties": {
13 )";
14
15static const char kLambdaTransformSchemaTail[] PROGMEM = R"(
16 }
17 })";
18
23// an unknown type may not be rendered in Json editor
24template <class T>
25const char* get_schema_type_string(const T dummy) {
26 return "unknown";
27}
28template <>
29const char* get_schema_type_string(const int dummy);
30
31template <>
32const char* get_schema_type_string(const float dummy);
33
34template <>
35const char* get_schema_type_string(const String dummy);
36
37template <>
38const char* get_schema_type_string(const bool dummy);
39
43struct ParamInfo {
44 const char* key;
45 const char* description;
46};
47
48// FIXME: This whole implementation should be written with variadic template
49// parameters once the SDK gets updated past GCC 5.2.
50
69template <class IN, class OUT, class P1 = bool, class P2 = bool,
70 class P3 = bool, class P4 = bool, class P5 = bool, class P6 = bool>
71class LambdaTransform : public Transform<IN, OUT> {
72 public:
73 LambdaTransform(std::function<OUT(IN)> function, String config_path = "")
74 : Transform<IN, OUT>(config_path), function0{function}, num_params{0} {
75 this->load_configuration();
76 }
77
78 LambdaTransform(std::function<OUT(IN)> function, const ParamInfo* param_info,
81 function0{function},
82 num_params{0},
83 param_info{param_info} {
84 this->load_configuration();
85 }
86
87 LambdaTransform(std::function<OUT(IN, P1)> function, P1 param1,
88 const ParamInfo* param_info, String config_path = "")
90 function1{function},
91 param1{param1},
92 num_params{1},
93 param_info{param_info} {
94 this->load_configuration();
95 }
96
110 LambdaTransform(std::function<OUT(IN, P1, P2)> function, P1 param1, P2 param2,
111 const ParamInfo* param_info, String config_path = "")
113 function2{function},
114 param1{param1},
115 param2{param2},
116 num_params{2},
117 param_info{param_info} {
118 this->load_configuration();
119 }
120
121 LambdaTransform(std::function<OUT(IN, P1, P2, P3)> function, P1 param1,
122 P2 param2, P3 param3, const ParamInfo* param_info,
123 String config_path = "")
125 function3{function},
126 param1{param1},
127 param2{param2},
128 param3{param3},
129 num_params{3},
130 param_info{param_info} {
131 this->load_configuration();
132 }
133
134 LambdaTransform(std::function<OUT(IN, P1, P2, P3, P4)> function, P1 param1,
135 P2 param2, P3 param3, P4 param4, const ParamInfo* param_info,
136 String config_path = "")
138 function4{function},
139 param1{param1},
140 param2{param2},
141 param3{param3},
142 param4{param4},
143 num_params{4},
144 param_info{param_info} {
145 this->load_configuration();
146 }
147
148 LambdaTransform(std::function<OUT(IN, P1, P2, P3, P4, P5)> function,
149 P1 param1, P2 param2, P3 param3, P4 param4, P5 param5,
150 const ParamInfo* param_info, String config_path = "")
152 function5{function},
153 param1{param1},
154 param2{param2},
155 param3{param3},
156 param4{param4},
157 param5{param5},
158 num_params{5},
159 param_info{param_info} {
160 this->load_configuration();
161 }
162
163 LambdaTransform(std::function<OUT(IN, P1, P2, P3, P4, P5, P6)> function,
164 P1 param1, P2 param2, P3 param3, P4 param4, P5 param5,
165 P6 param6, const ParamInfo* param_info,
166 String config_path = "")
168 function6{function},
169 param1{param1},
170 param2{param2},
171 param3{param3},
172 param4{param4},
173 param5{param5},
174 param6{param6},
175 num_params{6},
176 param_info{param_info} {
177 this->load_configuration();
178 }
179
180 void set_input(IN input, uint8_t input_channel = 0) override {
181 switch (num_params) {
182 case 0:
183 this->output = function0(input);
184 break;
185 case 1:
186 this->output = function1(input, param1);
187 break;
188 case 2:
189 this->output = function2(input, param1, param2);
190 break;
191 case 3:
192 this->output = function3(input, param1, param2, param3);
193 break;
194 case 4:
195 this->output = function4(input, param1, param2, param3, param4);
196 break;
197 case 5:
198 this->output = function5(input, param1, param2, param3, param4, param5);
199 break;
200 case 6:
201 this->output =
202 function6(input, param1, param2, param3, param4, param5, param6);
203 break;
204 default:
205 break;
206 }
208 }
209
211 switch (num_params) {
212 case 6:
213 doc[param_info[5].key] = param6;
214 case 5:
215 doc[param_info[4].key] = param5;
216 case 4:
217 doc[param_info[3].key] = param4;
218 case 3:
219 doc[param_info[2].key] = param3;
220 case 2:
221 doc[param_info[1].key] = param2;
222 case 1:
223 doc[param_info[0].key] = param1;
224 default:
225 break;
226 }
227 }
228
229 bool set_configuration(const JsonObject& config) override {
230 // test that each argument key (as defined by param_info)
231 // exists in the received Json object
232 debugD("Preparing to restore configuration from FS.");
233 for (int i = 0; i < num_params; i++) {
234 const char* expected = param_info[i].key;
235 if (!config.containsKey(expected)) {
236 debugD("Didn't find all keys.");
237 return false;
238 }
239 }
240 switch (num_params) {
241 case 6:
242 param6 = config[param_info[5].key];
243 case 5:
244 param5 = config[param_info[4].key];
245 case 4:
246 param4 = config[param_info[3].key];
247 case 3:
248 param3 = config[param_info[2].key];
249 case 2:
250 param2 = config[param_info[1].key];
251 case 1:
252 param1 = config[param_info[0].key];
253 default:
254 break;
255 }
256 debugD("Restored configuration");
257 return true;
258 }
259
261 // FIXME: The heavy use of Strings puts a lot of faith in that class's
262 // ability to not leak or corrupt memory. Would be better to receive
263 // a character array pointer as an argument for writing the output to.
264 String output = "";
265
266 debugD("Preparing config schema");
267
269 if (num_params > 0) {
270 debugD("getting param_info:");
271 debugD("%s -> %s", param_info[0].key, param_info[0].description);
272 output.concat(format_schema_row(param_info[0].key,
273 param_info[0].description,
274 get_schema_type_string(param1), false));
275 }
276 if (num_params > 1) {
277 output.concat(",");
278 output.concat(format_schema_row(param_info[1].key,
279 param_info[1].description,
280 get_schema_type_string(param2), false));
281 }
282 if (num_params > 2) {
283 output.concat(",");
284 output.concat(format_schema_row(param_info[2].key,
285 param_info[2].description,
286 get_schema_type_string(param3), false));
287 }
288 if (num_params > 3) {
289 output.concat(",");
290 output.concat(format_schema_row(param_info[3].key,
291 param_info[3].description,
292 get_schema_type_string(param4), false));
293 }
294 if (num_params > 4) {
295 output.concat(",");
296 output.concat(format_schema_row(param_info[4].key,
297 param_info[4].description,
298 get_schema_type_string(param5), false));
299 }
300 if (num_params > 5) {
301 output.concat(",");
302 output.concat(format_schema_row(param_info[5].key,
303 param_info[5].description,
304 get_schema_type_string(param6), false));
305 }
307
308 debugD("Prepared config schema.");
309
310 return output;
311 }
312
313 private:
314 P1 param1;
315 P2 param2;
316 P3 param3;
317 P4 param4;
318 P5 param5;
319 P6 param6;
320 int num_params;
321 const ParamInfo* param_info;
322
323 std::function<OUT(IN)> function0;
324 std::function<OUT(IN, P1)> function1;
325 std::function<OUT(IN, P1, P2)> function2;
326 std::function<OUT(IN, P1, P2, P3)> function3;
327 std::function<OUT(IN, P1, P2, P3, P4)> function4;
328 std::function<OUT(IN, P1, P2, P3, P4, P5)> function5;
329 std::function<OUT(IN, P1, P2, P3, P4, P5, P6)> function6;
330
331 static String format_schema_row(const char key[], const char title[],
332 const char type[], const bool read_only) {
333 char row[100] = "";
334 const char* read_only_str = read_only ? "true" : "false";
335
336 static const char schema_row[] = R"(
337 "%s": { "title": "%s", "type": "%s", "readOnly": %s }
338 )";
339
341
342 return String(row);
343 }
344};
345
346} // namespace sensesp
347
348#endif
virtual void load_configuration()
Construct a new transform based on a single function.
void set_input(IN input, uint8_t input_channel=0) override
bool set_configuration(const JsonObject &config) override
LambdaTransform(std::function< OUT(IN)> function, String config_path="")
LambdaTransform(std::function< OUT(IN, P1, P2, P3, P4, P5)> function, P1 param1, P2 param2, P3 param3, P4 param4, P5 param5, const ParamInfo *param_info, String config_path="")
LambdaTransform(std::function< OUT(IN, P1, P2)> function, P1 param1, P2 param2, const ParamInfo *param_info, String config_path="")
LambdaTransform constructor for two-parameter function.
LambdaTransform(std::function< OUT(IN, P1, P2, P3, P4)> function, P1 param1, P2 param2, P3 param3, P4 param4, const ParamInfo *param_info, String config_path="")
LambdaTransform(std::function< OUT(IN)> function, const ParamInfo *param_info, String config_path="")
LambdaTransform(std::function< OUT(IN, P1, P2, P3)> function, P1 param1, P2 param2, P3 param3, const ParamInfo *param_info, String config_path="")
LambdaTransform(std::function< OUT(IN, P1, P2, P3, P4, P5, P6)> function, P1 param1, P2 param2, P3 param3, P4 param4, P5 param5, P6 param6, const ParamInfo *param_info, String config_path="")
LambdaTransform(std::function< OUT(IN, P1)> function, P1 param1, const ParamInfo *param_info, String config_path="")
void get_configuration(JsonObject &doc) override
String get_config_schema() override
The main Transform class. A transform is identified primarily by the type of value that is produces (...
Definition transform.h:54
const uint8_t PAGE_css_bootstrap[] PROGMEM
#define debugD(fmt,...)
Definition local_debug.h:47
const char * get_schema_type_string(const int dummy)
const char * description