-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathpybind_espp.cpp
More file actions
3814 lines (3684 loc) · 268 KB
/
Copy pathpybind_espp.cpp
File metadata and controls
3814 lines (3684 loc) · 268 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include <chrono>
#include <memory>
#include <string>
#include <system_error>
#include <vector>
#include <pybind11/chrono.h>
#include <pybind11/functional.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "span_caster.h"
#include "espp.hpp"
namespace py = pybind11;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AUTOGENERATED CODE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// <litgen_glue_code> // Autogenerated code below! Do not edit!
// </litgen_glue_code> // Autogenerated code end
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AUTOGENERATED CODE END !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
void py_init_module_espp(py::module &m) {
// using namespace espp; // NON!
// create an Error class which is really just std::error_code
py::class_<std::error_code>(
m, "Error", py::module_local()) // should be module_local so other modules can have
// std::error_code if they need to
.def(py::init<>())
.def("__repr__",
[](const std::error_code &self) { return fmt::format("Error({})", self.message()); })
.def("__bool__", [](const std::error_code &self) { return bool(self); });
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AUTOGENERATED CODE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// <litgen_pydef> // Autogenerated code below! Do not edit!
//////////////////// <generated_from:base_component.hpp> ////////////////////
auto pyClassBaseComponent =
py::class_<espp::BaseComponent>(m, "BaseComponent", py::dynamic_attr(),
"/ Base class for all components\n/ Provides a logger and "
"some basic logging configuration")
.def("get_name", &espp::BaseComponent::get_name,
"/ Get the name of the component\n/ \\return A const reference to the name of the "
"component\n/ \note This is the tag of the logger")
.def("set_log_tag", &espp::BaseComponent::set_log_tag, py::arg("tag"),
"/ Set the tag for the logger\n/ \\param tag The tag to use for the logger")
.def("get_log_level", &espp::BaseComponent::get_log_level,
"/ Get the log level for the logger\n/ \\return The verbosity level of the "
"logger\n/ \\sa Logger::Verbosity\n/ \\sa Logger::set_verbosity")
.def("set_log_level", &espp::BaseComponent::set_log_level, py::arg("level"),
"/ Set the log level for the logger\n/ \\param level The verbosity level to use for "
"the logger\n/ \\sa Logger::Verbosity\n/ \\sa Logger::set_verbosity")
.def("set_log_verbosity", &espp::BaseComponent::set_log_verbosity, py::arg("level"),
"/ Set the log verbosity for the logger\n/ \\param level The verbosity level to use "
"for the logger\n/ \note This is a convenience method that calls set_log_level\n/ "
"\\sa set_log_level\n/ \\sa Logger::Verbosity\n/ \\sa Logger::set_verbosity")
.def("get_log_verbosity", &espp::BaseComponent::get_log_verbosity,
"/ Get the log verbosity for the logger\n/ \\return The verbosity level of the "
"logger\n/ \note This is a convenience method that calls get_log_level\n/ \\sa "
"get_log_level\n/ \\sa Logger::Verbosity\n/ \\sa Logger::get_verbosity")
.def("set_log_rate_limit", &espp::BaseComponent::set_log_rate_limit,
py::arg("rate_limit"),
"/ Set the rate limit for the logger\n/ \\param rate_limit The rate limit to use "
"for the logger\n/ \note Only calls to the logger that have _rate_limit suffix will "
"be rate limited\n/ \\sa Logger::set_rate_limit");
//////////////////// </generated_from:base_component.hpp> ////////////////////
//////////////////// <generated_from:cobs.hpp> ////////////////////
auto pyClassCobs =
py::class_<espp::Cobs>(
m, "Cobs", py::dynamic_attr(),
"*\n * @brief COBS (Consistent Overhead Byte Stuffing) encoder/decoder\n *\n * Provides "
"single-packet encoding and decoding using the COBS algorithm\n * with 0 as the "
"delimiter.\n * COBS encoding can add at most ceil(n/254) + 1 bytes overhead, plus 1 "
"byte\n * for the delimiter.\n * COBS changes the size of the packet by at least 1 byte, "
"so it's not possible to encode in\n * place. MAX_BLOCK_SIZE = 254 is the maximum number "
"of non-zero bytes in an encoded block.\n *\n * @see "
"https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing\n")
.def(py::init<>()) // implicit default constructor
.def_static("max_encoded_size", &espp::Cobs::max_encoded_size, py::arg("payload_len"),
"*\n * @brief Calculate maximum encoded size for a given payload length\n "
" *\n * @param payload_len Length of input data\n * @return Maximum "
"number of bytes needed for encoding (including delimiter)\n")
.def_static("encode_packet",
py::overload_cast<std::span<const uint8_t>>(&espp::Cobs::encode_packet),
py::arg("data"),
"*\n * @brief Encode a single packet\n *\n * @param data Input data to "
"encode\n * @return Encoded data with COBS encoding and delimiter\n")
.def_static(
"encode_packet",
py::overload_cast<std::span<const uint8_t>, std::span<uint8_t>>(
&espp::Cobs::encode_packet),
py::arg("data"), py::arg("output"),
"*\n * @brief Encode a single packet to existing buffer\n *\n * @param data "
"Input data to encode\n * @param output Output buffer span (must be at least "
"max_encoded_size)\n * @return Number of bytes written to output\n")
.def_static("max_decoded_size", &espp::Cobs::max_decoded_size, py::arg("encoded_len"),
"*\n * @brief Calculate maximum decoded size for a given encoded length\n "
" *\n * @param encoded_len Length of COBS-encoded data\n * @return "
"Maximum number of bytes needed for decoding (accounts for delimiter)\n")
.def_static("decode_packet",
py::overload_cast<std::span<const uint8_t>>(&espp::Cobs::decode_packet),
py::arg("encoded_data"),
"*\n * @brief Decode a single packet from COBS-encoded data\n *\n * "
"@param encoded_data COBS-encoded data\n * @return Decoded packet data, or "
"empty if invalid\n")
.def_static("decode_packet",
py::overload_cast<std::span<const uint8_t>, std::span<uint8_t>>(
&espp::Cobs::decode_packet),
py::arg("encoded_data"), py::arg("output"),
"*\n * @brief Decode a single packet to existing buffer\n *\n * @param "
"encoded_data COBS-encoded data\n * @param output Output buffer span (must "
"be at least max_decoded_size)\n * @return Number of bytes written to "
"output, or 0 if decoding failed\n");
//////////////////// </generated_from:cobs.hpp> ////////////////////
//////////////////// <generated_from:cobs_stream.hpp> ////////////////////
auto pyClassCobsStreamDecoder =
py::class_<espp::CobsStreamDecoder>(
m, "CobsStreamDecoder", py::dynamic_attr(),
"*\n * @brief Streaming decoder for multiple COBS-encoded packets\n *\n * Useful for "
"processing incoming data streams where packets may arrive\n * in fragments or multiple "
"packets may arrive together.\n")
.def(py::init<>())
.def("add_data",
py::overload_cast<std::span<const uint8_t>>(&espp::CobsStreamDecoder::add_data),
py::arg("data"),
"*\n * @brief Add encoded data to the decoder buffer\n *\n * @param data New "
"encoded data span\n")
.def("add_data",
py::overload_cast<std::vector<uint8_t> &&>(&espp::CobsStreamDecoder::add_data),
py::arg("data"),
"*\n * @brief Add encoded data to the decoder buffer (move semantics)\n *\n * "
"@param data New encoded data vector (will be moved)\n")
.def("extract_packet", &espp::CobsStreamDecoder::extract_packet,
"*\n * @brief Try to extract the next complete packet. Removes the extracted data "
"from the buffer.\n *\n * @return Decoded packet data, or empty if no complete "
"packet found\n")
.def("remaining_data", &espp::CobsStreamDecoder::remaining_data,
"*\n * @brief Access remaining unprocessed data for debug purposes\n *\n * "
"@return Const reference to buffered data that hasn't been processed yet\n")
.def("buffer_size", &espp::CobsStreamDecoder::buffer_size,
"*\n * @brief Get the size of buffered data\n *\n * @return Number of bytes "
"currently buffered\n")
.def("clear", &espp::CobsStreamDecoder::clear,
"*\n * @brief Clear all buffered data\n");
auto pyClassCobsStreamEncoder =
py::class_<espp::CobsStreamEncoder>(
m, "CobsStreamEncoder", py::dynamic_attr(),
"*\n * @brief Streaming encoder for multiple packets\n *\n * Useful for batching "
"multiple packets together for transmission\n * or for building up data to send in "
"chunks.\n")
.def(py::init<>())
.def("add_packet",
py::overload_cast<std::span<const uint8_t>>(&espp::CobsStreamEncoder::add_packet),
py::arg("data"),
"*\n * @brief Add a packet to be encoded\n *\n * @param data Packet data "
"span\n")
.def("add_packet",
py::overload_cast<std::vector<uint8_t> &&>(&espp::CobsStreamEncoder::add_packet),
py::arg("data"),
"*\n * @brief Add a packet to be encoded (move semantics)\n *\n * @param data "
"Packet data vector (will be moved)\n")
.def("get_encoded_data", &espp::CobsStreamEncoder::get_encoded_data,
"*\n * @brief Get all encoded data as a single buffer for debug purposes\n *\n "
" * @return All encoded packets concatenated, const reference\n")
.def("extract_data", py::overload_cast<size_t>(&espp::CobsStreamEncoder::extract_data),
py::arg("max_size"),
"*\n * @brief Extract encoded data up to a maximum size\n *\n * @param "
"max_size Maximum number of bytes to extract\n * @return Encoded data up to "
"max_size bytes\n")
.def("extract_data",
py::overload_cast<uint8_t *, size_t>(&espp::CobsStreamEncoder::extract_data),
py::arg("output"), py::arg("max_size"),
"*\n * @brief Extract encoded data directly to a buffer\n *\n * @param output "
"Output buffer to write data to\n * @param max_size Maximum number of bytes to "
"extract\n * @return Number of bytes actually written to output\n")
.def("buffer_size", &espp::CobsStreamEncoder::buffer_size,
"*\n * @brief Get the current buffer size\n *\n * @return Number of bytes "
"currently buffered\n")
.def("clear", &espp::CobsStreamEncoder::clear,
"*\n * @brief Clear all buffered data\n");
//////////////////// </generated_from:cobs_stream.hpp> ////////////////////
//////////////////// <generated_from:color.hpp> ////////////////////
auto pyClassRgb =
py::class_<espp::Rgb>(m, "Rgb", py::dynamic_attr(),
"*\n * @brief Class representing a color using RGB color space.\n")
.def_readwrite("r", &espp::Rgb::r, "/< Red value in [0, 1]")
.def_readwrite("g", &espp::Rgb::g, "/< Green value in [0, 1]")
.def_readwrite("b", &espp::Rgb::b, "/< Blue value in [0, 1]")
.def(py::init<>())
.def(py::init<const float &, const float &, const float &>(), py::arg("r"), py::arg("g"),
py::arg("b"),
"*\n * @brief Construct an Rgb object from the provided rgb values.\n * @note "
"If provided values outside the range [0,1], it will rescale them to\n * be "
"within the range [0,1] by dividing by 255.\n * @param r Floating point value for "
"the red channel, should be in range [0,\n * 1]\n * @param g Floating "
"point value for the green channel, should be in range\n * [0, 1]\n * "
"@param b Floating point value for the blue channel, should be in range\n * "
" [0, 1]\n")
.def(py::init<const espp::Rgb &>(), py::arg("rgb"),
"*\n * @brief Copy-construct an Rgb object from the provided object.\n * @note "
"If provided values outside the range [0,1], it will rescale them to\n * be "
"within the range [0,1] by dividing by 255.\n * @param rgb Rgb struct containing "
"the values to copy.\n")
.def(py::init<const espp::Hsv &>(), py::arg("hsv"),
"*\n * @brief Construct an Rgb object from the provided Hsv object.\n * @note "
"This calls hsv.rgb() on the provided object, which means that invalid\n * "
"HSV data (not in the ranges [0,360], [0,1], and [0,1]) could lead to\n * "
"bad RGB data. The Rgb constructor will automatically convert the\n * "
"values to be in the proper range, but the perceived color will be\n * "
"changed.\n * @param hsv Hsv object to copy.\n")
.def(py::init<const uint32_t &>(), py::arg("hex"),
"*\n * @brief Construct an Rgb object from the provided hex value.\n * @param "
"hex Hex value to convert to RGB. The hex value should be in the\n * "
"format 0xRRGGBB.\n")
.def("__add__", &espp::Rgb::operator+, py::arg("rhs"),
"*\n * @brief Perform additive color blending (averaging)\n * @param rhs Other "
"color to add to this color to create the resultant color\n * @return Resultant "
"color from blending this color with the \\p rhs color.\n")
.def("__iadd__", &espp::Rgb::operator+=, py::arg("rhs"),
"*\n * @brief Perform additive color blending (averaging)\n * @param rhs Other "
"color to add to this color\n")
.def("__eq__", &espp::Rgb::operator==, py::arg("rhs"))
.def("__ne__", &espp::Rgb::operator!=, py::arg("rhs"))
.def("hsv", &espp::Rgb::hsv,
"*\n * @brief Get a HSV representation of this RGB color.\n * @return An HSV "
"object containing the HSV representation.\n")
.def("hex", &espp::Rgb::hex,
"*\n * @brief Get the hex representation of this RGB color.\n * @return The hex "
"representation of this RGB color.\n");
auto pyClassHsv =
py::class_<espp::Hsv>(m, "Hsv", py::dynamic_attr(),
"*\n * @brief Class representing a color using HSV color space.\n")
.def_readwrite("h", &espp::Hsv::h, "/< Hue in [0, 360]")
.def_readwrite("s", &espp::Hsv::s, "/< Saturation in [0, 1]")
.def_readwrite("v", &espp::Hsv::v, "/< Value in [0, 1]")
.def(py::init<>())
.def(py::init<const float &, const float &, const float &>(), py::arg("h"), py::arg("s"),
py::arg("v"),
"*\n * @brief Construct a Hsv object from the provided values.\n * @param h Hue "
"- will be clamped to be in range [0, 360]\n * @param s Saturation - will be "
"clamped to be in range [0, 1]\n * @param v Value - will be clamped to be in "
"range [0, 1]\n")
.def(py::init<const espp::Hsv &>(), py::arg("hsv"),
"*\n * @brief Copy-construct the Hsv object\n * @param hsv Object to copy "
"from.\n")
.def(py::init<const espp::Rgb &>(), py::arg("rgb"),
"*\n * @brief Construct Hsv object from Rgb object. Calls rgb.hsv() to perform\n "
" * the conversion.\n * @param rgb The Rgb object to convert and copy.\n")
.def("__eq__", &espp::Hsv::operator==, py::arg("rhs"))
.def("__ne__", &espp::Hsv::operator!=, py::arg("rhs"))
.def("rgb", &espp::Hsv::rgb,
"*\n * @brief Get a RGB representation of this HSV color.\n * @return An RGB "
"object containing the RGB representation.\n");
m.def("color_code", py::overload_cast<const espp::Rgb &>(espp::color_code), py::arg("rgb"),
"\n(C++ auto return type)");
m.def("color_code", py::overload_cast<const espp::Hsv &>(espp::color_code), py::arg("hsv"),
"\n(C++ auto return type)");
//////////////////// </generated_from:color.hpp> ////////////////////
//////////////////// <generated_from:event_manager.hpp> ////////////////////
auto pyClassEventManager =
py::class_<espp::EventManager>(
m, "EventManager", py::dynamic_attr(),
"*\n * @brief Singleton class for managing events. Provides mechanisms for\n * "
"anonymous publish / subscribe interactions - enabling one to one,\n * one to "
"many, many to one, and many to many data distribution with\n * loose coupling "
"and low overhead. Each topic runs a thread for that\n * topic's subscribers, "
"executing all the callbacks in sequence and\n * then going to sleep again until "
"new data is published.\n *\n * @note In c++ objects, it's recommended to call the\n * "
" add_publisher/add_subscriber functions in the class constructor and\n * then "
"to call the remove_publisher/remove_subscriber functions in the\n * class "
"destructor.\n *\n * @note It is recommended (unless you are only interested in events "
"and not\n * data or are only needing to transmit actual strings) to use a\n * "
" serialization library (such as espp::serialization - which wraps\n * alpaca) to "
"serialize your data structures to string when publishing\n * and then deserialize "
"your data from string in the subscriber\n * callbacks.\n *\n * \\section "
"event_manager_ex1 Event Manager Example\n * \\snippet event_manager_example.cpp event "
"manager example\n")
.def_static("get", &espp::EventManager::get,
"*\n * @brief Get the singleton instance of the EventManager.\n * "
"@return A reference to the EventManager singleton.\n",
py::return_value_policy::reference)
.def("add_publisher", &espp::EventManager::add_publisher, py::arg("topic"),
py::arg("component"),
"*\n * @brief Register a publisher for \\p component on \\p topic.\n * @param "
"topic Topic name for the data being published.\n * @param component Name of the "
"component publishing data.\n * @return True if the publisher was added, False if "
"it was already\n * registered for that component.\n")
.def("add_subscriber",
py::overload_cast<const std::string &, const std::string &,
const espp::EventManager::event_callback_fn &, const size_t>(
&espp::EventManager::add_subscriber),
py::arg("topic"), py::arg("component"), py::arg("callback"),
py::arg("stack_size_bytes") = 8192,
"*\n * @brief Register a subscriber for \\p component on \\p topic.\n * @param "
"topic Topic name for the data being subscribed to.\n * @param component Name of "
"the component publishing data.\n * @param callback The event_callback_fn to be "
"called when receicing data on\n * \\p topic.\n * @param "
"stack_size_bytes The stack size in bytes to use for the subscriber\n * @note The "
"stack size is only used if a subscriber is not already registered\n * for "
"that topic. If a subscriber is already registered for that topic,\n * the "
"stack size is ignored.\n * @return True if the subscriber was added, False if it "
"was already\n * registered for that component.\n")
.def("add_subscriber",
py::overload_cast<const std::string &, const std::string &,
const espp::EventManager::event_callback_fn &,
const espp::Task::BaseConfig &>(
&espp::EventManager::add_subscriber),
py::arg("topic"), py::arg("component"), py::arg("callback"), py::arg("task_config"),
"*\n * @brief Register a subscriber for \\p component on \\p topic.\n * @param "
"topic Topic name for the data being subscribed to.\n * @param component Name of "
"the component publishing data.\n * @param callback The event_callback_fn to be "
"called when receicing data on\n * \\p topic.\n * @param task_config The "
"task configuration to use for the subscriber.\n * @note The task_config is only "
"used if a subscriber is not already\n * registered for that topic. If a "
"subscriber is already registered for\n * that topic, the task_config is "
"ignored.\n * @return True if the subscriber was added, False if it was already\n "
" * registered for that component.\n")
.def("publish", &espp::EventManager::publish, py::arg("topic"), py::arg("data"),
"*\n * @brief Publish \\p data on \\p topic.\n * @param topic Topic to publish "
"data on.\n * @param data Data to publish, within a vector container.\n * "
"@return True if \\p data was successfully published to \\p topic, False\n * "
" otherwise. Publish will not occur (and will return False) if\n * "
"there are no subscribers for this topic.\n")
.def("remove_publisher", &espp::EventManager::remove_publisher, py::arg("topic"),
py::arg("component"),
"*\n * @brief Remove \\p component's publisher for \\p topic.\n * @param topic "
"The topic that \\p component was publishing on.\n * @param component The "
"component for which the publisher was registered.\n * @return True if the "
"publisher was removed, False if it was not\n * registered.\n")
.def("remove_subscriber", &espp::EventManager::remove_subscriber, py::arg("topic"),
py::arg("component"),
"*\n * @brief Remove \\p component's subscriber for \\p topic.\n * @param topic "
"The topic that \\p component was subscribing to.\n * @param component The "
"component for which the subscriber was registered.\n * @return True if the "
"subscriber was removed, False if it was not\n * registered.\n");
//////////////////// </generated_from:event_manager.hpp> ////////////////////
//////////////////// <generated_from:ftp_server.hpp> ////////////////////
auto pyClassFtpServer =
py::class_<espp::FtpServer>(m, "FtpServer", py::dynamic_attr(),
"/ \\brief A class that implements a FTP server.")
.def(py::init<std::string_view, uint16_t, const std::filesystem::path &>(),
py::arg("ip_address"), py::arg("port"), py::arg("root"),
"/ \\brief A class that implements a FTP server.\n/ \note The IP Address is not "
"currently used to select the right\n/ interface, but is instead passed to "
"the FtpClientSession so that\n/ it can be used in the PASV command.\n/ "
"\\param ip_address The IP address to listen on.\n/ \\param port The port to listen "
"on.\n/ \\param root The root directory of the FTP server.")
.def("start", &espp::FtpServer::start,
"/ \\brief Start the FTP server.\n/ Bind to the port and start accepting "
"connections.\n/ \\return True if the server was started, False otherwise.",
py::call_guard<py::gil_scoped_release>())
.def("stop", &espp::FtpServer::stop, "/ \\brief Stop the FTP server.",
py::call_guard<py::gil_scoped_release>());
//////////////////// </generated_from:ftp_server.hpp> ////////////////////
//////////////////// <generated_from:logger.hpp> ////////////////////
auto pyClassLogger = py::class_<espp::Logger>(
m, "Logger", py::dynamic_attr(),
"*\n * @brief Logger provides a wrapper around nicer / more robust formatting than\n * "
"standard ESP_LOG* macros with the ability to change the log level at\n * run-time. Logger "
"currently is a light wrapper around libfmt (future\n * std::format).\n *\n * To save on "
"code size, the logger has the ability to be compiled out based on\n * the log level set in "
"the sdkconfig. This means that if the log level is set to\n * ERROR, all debug, info, and "
"warn logs will be compiled out. This is done by\n * checking the log level at compile time "
"and only compiling in the functions\n * that are needed.\n *\n * The logger can also be "
"compiled with support for cursor commands. This allows\n * the logger to move the cursor "
"up, down, clear the line, clear the screen, and\n * move the cursor to a specific position. "
"This can be useful for creating\n * various types of interactive output or to maintian "
"context with long-running\n * logs.\n *\n * \\section logger_ex1 Basic Example\n * "
"\\snippet logger_example.cpp Logger example\n * \\section logger_ex2 Threaded Logging and "
"Verbosity Example\n * \\snippet logger_example.cpp MultiLogger example\n * \\section "
"logger_ex3 Cursor Commands Example\n * \\snippet logger_example.cpp Cursor Commands "
"example\n");
{ // inner classes & enums of Logger
auto pyEnumVerbosity =
py::enum_<espp::Logger::Verbosity>(
pyClassLogger, "Verbosity", py::arithmetic(),
"*\n * Verbosity levels for the logger, in order of increasing priority.\n")
.value("debug", espp::Logger::Verbosity::DEBUG, "*< Debug level verbosity.")
.value("info", espp::Logger::Verbosity::INFO, "*< Info level verbosity.")
.value("warn", espp::Logger::Verbosity::WARN, "*< Warn level verbosity.")
.value("error", espp::Logger::Verbosity::ERROR, "*< Error level verbosity.")
.value("none", espp::Logger::Verbosity::NONE,
"*< No verbosity - logger will not print anything.");
auto pyClassLogger_ClassConfig =
py::class_<espp::Logger::Config>(pyClassLogger, "Config", py::dynamic_attr(),
"*\n * @brief Configuration struct for the logger.\n")
.def(py::init<>(
[](std::string_view tag = std::string_view(), bool include_time = {true},
std::chrono::duration<float> rate_limit = std::chrono::duration<float>(0),
espp::Logger::Verbosity level = espp::Logger::Verbosity::WARN) {
auto r_ctor_ = std::make_unique<espp::Logger::Config>();
r_ctor_->tag = tag;
r_ctor_->include_time = include_time;
r_ctor_->rate_limit = rate_limit;
r_ctor_->level = level;
return r_ctor_;
}),
py::arg("tag") = std::string_view(), py::arg("include_time") = bool{true},
py::arg("rate_limit") = std::chrono::duration<float>(0),
py::arg("level") = espp::Logger::Verbosity::WARN)
.def_readwrite("tag", &espp::Logger::Config::tag,
"*< The TAG that will be prepended to all logs.")
.def_readwrite("include_time", &espp::Logger::Config::include_time,
"*< Include the time in the log.")
.def_readwrite(
"rate_limit", &espp::Logger::Config::rate_limit,
"*< The rate limit for the logger. Optional, if <= 0 no\nrate limit. @note Only "
"calls that have _rate_limited suffixed will be rate limited.")
.def_readwrite("level", &espp::Logger::Config::level,
"*< The verbosity level for the logger.");
} // end of inner classes & enums of Logger
pyClassLogger.def(py::init<const espp::Logger::Config &>())
.def("get_verbosity", &espp::Logger::get_verbosity,
"*\n * @brief Get the current verbosity for the logger.\n * @return The current "
"verbosity level.\n * \\sa Logger::Verbosity\n *\n")
.def("set_verbosity", &espp::Logger::set_verbosity, py::arg("level"),
"*\n * @brief Change the verbosity for the logger. \\sa Logger::Verbosity\n * "
"@param level new verbosity level\n")
.def("set_tag", &espp::Logger::set_tag, py::arg("tag"),
"*\n * @brief Change the tag for the logger.\n * @param tag The new tag.\n")
.def("get_tag", &espp::Logger::get_tag,
"*\n * @brief Get the current tag for the logger.\n * @return A const reference to "
"the current tag.\n")
.def("set_include_time", &espp::Logger::set_include_time, py::arg("include_time"),
"*\n * @brief Whether to include the time in the log.\n * @param include_time "
"Whether to include the time in the log.\n * @note The time is in seconds since boot "
"and is represented as a floating\n * point number with precision to the "
"millisecond.\n")
.def("set_rate_limit", &espp::Logger::set_rate_limit, py::arg("rate_limit"),
"*\n * @brief Change the rate limit for the logger.\n * @param rate_limit The new "
"rate limit.\n * @note Only calls that have _rate_limited suffixed will be rate "
"limited.\n")
.def("get_rate_limit", &espp::Logger::get_rate_limit,
"*\n * @brief Get the current rate limit for the logger.\n * @return The current "
"rate limit.\n")
.def_static(
"get_time", &espp::Logger::get_time,
"*\n * Get the current time in seconds since the start of the logging system.\n * "
" @return time in seconds since the start of the logging system.\n");
//////////////////// </generated_from:logger.hpp> ////////////////////
//////////////////// <generated_from:bezier.hpp> ////////////////////
auto pyClassBezier_espp_Vector2f = py::class_<espp::Bezier<espp::Vector2f>>(
m, "Bezier_espp_Vector2f", py::dynamic_attr(),
"*\n * @brief Implements rational / weighted and unweighted cubic bezier curves\n * "
"between control points.\n * @note See https://pomax.github.io/bezierinfo/ for information "
"on bezier\n * curves.\n * @note Template class which can be used individually on "
"floating point\n * values directly or on containers such as Vector2d<float>.\n * "
"@tparam T The type of the control points, e.g. float or Vector2d<float>.\n * @note The "
"bezier curve is defined by 4 control points, P0, P1, P2, P3.\n * The curve is defined "
"by the equation:\n * \\f$B(t) = (1-t)^3 * P0 + 3 * (1-t)^2 * t * P1 + 3 * (1-t) * t^2 "
"* P2 + t^3 * P3\\f$\n * where t is the evaluation parameter, [0, 1].\n *\n * @note The "
"weighted bezier curve is defined by 4 control points, P0, P1, P2, P3\n * and 4 "
"weights, W0, W1, W2, W3.\n * The curve is defined by the equation:\n * \\f$B(t) = "
"(W0 * (1-t)^3 * P0 + W1 * 3 * (1-t)^2 * t * P1 + W2 * 3 * (1-t) * t^2 * P2 + W3 *\n * t^3 * "
"P3) / (W0 + W1 + W2 + W3)\\f$ where t is the evaluation parameter, [0, 1].\n *\n * "
"\\section bezier_ex1 Example\n * \\snippet math_example.cpp bezier example\n");
{ // inner classes & enums of Bezier_espp_Vector2f
auto pyClassBezier_ClassConfig =
py::class_<espp::Bezier<espp::Vector2f>::Config>(
pyClassBezier_espp_Vector2f, "Config", py::dynamic_attr(),
"*\n * @brief Unweighted cubic bezier configuration for 4 control points.\n")
.def(py::init<>()) // implicit default constructor
.def_readwrite("control_points", &espp::Bezier<espp::Vector2f>::Config::control_points,
"/< Array of 4 control points");
auto pyClassBezier_ClassWeightedConfig =
py::class_<espp::Bezier<espp::Vector2f>::WeightedConfig>(
pyClassBezier_espp_Vector2f, "WeightedConfig", py::dynamic_attr(),
"*\n * @brief Weighted cubic bezier configuration for 4 control points with\n * "
" individual weights.\n")
.def(py::init<>()) // implicit default constructor
.def_readwrite("control_points",
&espp::Bezier<espp::Vector2f>::WeightedConfig::control_points,
"/< Array of 4 control points")
.def_readwrite("weights", &espp::Bezier<espp::Vector2f>::WeightedConfig::weights,
"/< Array of 4 weights, default is array of 1.0");
} // end of inner classes & enums of Bezier_espp_Vector2f
pyClassBezier_espp_Vector2f.def(py::init<const espp::Bezier<espp::Vector2f>::Config &>())
.def(py::init<const espp::Bezier<espp::Vector2f>::WeightedConfig &>())
.def("__call__", &espp::Bezier<espp::Vector2f>::operator(), py::arg("t"),
"*\n * @brief Evaluate the bezier at \\p t.\n * @note Convienience wrapper around "
"the at() method.\n * @param t The evaluation parameter, [0, 1].\n * @return The "
"bezier evaluated at \\p t.\n");
//////////////////// </generated_from:bezier.hpp> ////////////////////
//////////////////// <generated_from:fast_math.hpp> ////////////////////
m.def("deg_to_rad", espp::deg_to_rad, py::arg("degrees"),
"*\n * @brief Convert degrees to radians\n * @param degrees Angle in degrees\n * @return "
"Angle in radians\n");
m.def("rad_to_deg", espp::rad_to_deg, py::arg("radians"),
"*\n * @brief Convert radians to degrees\n * @param radians Angle in radians\n * @return "
"Angle in degrees\n");
m.def("square", espp::square, py::arg("f"),
"*\n * @brief Simple square of the input.\n * @param f Value to square.\n * @return The "
"square of f (f*f).\n");
m.def("cube", espp::cube, py::arg("f"),
"*\n * @brief Simple cube of the input.\n * @param f Value to cube.\n * @return The cube "
"of f (f*f*f).\n");
m.def("fast_inv_sqrt", espp::fast_inv_sqrt, py::arg("value"),
"*\n * @brief Fast inverse square root approximation.\n * @note Using "
"https://reprap.org/forum/read.php?147,219210 and\n * "
"https://en.wikipedia.org/wiki/Fast_inverse_square_root\n * @param value Value to take the "
"inverse square root of.\n * @return Approximation of the inverse square root of value.\n");
m.def("sgn", py::overload_cast<int>(espp::sgn<int>), py::arg("x"),
"*\n * @brief Get the sign of a number (+1, 0, or -1)\n * @param x Value to get the sign "
"of\n * @return Sign of x: -1 if x < 0, 0 if x == 0, or +1 if x > 0\n");
m.def("sgn", py::overload_cast<float>(espp::sgn<float>), py::arg("x"),
"*\n * @brief Get the sign of a number (+1, 0, or -1)\n * @param x Value to get the sign "
"of\n * @return Sign of x: -1 if x < 0, 0 if x == 0, or +1 if x > 0\n");
m.def("lerp", espp::lerp, py::arg("a"), py::arg("b"), py::arg("t"),
"*\n * @brief Linear interpolation between two values.\n * @param a First value.\n * "
"@param b Second value.\n * @param t Interpolation factor in the range [0, 1].\n * @return "
"Linear interpolation between a and b.\n");
m.def("inv_lerp", espp::inv_lerp, py::arg("a"), py::arg("b"), py::arg("v"),
"*\n * @brief Compute the inverse lerped value.\n * @param a First value (usually the "
"lower of the two).\n * @param b Second value (usually the higher of the two).\n * @param "
"v Value to inverse lerp (usually a value between a and b).\n * @return Inverse lerp "
"value, the factor of v between a and b in the range [0,\n * 1] if v is between a "
"and b, 0 if v == a, or 1 if v == b. If a == b,\n * 0 is returned. If v is outside "
"the range [a, b], the value is\n * extrapolated linearly (i.e. if v < a, the "
"value is less than 0, if v\n * > b, the value is greater than 1).\n");
m.def(
"piecewise_linear", espp::piecewise_linear, py::arg("points"), py::arg("x"),
"*\n * @brief Compute the piecewise linear interpolation between a set of points.\n * @param "
"points Vector of points to interpolate between. The vector should be\n * "
"sorted by the first value in the pair. The first value in the\n * pair is the "
"x value and the second value is the y value. The x\n * values should be "
"unique. The function will interpolate between\n * the points using linear "
"interpolation. If x is less than the\n * first x value, the first y value is "
"returned. If x is greater\n * than the last x value, the last y value is "
"returned. If x is\n * between two x values, the y value is interpolated "
"between the\n * two y values.\n * @param x Value to interpolate at. Should be "
"a value from the first\n * distribution of the points (the domain). If x is "
"outside the domain\n * of the points, the value returned will be clamped to the "
"first or\n * last y value.\n * @return Interpolated value at x.\n");
m.def("round", espp::round, py::arg("x"),
"*\n * @brief Round x to the nearest integer.\n * @param x Floating point value to be "
"rounded.\n * @return Nearest integer to x.\n");
m.def("fast_ln", espp::fast_ln, py::arg("x"),
"*\n * @brief fast natural log function, ln(x).\n * @note This speed hack comes from:\n * "
" https://gist.github.com/LingDong-/7e4c4cae5cbbc44400a05fba65f06f23\n * @param x Value to "
"take the natural log of.\n * @return ln(x)\n");
m.def("fast_sin", espp::fast_sin, py::arg("angle"),
"*\n * @brief Fast approximation of sin(angle) (radians).\n * @note \\p Angle must be in "
"the range [0, 2PI].\n * @param angle Angle in radians [0, 2*PI]\n * @return Approximation "
"of sin(value)\n");
m.def("fast_cos", espp::fast_cos, py::arg("angle"),
"*\n * @brief Fast approximation of cos(angle) (radians).\n * @note \\p Angle must be in "
"the range [0, 2PI].\n * @param angle Angle in radians [0, 2*PI]\n * @return Approximation "
"of cos(value)\n");
//////////////////// </generated_from:fast_math.hpp> ////////////////////
//////////////////// <generated_from:gaussian.hpp> ////////////////////
auto pyClassGaussian = py::class_<espp::Gaussian>(
m, "Gaussian", py::dynamic_attr(),
"*\n * @brief Implements a gaussian function\n * "
"\\f$y(t)=\\alpha\\exp(-\\frac{(t-\\beta)^2}{2\\gamma^2})\\f$.\n * @details Alows you to "
"store the alpha, beta, and gamma coefficients as well\n * as update them "
"dynamically.\n *\n * \\section gaussian_ex1 Example\n * \\snippet math_example.cpp gaussian "
"example\n * \\section gaussian_ex2 Fade-In/Fade-Out Example\n * \\snippet math_example.cpp "
"gaussian fade in fade out example\n");
{ // inner classes & enums of Gaussian
auto pyClassGaussian_ClassConfig =
py::class_<espp::Gaussian::Config>(
pyClassGaussian, "Config", py::dynamic_attr(),
"*\n * @brief Configuration structure for initializing the gaussian.\n")
.def(py::init<>([](float gamma = float(), float alpha = {1.0f}, float beta = {0.5f}) {
auto r_ctor_ = std::make_unique<espp::Gaussian::Config>();
r_ctor_->gamma = gamma;
r_ctor_->alpha = alpha;
r_ctor_->beta = beta;
return r_ctor_;
}),
py::arg("gamma") = float(), py::arg("alpha") = float{1.0f},
py::arg("beta") = float{0.5f})
.def_readwrite(
"gamma", &espp::Gaussian::Config::gamma,
"/< Slope of the gaussian, range [0, 1]. 0 is more of a thin spike from 0 up to")
.def_readwrite("alpha", &espp::Gaussian::Config::alpha,
"/< Max amplitude of the gaussian output, defautls to 1.0.")
.def_readwrite(
"beta", &espp::Gaussian::Config::beta,
"/< Beta value for the gaussian, default to be symmetric at 0.5 in range [0,1].")
.def("__eq__", &espp::Gaussian::Config::operator==, py::arg("rhs"));
} // end of inner classes & enums of Gaussian
pyClassGaussian.def(py::init<const espp::Gaussian::Config &>())
.def("__call__", &espp::Gaussian::operator(), py::arg("t"),
"*\n * @brief Evaluate the gaussian at \\p t.\n * @note Convienience wrapper around "
"the at() method.\n * @param t The evaluation parameter, [0, 1].\n * @return The "
"gaussian evaluated at \\p t.\n")
.def("update", &espp::Gaussian::update, py::arg("config"),
"*\n * @brief Update the gaussian configuration.\n * @param config The new "
"configuration.\n")
.def("set_config", &espp::Gaussian::set_config, py::arg("config"),
"*\n * @brief Set the configuration of the gaussian.\n * @param config The new "
"configuration.\n")
.def("get_config", &espp::Gaussian::get_config,
"*\n * @brief Get the current configuration of the gaussian.\n * @return The "
"current configuration.\n")
.def("get_gamma", &espp::Gaussian::get_gamma,
"*\n * @brief Get the gamma value.\n * @return The gamma value.\n")
.def("get_alpha", &espp::Gaussian::get_alpha,
"*\n * @brief Get the alpha value.\n * @return The alpha value.\n")
.def("get_beta", &espp::Gaussian::get_beta,
"*\n * @brief Get the beta value.\n * @return The beta value.\n")
.def("set_gamma", &espp::Gaussian::set_gamma, py::arg("gamma"),
"*\n * @brief Set the gamma value.\n * @param gamma The new gamma value.\n")
.def("set_alpha", &espp::Gaussian::set_alpha, py::arg("alpha"),
"*\n * @brief Set the alpha value.\n * @param alpha The new alpha value.\n")
.def("set_beta", &espp::Gaussian::set_beta, py::arg("beta"),
"*\n * @brief Set the beta value.\n * @param beta The new beta value.\n");
//////////////////// </generated_from:gaussian.hpp> ////////////////////
//////////////////// <generated_from:range_mapper.hpp> ////////////////////
auto pyClassRangeMapper_int = py::class_<espp::RangeMapper<int>>(
m, "RangeMapper_int", py::dynamic_attr(),
"*\n * @brief Template class for converting a value from an uncentered [minimum,\n * "
"maximum] range into a centered output range (default [-1,1]). If\n * provided a "
"non-zero deadband, it will convert all values within\n * [center-deadband, "
"center+deadband] to be the configured\n * output_center (default 0).\n *\n * "
"The RangeMapper can be optionally configured to invert the input,\n * so that it "
"will compute the input w.r.t. the configured min/max of\n * the input range when "
"mapping to the output range - this will mean\n * that a values within the ranges "
"[minimum, minimum+deadband] and\n * [maximum-deadband, maximum] will all map to the "
"output_center and\n * the input center will map to both output_max and output_min\n "
"* depending on the sign of the input.\n *\n * @tparam T Numeric type to use for the "
"input and output values.\n *\n * @note When inverting the input range, you are introducing "
"a discontinuity\n * between the input distribution and the output distribution at "
"the\n * input center. Noise around the input's center value will create\n * "
"oscillations in the output which will jump between output maximum\n * and output "
"minimum. Therefore it is advised to use \\p invert_input\n * sparignly, and to set "
"the values robustly.\n *\n * The RangeMapper can be optionally configured to invert "
"the output,\n * so that after converting from the input range to the output range,\n "
"* it will flip the sign on the output.\n *\n * \\section range_mapper_ex1 Example\n "
"* \\snippet math_example.cpp range_mapper example\n");
{ // inner classes & enums of RangeMapper_int
auto pyClassRangeMapper_ClassConfig =
py::class_<espp::RangeMapper<int>::Config>(
pyClassRangeMapper_int, "Config", py::dynamic_attr(),
"*\n * @brief Configuration for the input uncentered range with optional\n * "
"values for the centered output range, default values of 0 output center\n * and 1 "
"output range provide a default output range between [-1, 1].\n")
.def(py::init<>([](int center = int(), int center_deadband = 0, int minimum = int(),
int maximum = int(), int range_deadband = 0, int output_center = 0,
int output_range = 1, bool invert_output = false) {
auto r_ctor_ = std::make_unique<espp::RangeMapper<int>::Config>();
r_ctor_->center = center;
r_ctor_->center_deadband = center_deadband;
r_ctor_->minimum = minimum;
r_ctor_->maximum = maximum;
r_ctor_->range_deadband = range_deadband;
r_ctor_->output_center = output_center;
r_ctor_->output_range = output_range;
r_ctor_->invert_output = invert_output;
return r_ctor_;
}),
py::arg("center") = int(), py::arg("center_deadband") = 0,
py::arg("minimum") = int(), py::arg("maximum") = int(),
py::arg("range_deadband") = 0, py::arg("output_center") = 0,
py::arg("output_range") = 1, py::arg("invert_output") = false)
.def_readwrite("center", &espp::RangeMapper<int>::Config::center,
"*< Center value for the input range.")
.def_readwrite("center_deadband", &espp::RangeMapper<int>::Config::center_deadband,
"*< Deadband amount around (+-) the center for which output will be 0.")
.def_readwrite("minimum", &espp::RangeMapper<int>::Config::minimum,
"*< Minimum value for the input range.")
.def_readwrite("maximum", &espp::RangeMapper<int>::Config::maximum,
"*< Maximum value for the input range.")
.def_readwrite("range_deadband", &espp::RangeMapper<int>::Config::range_deadband,
"*< Deadband amount around the minimum and maximum for which output "
"will\n be min/max output.")
.def_readwrite("output_center", &espp::RangeMapper<int>::Config::output_center,
"*< The center for the output. Default 0.")
.def_readwrite(
"output_range", &espp::RangeMapper<int>::Config::output_range,
"*< The range (+/-) from the center for the output. Default 1. @note Will\n "
" be passed through std::abs() to ensure it is positive.")
.def_readwrite("invert_output", &espp::RangeMapper<int>::Config::invert_output,
"*< Whether to invert the output (default False). @note If True will "
"flip the sign\n of the output after converting from "
"the input distribution.");
} // end of inner classes & enums of RangeMapper_int
pyClassRangeMapper_int.def(py::init<>())
.def("get_center_deadband", &espp::RangeMapper<int>::get_center_deadband,
"*\n * @brief Return the configured deadband around the center of the input\n * "
" distribution\n * @return Deadband around the center of the input distribution for "
"this\n * range mapper.\n")
.def("get_minimum", &espp::RangeMapper<int>::get_minimum,
"*\n * @brief Return the configured minimum of the input distribution\n * @return "
"Minimum of the input distribution for this range mapper.\n")
.def("get_maximum", &espp::RangeMapper<int>::get_maximum,
"*\n * @brief Return the configured maximum of the input distribution\n * @return "
"Maximum of the input distribution for this range mapper.\n")
.def(
"get_range", &espp::RangeMapper<int>::get_range,
"*\n * @brief Return the configured range of the input distribution\n * @note Always "
"positive.\n * @return Range of the input distribution for this range mapper.\n")
.def("get_range_deadband", &espp::RangeMapper<int>::get_range_deadband,
"*\n * @brief Return the configured deadband around the min/max of the input\n * "
" distribution\n * @return Deadband around the min/max of the input distribution "
"for this\n * range mapper.\n")
.def("get_output_center", &espp::RangeMapper<int>::get_output_center,
"*\n * @brief Return the configured center of the output distribution\n * @return "
"Center of the output distribution for this range mapper.\n")
.def("get_output_range", &espp::RangeMapper<int>::get_output_range,
"*\n * @brief Return the configured range of the output distribution\n * @note "
"Always positive.\n * @return Range of the output distribution for this range "
"mapper.\n")
.def("get_output_min", &espp::RangeMapper<int>::get_output_min,
"*\n * @brief Return the configured minimum of the output distribution\n * @return "
"Minimum of the output distribution for this range mapper.\n")
.def("get_output_max", &espp::RangeMapper<int>::get_output_max,
"*\n * @brief Return the configured maximum of the output distribution\n * @return "
"Maximum of the output distribution for this range mapper.\n")
.def("set_center_deadband", &espp::RangeMapper<int>::set_center_deadband, py::arg("deadband"),
"*\n * @brief Set the deadband around the center of the input distribution.\n * "
"@param deadband The deadband to use around the center of the input\n * "
"distribution.\n * @note The deadband must be non-negative.\n * @note The deadband "
"is applied around the center value of the input\n * distribution.\n")
.def("set_range_deadband", &espp::RangeMapper<int>::set_range_deadband, py::arg("deadband"),
"*\n * @brief Set the deadband around the min/max of the input distribution.\n * "
"@param deadband The deadband to use around the min/max of the input\n * "
"distribution.\n * @note The deadband must be non-negative.\n * @note The deadband "
"is applied around the min/max values of the input\n * distribution.\n")
.def("map", &espp::RangeMapper<int>::map, py::arg("v"),
"*\n * @brief Map a value \\p v from the input distribution into the configured\n * "
" output range (centered, default [-1,1]).\n * @param v Value from the "
"(possibly uncentered and possibly inverted -\n * defined by the previously "
"configured Config) input distribution\n * @return Value within the centered output "
"distribution.\n")
.def("unmap", &espp::RangeMapper<int>::unmap, py::arg("v"),
"*\n * @brief Unmap a value \\p v from the configured output range (centered,\n * "
" default [-1,1]) back into the input distribution.\n * @param v Value from the "
"centered output distribution.\n * @return Value within the input distribution.\n");
auto pyClassRangeMapper_float = py::class_<espp::RangeMapper<float>>(
m, "RangeMapper_float", py::dynamic_attr(),
"*\n * @brief Template class for converting a value from an uncentered [minimum,\n * "
"maximum] range into a centered output range (default [-1,1]). If\n * provided a "
"non-zero deadband, it will convert all values within\n * [center-deadband, "
"center+deadband] to be the configured\n * output_center (default 0).\n *\n * "
"The RangeMapper can be optionally configured to invert the input,\n * so that it "
"will compute the input w.r.t. the configured min/max of\n * the input range when "
"mapping to the output range - this will mean\n * that a values within the ranges "
"[minimum, minimum+deadband] and\n * [maximum-deadband, maximum] will all map to the "
"output_center and\n * the input center will map to both output_max and output_min\n "
"* depending on the sign of the input.\n *\n * @tparam T Numeric type to use for the "
"input and output values.\n *\n * @note When inverting the input range, you are introducing "
"a discontinuity\n * between the input distribution and the output distribution at "
"the\n * input center. Noise around the input's center value will create\n * "
"oscillations in the output which will jump between output maximum\n * and output "
"minimum. Therefore it is advised to use \\p invert_input\n * sparignly, and to set "
"the values robustly.\n *\n * The RangeMapper can be optionally configured to invert "
"the output,\n * so that after converting from the input range to the output range,\n "
"* it will flip the sign on the output.\n *\n * \\section range_mapper_ex1 Example\n "
"* \\snippet math_example.cpp range_mapper example\n");
{ // inner classes & enums of RangeMapper_float
auto pyClassRangeMapper_ClassConfig =
py::class_<espp::RangeMapper<float>::Config>(
pyClassRangeMapper_float, "Config", py::dynamic_attr(),
"*\n * @brief Configuration for the input uncentered range with optional\n * "
"values for the centered output range, default values of 0 output center\n * and 1 "
"output range provide a default output range between [-1, 1].\n")
.def(py::init<>([](float center = float(), float center_deadband = 0,
float minimum = float(), float maximum = float(),
float range_deadband = 0, float output_center = 0,
float output_range = 1, bool invert_output = false) {
auto r_ctor_ = std::make_unique<espp::RangeMapper<float>::Config>();
r_ctor_->center = center;
r_ctor_->center_deadband = center_deadband;
r_ctor_->minimum = minimum;
r_ctor_->maximum = maximum;
r_ctor_->range_deadband = range_deadband;
r_ctor_->output_center = output_center;
r_ctor_->output_range = output_range;
r_ctor_->invert_output = invert_output;
return r_ctor_;
}),
py::arg("center") = float(), py::arg("center_deadband") = 0,
py::arg("minimum") = float(), py::arg("maximum") = float(),
py::arg("range_deadband") = 0, py::arg("output_center") = 0,
py::arg("output_range") = 1, py::arg("invert_output") = false)
.def_readwrite("center", &espp::RangeMapper<float>::Config::center,
"*< Center value for the input range.")
.def_readwrite("center_deadband", &espp::RangeMapper<float>::Config::center_deadband,
"*< Deadband amount around (+-) the center for which output will be 0.")
.def_readwrite("minimum", &espp::RangeMapper<float>::Config::minimum,
"*< Minimum value for the input range.")
.def_readwrite("maximum", &espp::RangeMapper<float>::Config::maximum,
"*< Maximum value for the input range.")
.def_readwrite("range_deadband", &espp::RangeMapper<float>::Config::range_deadband,
"*< Deadband amount around the minimum and maximum for which output "
"will\n be min/max output.")
.def_readwrite("output_center", &espp::RangeMapper<float>::Config::output_center,
"*< The center for the output. Default 0.")
.def_readwrite(
"output_range", &espp::RangeMapper<float>::Config::output_range,
"*< The range (+/-) from the center for the output. Default 1. @note Will\n "
" be passed through std::abs() to ensure it is positive.")
.def_readwrite("invert_output", &espp::RangeMapper<float>::Config::invert_output,
"*< Whether to invert the output (default False). @note If True will "
"flip the sign\n of the output after converting from "
"the input distribution.");
} // end of inner classes & enums of RangeMapper_float
pyClassRangeMapper_float.def(py::init<>())
.def("get_center_deadband", &espp::RangeMapper<float>::get_center_deadband,
"*\n * @brief Return the configured deadband around the center of the input\n * "
" distribution\n * @return Deadband around the center of the input distribution for "
"this\n * range mapper.\n")
.def("get_minimum", &espp::RangeMapper<float>::get_minimum,
"*\n * @brief Return the configured minimum of the input distribution\n * @return "
"Minimum of the input distribution for this range mapper.\n")
.def("get_maximum", &espp::RangeMapper<float>::get_maximum,
"*\n * @brief Return the configured maximum of the input distribution\n * @return "
"Maximum of the input distribution for this range mapper.\n")
.def(
"get_range", &espp::RangeMapper<float>::get_range,
"*\n * @brief Return the configured range of the input distribution\n * @note Always "
"positive.\n * @return Range of the input distribution for this range mapper.\n")
.def("get_range_deadband", &espp::RangeMapper<float>::get_range_deadband,
"*\n * @brief Return the configured deadband around the min/max of the input\n * "
" distribution\n * @return Deadband around the min/max of the input distribution "
"for this\n * range mapper.\n")
.def("get_output_center", &espp::RangeMapper<float>::get_output_center,
"*\n * @brief Return the configured center of the output distribution\n * @return "
"Center of the output distribution for this range mapper.\n")
.def("get_output_range", &espp::RangeMapper<float>::get_output_range,
"*\n * @brief Return the configured range of the output distribution\n * @note "
"Always positive.\n * @return Range of the output distribution for this range "
"mapper.\n")
.def("get_output_min", &espp::RangeMapper<float>::get_output_min,
"*\n * @brief Return the configured minimum of the output distribution\n * @return "
"Minimum of the output distribution for this range mapper.\n")
.def("get_output_max", &espp::RangeMapper<float>::get_output_max,
"*\n * @brief Return the configured maximum of the output distribution\n * @return "
"Maximum of the output distribution for this range mapper.\n")
.def("set_center_deadband", &espp::RangeMapper<float>::set_center_deadband,
py::arg("deadband"),
"*\n * @brief Set the deadband around the center of the input distribution.\n * "
"@param deadband The deadband to use around the center of the input\n * "
"distribution.\n * @note The deadband must be non-negative.\n * @note The deadband "
"is applied around the center value of the input\n * distribution.\n")
.def("set_range_deadband", &espp::RangeMapper<float>::set_range_deadband, py::arg("deadband"),
"*\n * @brief Set the deadband around the min/max of the input distribution.\n * "
"@param deadband The deadband to use around the min/max of the input\n * "
"distribution.\n * @note The deadband must be non-negative.\n * @note The deadband "
"is applied around the min/max values of the input\n * distribution.\n")
.def("map", &espp::RangeMapper<float>::map, py::arg("v"),
"*\n * @brief Map a value \\p v from the input distribution into the configured\n * "
" output range (centered, default [-1,1]).\n * @param v Value from the "
"(possibly uncentered and possibly inverted -\n * defined by the previously "
"configured Config) input distribution\n * @return Value within the centered output "
"distribution.\n")
.def("unmap", &espp::RangeMapper<float>::unmap, py::arg("v"),
"*\n * @brief Unmap a value \\p v from the configured output range (centered,\n * "
" default [-1,1]) back into the input distribution.\n * @param v Value from the "
"centered output distribution.\n * @return Value within the input distribution.\n");
//////////////////// </generated_from:range_mapper.hpp> ////////////////////
//////////////////// <generated_from:vector2d.hpp> ////////////////////
auto pyClassVector2d_int =
py::class_<espp::Vector2d<int>>(
m, "Vector2d_int", py::dynamic_attr(),
"*\n * @brief Container representing a 2 dimensional vector.\n *\n * Provides "
"getters/setters, index operator, and vector / scalar math\n * utilities.\n *\n * "
"\\section vector_ex1 Example\n * \\snippet math_example.cpp vector2d example\n")
.def(py::init<int, int>(), py::arg("x") = 0, py::arg("y") = 0,
"*\n * @brief Constructor for the vector, defaults to 0,0.\n * @param x The "
"starting X value.\n * @param y The starting Y value.\n")
.def(py::init<const espp::Vector2d<int> &>(), py::arg("other"),
"*\n * @brief Vector copy constructor.\n * @param other Vector to copy.\n")
.def("magnitude", &espp::Vector2d<int>::magnitude,
"*\n * @brief Returns vector magnitude: ||v||.\n * @return The magnitude.\n")
.def("magnitude_squared", &espp::Vector2d<int>::magnitude_squared,
"*\n * @brief Returns vector magnitude squared: ||v||^2.\n * @return The "
"magnitude squared.\n")
.def(
"x", [](espp::Vector2d<int> &self) { return self.x(); },
"*\n * @brief Getter for the x value.\n * @return The current x value.\n")
.def("x", py::overload_cast<int>(&espp::Vector2d<int>::x), py::arg("v"),
"*\n * @brief Setter for the x value.\n * @param v New value for \\c x.\n")
.def(
"y", [](espp::Vector2d<int> &self) { return self.y(); },
"*\n * @brief Getter for the y value.\n * @return The current y value.\n")
.def("y", py::overload_cast<int>(&espp::Vector2d<int>::y), py::arg("v"),
"*\n * @brief Setter for the y value.\n * @param v New value for \\c y.\n")
.def(
"__lt__",
[](const espp::Vector2d<int> &self, const espp::Vector2d<int> &other) -> bool {
auto cmp = [&self](auto &&other) -> bool { return self.operator<=>(other) < 0; };
return cmp(other);
},
py::arg("other"),
"*\n * @brief Spaceship operator for comparing two vectors.\n * @param other The "
"vector to compare against.\n * @return -1 if this vector is less than \\p other, "
"0 if they are equal, 1 if\n * this vector is greater than \\p other.\n")
.def(
"__le__",
[](const espp::Vector2d<int> &self, const espp::Vector2d<int> &other) -> bool {
auto cmp = [&self](auto &&other) -> bool { return self.operator<=>(other) <= 0; };
return cmp(other);
},
py::arg("other"),
"*\n * @brief Spaceship operator for comparing two vectors.\n * @param other The "
"vector to compare against.\n * @return -1 if this vector is less than \\p other, "
"0 if they are equal, 1 if\n * this vector is greater than \\p other.\n")
.def(
"__eq__",
[](const espp::Vector2d<int> &self, const espp::Vector2d<int> &other) -> bool {
auto cmp = [&self](auto &&other) -> bool { return self.operator<=>(other) == 0; };
return cmp(other);
},
py::arg("other"),
"*\n * @brief Spaceship operator for comparing two vectors.\n * @param other The "
"vector to compare against.\n * @return -1 if this vector is less than \\p other, "
"0 if they are equal, 1 if\n * this vector is greater than \\p other.\n")
.def(
"__ge__",
[](const espp::Vector2d<int> &self, const espp::Vector2d<int> &other) -> bool {
auto cmp = [&self](auto &&other) -> bool { return self.operator<=>(other) >= 0; };
return cmp(other);
},
py::arg("other"),
"*\n * @brief Spaceship operator for comparing two vectors.\n * @param other The "
"vector to compare against.\n * @return -1 if this vector is less than \\p other, "
"0 if they are equal, 1 if\n * this vector is greater than \\p other.\n")
.def(
"__gt__",
[](const espp::Vector2d<int> &self, const espp::Vector2d<int> &other) -> bool {
auto cmp = [&self](auto &&other) -> bool { return self.operator<=>(other) > 0; };
return cmp(other);
},
py::arg("other"),
"*\n * @brief Spaceship operator for comparing two vectors.\n * @param other The "
"vector to compare against.\n * @return -1 if this vector is less than \\p other, "
"0 if they are equal, 1 if\n * this vector is greater than \\p other.\n")
.def("__eq__", &espp::Vector2d<int>::operator==, py::arg("other"),
"*\n * @brief Equality operator for comparing two vectors.\n * @param other The "
"vector to compare against.\n * @return True if the vectors are equal, False "
"otherwise.\n")
.def("__getitem__", &espp::Vector2d<int>::operator[], py::arg("index"),
"*\n * @brief Index operator for vector elements.\n * @note Returns a mutable "
"reference to the element.\n * @param index The index to return.\n * @return "
"Mutable reference to the element at \\p index.\n")
.def(
"__neg__", [](espp::Vector2d<int> &self) { return self.operator-(); },
"*\n * @brief Negate the vector.\n * @return The new vector which is the "
"negative.\n")
.def("__sub__",
py::overload_cast<const espp::Vector2d<int> &>(&espp::Vector2d<int>::operator-,
py::const_),
py::arg("rhs"),
"*\n * @brief Return a new vector which is the provided vector subtracted from\n "
" * this vector.\n * @param rhs The vector to subtract from this vector.\n "
" * @return Resultant vector subtraction.\n")
.def("__isub__", &espp::Vector2d<int>::operator-=, py::arg("rhs"),
"*\n * @brief Return the provided vector subtracted from this vector.\n * "
"@param rhs The vector to subtract from this vector.\n * @return Resultant vector "
"subtraction.\n")
.def("__add__", &espp::Vector2d<int>::operator+, py::arg("rhs"),
"*\n * @brief Return a new vector, which is the addition of this vector and the\n "
" * provided vector.\n * @param rhs The vector to add to this vector.\n "
"* @return Resultant vector addition.\n")