From 654374c5805661bd1ba63427e1461eed29beaf51 Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Tue, 17 Sep 2024 09:51:12 -0500 Subject: [PATCH] style: Apply style to all files (#327) * style: Apply style to all files * lib: update readme and bindings * fix binding mods * fix numbering in readme --- .../include/display_drivers.hpp | 14 +- .../esp-box/example/main/esp_box_example.cpp | 27 +- components/esp-box/src/esp-box.cpp | 3 +- .../include/esp32-timer-cam.hpp | 13 +- .../esp32-timer-cam/src/esp32-timer-cam.cpp | 47 +- components/interrupt/include/interrupt.hpp | 3 +- components/logger/include/logger.hpp | 1 - .../main/matouch_rotary_display_example.cpp | 19 +- .../src/matouch-rotary-display.cpp | 4 +- .../example/main/t_dongle_s3_example.cpp | 39 +- .../t-dongle-s3/include/t-dongle-s3.hpp | 7 +- components/t-dongle-s3/src/t-dongle-s3.cpp | 4 +- .../example/main/wrover_kit_example.cpp | 39 +- components/wrover-kit/include/wrover-kit.hpp | 7 +- components/wrover-kit/src/wrover-kit.cpp | 4 +- lib/README.md | 55 ++ lib/python_bindings/espp/__init__.pyi | 800 +++++++++--------- lib/python_bindings/pybind_espp.cpp | 66 +- 18 files changed, 645 insertions(+), 507 deletions(-) diff --git a/components/display_drivers/include/display_drivers.hpp b/components/display_drivers/include/display_drivers.hpp index 1ad44196c..f431fb7ce 100644 --- a/components/display_drivers/include/display_drivers.hpp +++ b/components/display_drivers/include/display_drivers.hpp @@ -43,14 +43,14 @@ struct Config { command bits. */ bool reset_value{false}; /**< The value to set the reset pin to when resetting the display (low to reset default). */ - bool invert_colors{false}; /**< Whether to invert the colors on the display. */ + bool invert_colors{false}; /**< Whether to invert the colors on the display. */ bool swap_color_order{false}; /**< Whether to swap the color order (RGB/BGR) on the display. */ - int offset_x{0}; /**< X Gap / offset, in pixels. */ - int offset_y{0}; /**< Y Gap / offset, in pixels. */ - bool swap_xy{false}; /**< Swap row/column order. */ - bool mirror_x{false}; /**< Mirror the display horizontally. */ - bool mirror_y{false}; /**< Mirror the display vertically. */ - bool mirror_portrait{false}; /**< Mirror the display in portrait mode. */ + int offset_x{0}; /**< X Gap / offset, in pixels. */ + int offset_y{0}; /**< Y Gap / offset, in pixels. */ + bool swap_xy{false}; /**< Swap row/column order. */ + bool mirror_x{false}; /**< Mirror the display horizontally. */ + bool mirror_y{false}; /**< Mirror the display vertically. */ + bool mirror_portrait{false}; /**< Mirror the display in portrait mode. */ }; /** diff --git a/components/esp-box/example/main/esp_box_example.cpp b/components/esp-box/example/main/esp_box_example.cpp index 2861bc6ef..9802e7dcd 100644 --- a/components/esp-box/example/main/esp_box_example.cpp +++ b/components/esp-box/example/main/esp_box_example.cpp @@ -64,10 +64,10 @@ extern "C" void app_main(void) { // set the pixel buffer to be 50 lines high static constexpr size_t pixel_buffer_size = box.lcd_width() * 50; espp::Task::BaseConfig display_task_config = { - .name = "Display", - .stack_size_bytes = 6 * 1024, - .priority = 10, - .core_id = 0, + .name = "Display", + .stack_size_bytes = 6 * 1024, + .priority = 10, + .core_id = 0, }; // initialize the LVGL display for the esp-box if (!box.initialize_display(pixel_buffer_size, display_task_config)) { @@ -100,14 +100,17 @@ extern "C" void app_main(void) { lv_label_set_text(label_btn, LV_SYMBOL_REFRESH); // center the text in the button lv_obj_align(label_btn, LV_ALIGN_CENTER, 0, 0); - lv_obj_add_event_cb(btn, [](auto event) { - std::lock_guard lock(lvgl_mutex); - clear_circles(); - static auto rotation = LV_DISPLAY_ROTATION_0; - rotation = static_cast((static_cast(rotation) + 1) % 4); - lv_display_t *disp = _lv_refr_get_disp_refreshing(); - lv_disp_set_rotation(disp, rotation); - }, LV_EVENT_PRESSED, nullptr); + lv_obj_add_event_cb( + btn, + [](auto event) { + std::lock_guard lock(lvgl_mutex); + clear_circles(); + static auto rotation = LV_DISPLAY_ROTATION_0; + rotation = static_cast((static_cast(rotation) + 1) % 4); + lv_display_t *disp = _lv_refr_get_disp_refreshing(); + lv_disp_set_rotation(disp, rotation); + }, + LV_EVENT_PRESSED, nullptr); // disable scrolling on the screen (so that it doesn't behave weirdly when // rotated and drawing with your finger) diff --git a/components/esp-box/src/esp-box.cpp b/components/esp-box/src/esp-box.cpp index 59f17107d..092d3c8ea 100644 --- a/components/esp-box/src/esp-box.cpp +++ b/components/esp-box/src/esp-box.cpp @@ -315,7 +315,8 @@ bool EspBox::initialize_lcd() { return true; } -bool EspBox::initialize_display(size_t pixel_buffer_size, const espp::Task::BaseConfig &task_config, int update_period_ms) { +bool EspBox::initialize_display(size_t pixel_buffer_size, const espp::Task::BaseConfig &task_config, + int update_period_ms) { if (!lcd_handle_) { logger_.error( "LCD not initialized, you must call initialize_lcd() before initialize_display()!"); diff --git a/components/esp32-timer-cam/include/esp32-timer-cam.hpp b/components/esp32-timer-cam/include/esp32-timer-cam.hpp index 44020c285..81ab72336 100644 --- a/components/esp32-timer-cam/include/esp32-timer-cam.hpp +++ b/components/esp32-timer-cam/include/esp32-timer-cam.hpp @@ -69,7 +69,7 @@ class EspTimerCam : public BaseComponent { /// @brief Initialize the LED /// @param breathing_period The period of the LED breathing effect /// @return True if the LED was successfully initialized, false otherwise - bool initialize_led(float breathing_period=3.5f); + bool initialize_led(float breathing_period = 3.5f); /// @brief Start the LED breathing effect void start_led_breathing(); @@ -207,7 +207,8 @@ class EspTimerCam : public BaseComponent { static constexpr gpio_num_t internal_i2c_scl = GPIO_NUM_14; // Battery - static constexpr float BATTERY_VOLTAGE_SCALE = 1.0f / 661.0f; // measured mV across divider to battery volts + static constexpr float BATTERY_VOLTAGE_SCALE = + 1.0f / 661.0f; // measured mV across divider to battery volts static constexpr gpio_num_t battery_hold_pin = GPIO_NUM_33; // NOTE: unused // Camera @@ -258,14 +259,14 @@ class EspTimerCam : public BaseComponent { // Battery ADC espp::AdcConfig battery_channel_{.unit = ADC_UNIT_1, - .channel = ADC_CHANNEL_2, // GPIO 38 - .attenuation = ADC_ATTEN_DB_12}; + .channel = ADC_CHANNEL_2, // GPIO 38 + .attenuation = ADC_ATTEN_DB_12}; // NOTE: for some reason, I cannot use Continuous ADC in combination with // esp32-camera... espp::OneshotAdc adc_{{.unit = battery_channel_.unit, - .channels = {battery_channel_}, - .log_level = espp::Logger::Verbosity::WARN}}; + .channels = {battery_channel_}, + .log_level = espp::Logger::Verbosity::WARN}}; }; // class EspTimerCam } // namespace espp diff --git a/components/esp32-timer-cam/src/esp32-timer-cam.cpp b/components/esp32-timer-cam/src/esp32-timer-cam.cpp index c2906238a..09f5b9de5 100644 --- a/components/esp32-timer-cam/src/esp32-timer-cam.cpp +++ b/components/esp32-timer-cam/src/esp32-timer-cam.cpp @@ -2,8 +2,8 @@ using namespace espp; -EspTimerCam::EspTimerCam() : BaseComponent("EspTimerCam") { -} +EspTimerCam::EspTimerCam() + : BaseComponent("EspTimerCam") {} //////////////////////// // LED // @@ -20,7 +20,10 @@ bool EspTimerCam::initialize_led(float breathing_period) { .channels = led_channels_, .duty_resolution = LEDC_TIMER_10_BIT, }); - led_task_ = espp::Task::make_unique({.name = "breathe", .callback = std::bind(&EspTimerCam::led_task_callback, this, std::placeholders::_1, std::placeholders::_2)}); + led_task_ = espp::Task::make_unique( + {.name = "breathe", + .callback = std::bind(&EspTimerCam::led_task_callback, this, std::placeholders::_1, + std::placeholders::_2)}); set_led_breathing_period(breathing_period); return true; } @@ -30,9 +33,7 @@ void EspTimerCam::start_led_breathing() { led_task_->start(); } -void EspTimerCam::stop_led_breathing() { - led_task_->stop(); -} +void EspTimerCam::stop_led_breathing() { led_task_->stop(); } bool EspTimerCam::set_led_brightness(float brightness) { if (led_ == nullptr) { @@ -70,23 +71,17 @@ bool EspTimerCam::set_led_breathing_period(float breathing_period) { return true; } -float EspTimerCam::get_led_breathing_period() { - return breathing_period_; -} +float EspTimerCam::get_led_breathing_period() { return breathing_period_; } -std::shared_ptr EspTimerCam::led() { - return led_; -} +std::shared_ptr EspTimerCam::led() { return led_; } -espp::Gaussian &EspTimerCam::gaussian() { - return gaussian_; -} +espp::Gaussian &EspTimerCam::gaussian() { return gaussian_; } float EspTimerCam::led_breathe() { - auto now = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration(now - breathing_start_).count(); - float t = std::fmod(elapsed, breathing_period_) / breathing_period_; - return gaussian_(t); + auto now = std::chrono::high_resolution_clock::now(); + auto elapsed = std::chrono::duration(now - breathing_start_).count(); + float t = std::fmod(elapsed, breathing_period_) / breathing_period_; + return gaussian_(t); } bool EspTimerCam::led_task_callback(std::mutex &m, std::condition_variable &cv) { @@ -121,15 +116,13 @@ bool EspTimerCam::initialize_rtc() { return false; } rtc_ = std::make_shared(EspTimerCam::Rtc::Config{ - .write = std::bind(&espp::I2c::write, &internal_i2c_, std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3), - .write_then_read = - std::bind(&espp::I2c::write_read, &internal_i2c_, std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), + .write = std::bind(&espp::I2c::write, &internal_i2c_, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3), + .write_then_read = std::bind(&espp::I2c::write_read, &internal_i2c_, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3, + std::placeholders::_4, std::placeholders::_5), .log_level = espp::Logger::Verbosity::WARN}); return true; } -std::shared_ptr EspTimerCam::rtc() { - return rtc_; -} +std::shared_ptr EspTimerCam::rtc() { return rtc_; } diff --git a/components/interrupt/include/interrupt.hpp b/components/interrupt/include/interrupt.hpp index c7805d985..a186afbfe 100644 --- a/components/interrupt/include/interrupt.hpp +++ b/components/interrupt/include/interrupt.hpp @@ -381,7 +381,8 @@ class Interrupt : public BaseComponent { // for printing the interrupt event using libfmt template <> struct fmt::formatter { constexpr auto parse(format_parse_context &ctx) const { return ctx.begin(); } - template auto format(const espp::Interrupt::Event &t, FormatContext &ctx) const { + template + auto format(const espp::Interrupt::Event &t, FormatContext &ctx) const { return fmt::format_to(ctx.out(), "Event{{gpio_num={}, active={}}}", t.gpio_num, t.active); } }; diff --git a/components/logger/include/logger.hpp b/components/logger/include/logger.hpp index 55518463b..c8994d853 100644 --- a/components/logger/include/logger.hpp +++ b/components/logger/include/logger.hpp @@ -74,7 +74,6 @@ class Logger { #endif // CONFIG_ESPP_LOGGER_ENABLE_CURSOR_COMMANDS #endif // ESPP_LOGGER_CURSOR_COMMANDS_ENABLED - public: /** * Verbosity levels for the logger, in order of increasing priority. diff --git a/components/matouch-rotary-display/example/main/matouch_rotary_display_example.cpp b/components/matouch-rotary-display/example/main/matouch_rotary_display_example.cpp index 415c745bf..2c1723430 100644 --- a/components/matouch-rotary-display/example/main/matouch_rotary_display_example.cpp +++ b/components/matouch-rotary-display/example/main/matouch_rotary_display_example.cpp @@ -101,14 +101,17 @@ extern "C" void app_main(void) { lv_label_set_text(label_btn, LV_SYMBOL_REFRESH); // center the text in the button lv_obj_align(label_btn, LV_ALIGN_CENTER, 0, 0); - lv_obj_add_event_cb(btn, [](auto event) { - std::lock_guard lock(lvgl_mutex); - clear_circles(); - static auto rotation = LV_DISPLAY_ROTATION_0; - rotation = static_cast((static_cast(rotation) + 1) % 4); - lv_display_t *disp = _lv_refr_get_disp_refreshing(); - lv_disp_set_rotation(disp, rotation); - }, LV_EVENT_PRESSED, nullptr); + lv_obj_add_event_cb( + btn, + [](auto event) { + std::lock_guard lock(lvgl_mutex); + clear_circles(); + static auto rotation = LV_DISPLAY_ROTATION_0; + rotation = static_cast((static_cast(rotation) + 1) % 4); + lv_display_t *disp = _lv_refr_get_disp_refreshing(); + lv_disp_set_rotation(disp, rotation); + }, + LV_EVENT_PRESSED, nullptr); // disable scrolling on the screen (so that it doesn't behave weirdly when // rotated and drawing with your finger) diff --git a/components/matouch-rotary-display/src/matouch-rotary-display.cpp b/components/matouch-rotary-display/src/matouch-rotary-display.cpp index 49c5fec34..2684c4ffd 100644 --- a/components/matouch-rotary-display/src/matouch-rotary-display.cpp +++ b/components/matouch-rotary-display/src/matouch-rotary-display.cpp @@ -279,7 +279,9 @@ bool MatouchRotaryDisplay::initialize_lcd() { return true; } -bool MatouchRotaryDisplay::initialize_display(size_t pixel_buffer_size, const espp::Task::BaseConfig &task_config, int update_period_ms) { +bool MatouchRotaryDisplay::initialize_display(size_t pixel_buffer_size, + const espp::Task::BaseConfig &task_config, + int update_period_ms) { if (!lcd_handle_) { logger_.error( "LCD not initialized, you must call initialize_lcd() before initialize_display()!"); diff --git a/components/t-dongle-s3/example/main/t_dongle_s3_example.cpp b/components/t-dongle-s3/example/main/t_dongle_s3_example.cpp index 049c08af6..db014330c 100644 --- a/components/t-dongle-s3/example/main/t_dongle_s3_example.cpp +++ b/components/t-dongle-s3/example/main/t_dongle_s3_example.cpp @@ -42,25 +42,26 @@ extern "C" void app_main(void) { // initialize the button, which we'll use to cycle the rotation of the display espp::Button button(espp::Button::Config{ .name = "Boot Button", - .interrupt_config = espp::Interrupt::PinConfig{ - .gpio_num = GPIO_NUM_0, - .callback = [](const auto &event) { - if (event.active) { - // lock the display mutex - std::lock_guard lock(lvgl_mutex); - static auto rotation = LV_DISPLAY_ROTATION_0; - rotation = static_cast((static_cast(rotation) + 1) % 4); - fmt::print("Setting rotation to {}\n", (int)rotation); - lv_display_t *disp = _lv_refr_get_disp_refreshing(); - lv_disp_set_rotation(disp, rotation); - } - }, - .active_level = espp::Interrupt::ActiveLevel::LOW, - .interrupt_type = espp::Interrupt::Type::ANY_EDGE, - .pullup_enabled = false, - .pulldown_enabled = false - }, - }); + .interrupt_config = + espp::Interrupt::PinConfig{.gpio_num = GPIO_NUM_0, + .callback = + [](const auto &event) { + if (event.active) { + // lock the display mutex + std::lock_guard lock(lvgl_mutex); + static auto rotation = LV_DISPLAY_ROTATION_0; + rotation = static_cast( + (static_cast(rotation) + 1) % 4); + fmt::print("Setting rotation to {}\n", (int)rotation); + lv_display_t *disp = _lv_refr_get_disp_refreshing(); + lv_disp_set_rotation(disp, rotation); + } + }, + .active_level = espp::Interrupt::ActiveLevel::LOW, + .interrupt_type = espp::Interrupt::Type::ANY_EDGE, + .pullup_enabled = false, + .pulldown_enabled = false}, + }); // set the LED to be red espp::Hsv hsv(150.0f, 1.0f, 1.0f); diff --git a/components/t-dongle-s3/include/t-dongle-s3.hpp b/components/t-dongle-s3/include/t-dongle-s3.hpp index 40e05eadb..855ca3619 100644 --- a/components/t-dongle-s3/include/t-dongle-s3.hpp +++ b/components/t-dongle-s3/include/t-dongle-s3.hpp @@ -83,7 +83,12 @@ class TDongleS3 : public BaseComponent { /// \param update_period_ms The update period of the display task /// \return true if the display was successfully initialized, false otherwise /// \note This will also allocate two full frame buffers in the SPIRAM - bool initialize_display(size_t pixel_buffer_size, const espp::Task::BaseConfig &task_config = {.name="Display", .stack_size_bytes=4096, .priority=10, .core_id=0}, int update_period_ms = 16); + bool initialize_display(size_t pixel_buffer_size, + const espp::Task::BaseConfig &task_config = {.name = "Display", + .stack_size_bytes = 4096, + .priority = 10, + .core_id = 0}, + int update_period_ms = 16); /// Get the width of the LCD in pixels /// \return The width of the LCD in pixels diff --git a/components/t-dongle-s3/src/t-dongle-s3.cpp b/components/t-dongle-s3/src/t-dongle-s3.cpp index 8206647c4..a19e7ce99 100644 --- a/components/t-dongle-s3/src/t-dongle-s3.cpp +++ b/components/t-dongle-s3/src/t-dongle-s3.cpp @@ -168,7 +168,9 @@ bool TDongleS3::initialize_lcd() { return true; } -bool TDongleS3::initialize_display(size_t pixel_buffer_size, const espp::Task::BaseConfig &task_config, int update_period_ms) { +bool TDongleS3::initialize_display(size_t pixel_buffer_size, + const espp::Task::BaseConfig &task_config, + int update_period_ms) { if (!lcd_handle_) { logger_.error( "LCD not initialized, you must call initialize_lcd() before initialize_display()!"); diff --git a/components/wrover-kit/example/main/wrover_kit_example.cpp b/components/wrover-kit/example/main/wrover_kit_example.cpp index fe62dc2e4..c6038d220 100644 --- a/components/wrover-kit/example/main/wrover_kit_example.cpp +++ b/components/wrover-kit/example/main/wrover_kit_example.cpp @@ -39,25 +39,26 @@ extern "C" void app_main(void) { // initialize the button, which we'll use to cycle the rotation of the display espp::Button button(espp::Button::Config{ .name = "Boot Button", - .interrupt_config = espp::Interrupt::PinConfig{ - .gpio_num = GPIO_NUM_0, - .callback = [](const auto &event) { - if (event.active) { - // lock the display mutex - std::lock_guard lock(lvgl_mutex); - static auto rotation = LV_DISPLAY_ROTATION_0; - rotation = static_cast((static_cast(rotation) + 1) % 4); - fmt::print("Setting rotation to {}\n", (int)rotation); - lv_display_t *disp = _lv_refr_get_disp_refreshing(); - lv_disp_set_rotation(disp, rotation); - } - }, - .active_level = espp::Interrupt::ActiveLevel::LOW, - .interrupt_type = espp::Interrupt::Type::ANY_EDGE, - .pullup_enabled = false, - .pulldown_enabled = false - }, - }); + .interrupt_config = + espp::Interrupt::PinConfig{.gpio_num = GPIO_NUM_0, + .callback = + [](const auto &event) { + if (event.active) { + // lock the display mutex + std::lock_guard lock(lvgl_mutex); + static auto rotation = LV_DISPLAY_ROTATION_0; + rotation = static_cast( + (static_cast(rotation) + 1) % 4); + fmt::print("Setting rotation to {}\n", (int)rotation); + lv_display_t *disp = _lv_refr_get_disp_refreshing(); + lv_disp_set_rotation(disp, rotation); + } + }, + .active_level = espp::Interrupt::ActiveLevel::LOW, + .interrupt_type = espp::Interrupt::Type::ANY_EDGE, + .pullup_enabled = false, + .pulldown_enabled = false}, + }); // set the background color to black lv_obj_t *bg = lv_obj_create(lv_screen_active()); diff --git a/components/wrover-kit/include/wrover-kit.hpp b/components/wrover-kit/include/wrover-kit.hpp index 3042fda84..ce5b6e4f6 100644 --- a/components/wrover-kit/include/wrover-kit.hpp +++ b/components/wrover-kit/include/wrover-kit.hpp @@ -66,7 +66,12 @@ class WroverKit : public BaseComponent { /// \param update_period_ms The update period of the display task /// \return true if the display was successfully initialized, false otherwise /// \note This will also allocate two full frame buffers in the SPIRAM - bool initialize_display(size_t pixel_buffer_size, const espp::Task::BaseConfig &task_config = {.name="Display", .stack_size_bytes=4096, .priority=10, .core_id=0}, int update_period_ms = 16); + bool initialize_display(size_t pixel_buffer_size, + const espp::Task::BaseConfig &task_config = {.name = "Display", + .stack_size_bytes = 4096, + .priority = 10, + .core_id = 0}, + int update_period_ms = 16); /// Get the width of the LCD in pixels /// \return The width of the LCD in pixels diff --git a/components/wrover-kit/src/wrover-kit.cpp b/components/wrover-kit/src/wrover-kit.cpp index 8624eb68d..7ea0c36cc 100644 --- a/components/wrover-kit/src/wrover-kit.cpp +++ b/components/wrover-kit/src/wrover-kit.cpp @@ -85,7 +85,9 @@ bool WroverKit::initialize_lcd() { return true; } -bool WroverKit::initialize_display(size_t pixel_buffer_size, const espp::Task::BaseConfig &task_config, int update_period_ms) { +bool WroverKit::initialize_display(size_t pixel_buffer_size, + const espp::Task::BaseConfig &task_config, + int update_period_ms) { if (!lcd_handle_) { logger_.error( "LCD not initialized, you must call initialize_lcd() before initialize_display()!"); diff --git a/lib/README.md b/lib/README.md index bb9646e2a..c291ae319 100644 --- a/lib/README.md +++ b/lib/README.md @@ -7,6 +7,61 @@ This folder contains the configuration needed to cross-compile the central * C++ * Python (through pybind 11) +## Updating the python bindings + +We use [litgen](https://github.com/pthom/litgen) to automatically parse specific +header files and generate python bindings for them in c++ using pybind11. + +Relevant files: +- [./autogenerate_bindings.py](./autogenerate_bindings.py): This is the script + which configures litgen and generates the appropriate code. Inside this script + is where we tell litgen which header files to generate python bindings for. + Note that the ordering of the header file list is important. +- [./python_bindings/pybind_espp.cpp](./python_bindings/pybind_espp.cpp): This + is where the generated pybind11 c++ code will go. It will need to be modified + after generation (see below). + +### Setup + +Create a virtual environment, and install the required packages: + +``` console +python3 -m venv env +source env/bin/activate +pip install -r requirements.txt +``` + +### Generating python bindings + +```console +# start the environment +source env/bin/activate +python autogenerate_bindings.py +``` + +Note: after you autogenerate the bindings, you will need to manually modify the +generated code in +[./python_bindings/pybind_espp.cpp](./python_bindings/pybind_espp.cpp) slightly +(at least until the underlying bugs in litgen/srcmlcpp are fixed): +1. You must fix the `RangeMapper::` to be `RangeMapper::` and + `RangeMapper::` where appropriate. +2. You must fix the `pyClassRangeMapper,` to be `pyClassRangeMapper_int,` and + `pyClassRangeMapper_float,` where appropriate (1 place each). +3. You must fix the `Bezier::` to be properly templated on `espp::Vector2f` + (`Bezier::`). +4. You must fix the `pyClassBezier` to be instead `pyClassBezier_espp_Vector2f`. +5. You must fix the `Vector2d` generated template code for both `int` and + `float` to ensure that the template type is always provided. +6. Srcml currently has an [issue with inner + structs](https://github.com/srcML/srcML/issues/2033). This means that for + `Bezier`, `Gaussian`, `Logger`, `Pid`, `Socket`, `Task`, `Timer`, + `TcpSocket`, `UdpSocket`, and `Joystick`, litgen will improperly generate an + `implicit default constructor`. You you can update the template parameter for + it to have the appropriate `const espp::::Config&` template + parameter. Note that for some classes, they may have multiple config + options - so for `Bezier`, `Task`, `Timer`, etc. you will want to create + overloads which target each of the config types. + ## Building for PC (C++ & Python) To build the library for use on PC (with C++ and Python), simply build with diff --git a/lib/python_bindings/espp/__init__.pyi b/lib/python_bindings/espp/__init__.pyi index f30e2bd18..018f41b9f 100644 --- a/lib/python_bindings/espp/__init__.pyi +++ b/lib/python_bindings/espp/__init__.pyi @@ -442,261 +442,6 @@ class FtpServer: #################### #################### -#################### #################### - - - -class Joystick: - """* - * @brief 2-axis Joystick with axis mapping / calibration. - * - * \section joystick_ex1 Basic Circular and Rectangular Joystick Example - * \snippet joystick_example.cpp circular joystick example - * \section joystick_ex2 ADC Joystick Example - * \snippet joystick_example.cpp adc joystick example - - """ - class Type(enum.Enum): - """* - * @brief Type of the joystick. - * @note When using a Type::CIRCULAR joystick, it's recommended to set the - * individual x/y calibration deadzones to be 0 and to only use the - * deadzone_radius field to set the deadzone around the center. - - """ - rectangular = enum.auto() # (= 0) #/< The default type of joystick. Uses the rangemappers for - #/ each axis (to convert raw values from input range to be - #/ [-1,1]) independently which results in x/y deadzones and - #/ output that are rectangular. - circular = enum.auto() # (= 1) #/< The joystick is configured to have a circular output. This - #/ means that the x/y < deadzones are circular around the - #/ input and range and the output is clamped to be on or - #/ within the unit circle. - - - class Config: - """* - * @brief Configuration structure for the joystick. - - """ - x_calibration: FloatRangeMapper.Config #*< Configuration for the x axis. - y_calibration: FloatRangeMapper.Config #*< Configuration for the y axis. - type: espp.Joystick.Type = espp.Joystick.Type(espp.Joystick.Type.rectangular) #*< The type of the joystick. See - Type enum for more information. - center_deadzone_radius: float = float(0) #*< The radius of the unit circle's deadzone [0, 1.0] around the center, only used - when the joystick is configured as Type::CIRCULAR. - range_deadzone: float = float(0) #*< The deadzone around the edge of the unit circle, only used when - the joystick is configured as Type::CIRCULAR. This scales the output so - that the output appears to have magnitude 1 (meaning it appears to be on - the edge of the unit circle) when the joystick value magnitude is within - the range [1-range_deadzone, 1]. - get_values: espp.Joystick.get_values_fn = espp.Joystick.get_values_fn(None) #*< Function to retrieve the latest - unmapped joystick values. Required if - you want to use update(), unused if - you call update(float raw_x, float - raw_y). - log_level: espp.Logger.Verbosity = espp.Logger.Verbosity(espp.Logger.Verbosity.WARN) #*< Verbosity for the Joystick logger_. - def __init__( - self, - x_calibration: FloatRangeMapper.Config = FloatRangeMapper.Config(), - y_calibration: FloatRangeMapper.Config = FloatRangeMapper.Config(), - type: Joystick.Type = Joystick.Type(Joystick.Type.rectangular), - center_deadzone_radius: float = float(0), - range_deadzone: float = float(0), - get_values: Joystick.get_values_fn = Joystick.get_values_fn(None), - log_level: Logger.Verbosity = Logger.Verbosity(Logger.Verbosity.WARN) - ) -> None: - """Auto-generated default constructor with named params""" - pass - - - def set_type( - self, - type: Joystick.Type, - radius: float = 0, - range_deadzone: float = 0 - ) -> None: - """* - * @brief Set the type of the joystick. - * @param type The Type of the joystick. - * @param radius Optional radius parameter used when \p type is - * Type::CIRCULAR. When the magnitude of the joystick's mapped - * position vector is less than this value, the vector is set to - * (0,0). - * @param range_deadzone Optional deadzone around the edge of the unit circle - * when \p type is Type::CIRCULAR. This scales the output so that the - * output appears to have magnitude 1 (meaning it appears to be on the - * edge of the unit circle) if the magnitude of the mapped position - * vector is greater than 1-range_deadzone. Example: if the range - * deadzone is 0.1, then the output will be scaled so that the - * magnitude of the output is 1 if the magnitude of the mapped - * position vector is greater than 0.9. - * @note If the Joystick is Type::CIRCULAR, the actual calibrations that are - * saved into the joystick will have 0 deadzone around the center value - * and range values, so that center and range deadzones are actually - * applied on the vector value instead of on the individual axes - * independently. - * @sa set_center_deadzone_radius - * @sa set_range_deadzone - * @sa set_calibration - - """ - pass - - def type(self) -> Joystick.Type: - """* - * @brief Get the type of the joystick. - * @return The Type of the joystick. - - """ - pass - - def set_center_deadzone_radius(self, radius: float) -> None: - """* - * @brief Sets the center deadzone radius. - * @note Radius is only applied when \p deadzone is Deadzone::CIRCULAR. - * @param radius Optional radius parameter used when \p deadzone is - * Deadzone::CIRCULAR. When the magnitude of the joystick's mapped - * position vector is less than this value, the vector is set to - * (0,0). - - """ - pass - - def center_deadzone_radius(self) -> float: - """* - * @brief Get the center deadzone radius. - * @return The center deadzone radius. - - """ - pass - - def set_range_deadzone(self, range_deadzone: float) -> None: - """* - * @brief Sets the range deadzone. - * @note Range deadzone is only applied when \p deadzone is Deadzone::CIRCULAR. - * @param range_deadzone Optional deadzone around the edge of the unit circle - * when \p deadzone is Deadzone::CIRCULAR. This scales the output so - * that the output appears to have magnitude 1 (meaning it appears to - * be on the edge of the unit circle) if the magnitude of the mapped - * position vector is greater than 1-range_deadzone. Example: if the - * range deadzone is 0.1, then the output will be scaled so that the - * magnitude of the output is 1 if the magnitude of the mapped position - * vector is greater than 0.9. - - """ - pass - - def range_deadzone(self) -> float: - """* - * @brief Get the range deadzone. - * @return The range deadzone. - - """ - pass - - def set_calibration( - self, - x_calibration: FloatRangeMapper.Config, - y_calibration: FloatRangeMapper.Config, - center_deadzone_radius: float = 0, - range_deadzone: float = 0 - ) -> None: - """* - * @brief Update the x and y axis mapping. - * @param x_calibration New x-axis range mapping configuration to use. - * @param y_calibration New y-axis range mapping configuration to use. - * @param center_deadzone_radius The radius of the unit circle's deadzone [0, - * 1.0] around the center, only used when the joystick is configured - * as Type::CIRCULAR. - * @param range_deadzone Optional deadzone around the edge of the unit circle - * when \p type is Type::CIRCULAR. This scales the output so that the - * output appears to have magnitude 1 (meaning it appears to be on the - * edge of the unit circle) if the magnitude of the mapped position - * vector is greater than 1-range_deadzone. Example: if the range - * deadzone is 0.1, then the output will be scaled so that the - * magnitude of the output is 1 if the magnitude of the mapped - * position vector is greater than 0.9. - * @note If the Joystick is Type::CIRCULAR, the actual calibrations that are - * saved into the joystick will have 0 deadzone around the center and range values, - * so that center and range deadzones are actually applied on the vector value. - * @sa set_center_deadzone_radius - * @sa set_range_deadzone - - """ - pass - - @overload - def update(self) -> None: - """* - * @brief Read the raw values and use the calibration data to update the - * position. - * @note Requires that the get_values_ function is set. - - """ - pass - - @overload - def update(self, raw_x: float, raw_y: float) -> None: - """* - * @brief Update the joystick's position using the provided raw x and y - * values. - * @param raw_x The raw x-axis value. - * @param raw_y The raw y-axis value. - * @note This function is useful when you have the raw values and don't want - * to use the get_values_ function. - - """ - pass - - def x(self) -> float: - """* - * @brief Get the most recently updated x axis calibrated position. - * @return The most recent x-axis position (from when update() was last - * called). - - """ - pass - - def y(self) -> float: - """* - * @brief Get the most recently updated y axis calibrated position. - * @return The most recent y-axis position (from when update() was last - * called). - - """ - pass - - def position(self) -> Vector2f: - """* - * @brief Get the most recently updated calibrated position. - * @return The most recent position (from when update() was last called). - - """ - pass - - def raw(self) -> Vector2f: - """* - * @brief Get the most recently updated raw / uncalibrated readings. This - * function is useful for externally performing a calibration routine - * and creating updated calibration / mapper configuration - * structures. - * @return The most recent raw measurements (from when update() was last - * called). - - """ - pass - - - def __init__(self) -> None: - """Auto-generated default constructor""" - pass - -# namespace espp - -#################### #################### - - #################### #################### @@ -718,10 +463,18 @@ class Logger: * checking the log level at compile time and only compiling in the functions * that are needed. * + * The logger can also be compiled with support for cursor commands. This allows + * the logger to move the cursor up, down, clear the line, clear the screen, and + * move the cursor to a specific position. This can be useful for creating + * various types of interactive output or to maintian context with long-running + * logs. + * * \section logger_ex1 Basic Example * \snippet logger_example.cpp Logger example * \section logger_ex2 Threaded Logging and Verbosity Example * \snippet logger_example.cpp MultiLogger example + * \section logger_ex3 Cursor Commands Example + * \snippet logger_example.cpp Cursor Commands example """ class Verbosity(enum.Enum): @@ -816,6 +569,16 @@ class Logger: + + @staticmethod + def get_time() -> str: + """* + * Get the current time in seconds since the start of the logging system. + * @return time in seconds since the start of the logging system. + + """ + pass + def __init__(self) -> None: """Auto-generated default constructor""" pass @@ -2196,15 +1959,15 @@ class Ndef: * * Handover Select (Hs) """ - empty = enum.auto() # (= 0x00) #/< Record is empty - well_known = enum.auto() # (= 0x01) #/< Type field contains a well-known RTD type name - mime_media = enum.auto() # (= 0x02) #/< Type field contains a media type (RFC 2046) - absolute_uri = enum.auto() # (= 0x03) #/< Type field contains an absolute URI (RFC 3986) - external_type = enum.auto() # (= 0x04) #/< Type field Contains an external type name - unknown = enum.auto() # (= 0x05) #/< Payload type is unknown, type length must be 0. - unchanged = enum.auto() # (= 0x06) #/< Indicates the payload is an intermediate or final chunk of a chunked NDEF + empty = enum.auto() # (= 0x00) #/< Record is empty + well_known = enum.auto() # (= 0x01) #/< Type field contains a well-known RTD type name + mime_media = enum.auto() # (= 0x02) #/< Type field contains a media type (RFC 2046) + absolute_uri = enum.auto() # (= 0x03) #/< Type field contains an absolute URI (RFC 3986) + external_type = enum.auto() # (= 0x04) #/< Type field Contains an external type name + unknown = enum.auto() # (= 0x05) #/< Payload type is unknown, type length must be 0. + unchanged = enum.auto() # (= 0x06) #/< Indicates the payload is an intermediate or final chunk of a chunked NDEF #/< record, type length must be 0. - reserved = enum.auto() # (= 0x07) #/< Reserved by the NFC forum for future use + reserved = enum.auto() # (= 0x07) #/< Reserved by the NFC forum for future use class Uic(enum.Enum): """* @@ -2213,78 +1976,78 @@ class Ndef: * and https://learn.adafruit.com/adafruit-pn532-rfid-nfc/ndef """ - none = enum.auto() # (= 0x00) #/< Exactly as written - http_www = enum.auto() # (= 0x01) #/< http://www. - https_www = enum.auto() # (= 0x02) #/< https://www. - http = enum.auto() # (= 0x03) #/< http:// - https = enum.auto() # (= 0x04) #/< https:// - tel = enum.auto() # (= 0x05) #/< tel: - mailto = enum.auto() # (= 0x06) #/< mailto: - ftp_anon = enum.auto() # (= 0x07) #/< ftp://anonymous:anonymous@ - ftp_ftp = enum.auto() # (= 0x08) #/< ftp://ftp. - ftps = enum.auto() # (= 0x09) #/< ftps:// - sftp = enum.auto() # (= 0x0A) #/< sftp:// - smb = enum.auto() # (= 0x0B) #/< smb:// - nfs = enum.auto() # (= 0x0C) #/< nfs:// - ftp = enum.auto() # (= 0x0D) #/< ftp:// - dav = enum.auto() # (= 0x0E) #/< dav:// - news = enum.auto() # (= 0x0F) #/< news: - telnet = enum.auto() # (= 0x10) #/< telnet:// - imap = enum.auto() # (= 0x11) #/< imap: - rstp = enum.auto() # (= 0x12) #/< rtsp:// - urn = enum.auto() # (= 0x13) #/< urn: - pop = enum.auto() # (= 0x14) #/< pop: - sip = enum.auto() # (= 0x15) #/< sip: - sips = enum.auto() # (= 0x16) #/< sips: - tftp = enum.auto() # (= 0x17) #/< tftp: - btspp = enum.auto() # (= 0x18) #/< btspp:// - btl2_cap = enum.auto() # (= 0x19) #/< btl2cap:// - btgoep = enum.auto() # (= 0x1A) #/< btgoep:// - tcpobex = enum.auto() # (= 0x1B) #/< tcpobex:// - irdaobex = enum.auto() # (= 0x1C) #/< irdaobex:// - file = enum.auto() # (= 0x1D) #/< file:// - urn_epc_id = enum.auto() # (= 0x1E) #/< urn:epc:id: - urn_epc_tag = enum.auto() # (= 0x1F) #/< urn:epc:tag: - urn_epc_pat = enum.auto() # (= 0x20) #/< urn:epc:pat: - urn_epc_raw = enum.auto() # (= 0x21) #/< urn:epc:raw: - urn_epc = enum.auto() # (= 0x22) #/< urn:epc: - urn_nfc = enum.auto() # (= 0x23) #/< urn:nfc: + none = enum.auto() # (= 0x00) #/< Exactly as written + http_www = enum.auto() # (= 0x01) #/< http://www. + https_www = enum.auto() # (= 0x02) #/< https://www. + http = enum.auto() # (= 0x03) #/< http:// + https = enum.auto() # (= 0x04) #/< https:// + tel = enum.auto() # (= 0x05) #/< tel: + mailto = enum.auto() # (= 0x06) #/< mailto: + ftp_anon = enum.auto() # (= 0x07) #/< ftp://anonymous:anonymous@ + ftp_ftp = enum.auto() # (= 0x08) #/< ftp://ftp. + ftps = enum.auto() # (= 0x09) #/< ftps:// + sftp = enum.auto() # (= 0x0A) #/< sftp:// + smb = enum.auto() # (= 0x0B) #/< smb:// + nfs = enum.auto() # (= 0x0C) #/< nfs:// + ftp = enum.auto() # (= 0x0D) #/< ftp:// + dav = enum.auto() # (= 0x0E) #/< dav:// + news = enum.auto() # (= 0x0F) #/< news: + telnet = enum.auto() # (= 0x10) #/< telnet:// + imap = enum.auto() # (= 0x11) #/< imap: + rstp = enum.auto() # (= 0x12) #/< rtsp:// + urn = enum.auto() # (= 0x13) #/< urn: + pop = enum.auto() # (= 0x14) #/< pop: + sip = enum.auto() # (= 0x15) #/< sip: + sips = enum.auto() # (= 0x16) #/< sips: + tftp = enum.auto() # (= 0x17) #/< tftp: + btspp = enum.auto() # (= 0x18) #/< btspp:// + btl2_cap = enum.auto() # (= 0x19) #/< btl2cap:// + btgoep = enum.auto() # (= 0x1A) #/< btgoep:// + tcpobex = enum.auto() # (= 0x1B) #/< tcpobex:// + irdaobex = enum.auto() # (= 0x1C) #/< irdaobex:// + file = enum.auto() # (= 0x1D) #/< file:// + urn_epc_id = enum.auto() # (= 0x1E) #/< urn:epc:id: + urn_epc_tag = enum.auto() # (= 0x1F) #/< urn:epc:tag: + urn_epc_pat = enum.auto() # (= 0x20) #/< urn:epc:pat: + urn_epc_raw = enum.auto() # (= 0x21) #/< urn:epc:raw: + urn_epc = enum.auto() # (= 0x22) #/< urn:epc: + urn_nfc = enum.auto() # (= 0x23) #/< urn:nfc: class BtType(enum.Enum): """* * @brief Type of Bluetooth radios. """ - bredr = enum.auto() # (= 0x00) #/< BT Classic - ble = enum.auto() # (= 0x01) #/< BT Low Energy + bredr = enum.auto() # (= 0x00) #/< BT Classic + ble = enum.auto() # (= 0x01) #/< BT Low Energy class BtAppearance(enum.Enum): """* * @brief Some appearance codes for BLE radios. """ - unknown = enum.auto() # (= 0x0000) #/< Generic Unknown + unknown = enum.auto() # (= 0x0000) #/< Generic Unknown # Generic Phone (b15-b6 = 0x001 << 6 = 0x0040) - phone = enum.auto() # (= 0x0040) #/< Generic Phone + phone = enum.auto() # (= 0x0040) #/< Generic Phone # Generic Computer (b15-b6 = 0x002 << 6 = 0x0080) - computer = enum.auto() # (= 0x0080) #/< Generic Computer + computer = enum.auto() # (= 0x0080) #/< Generic Computer # Generic Watch (b15-b6 = 0x003 << 6 = 0x00C0) - watch = enum.auto() # (= 0x00C0) #/< Generic Watch + watch = enum.auto() # (= 0x00C0) #/< Generic Watch # Generic Clock (b15-b6 = 0x004 << 6 = 0x0100) - clock = enum.auto() # (= 0x0100) #/< Generic Clock + clock = enum.auto() # (= 0x0100) #/< Generic Clock # Generic Computer (b15-b6 = 0x005 << 6 = 0x0140) - display = enum.auto() # (= 0x0140) #/< Generic Display + display = enum.auto() # (= 0x0140) #/< Generic Display # Generic Computer (b15-b6 = 0x006 << 6 = 0x0180) - remote_control = enum.auto() # (= 0x0180) #/< Generic Remote Control + remote_control = enum.auto() # (= 0x0180) #/< Generic Remote Control # Generic HID (b15-b6 = 0x00F << 6 = 0x03C0) - generic_hid = enum.auto() # (= 0x03C0) #/< Generic HID - keyboard = enum.auto() # (= 0x03C1) #/< HID Keyboard - mouse = enum.auto() # (= 0x03C2) #/< HID Mouse - joystick = enum.auto() # (= 0x03C3) #/< HID Joystick - gamepad = enum.auto() # (= 0x03C4) #/< HID Gamepad - touchpad = enum.auto() # (= 0x03C9) #/< HID Touchpad + generic_hid = enum.auto() # (= 0x03C0) #/< Generic HID + keyboard = enum.auto() # (= 0x03C1) #/< HID Keyboard + mouse = enum.auto() # (= 0x03C2) #/< HID Mouse + joystick = enum.auto() # (= 0x03C3) #/< HID Joystick + gamepad = enum.auto() # (= 0x03C4) #/< HID Gamepad + touchpad = enum.auto() # (= 0x03C9) #/< HID Touchpad # Generic Gaming (b15-b6 = 0x02A << 6 = 0x0A80) - gaming = enum.auto() # (= 0x0A80) #/< Generic Gaming group + gaming = enum.auto() # (= 0x0A80) #/< Generic Gaming group class CarrierPowerState(enum.Enum): """* @@ -2293,10 +2056,10 @@ class Ndef: * message. """ - inactive = enum.auto() # (= 0x00) #/< Carrier power is off - active = enum.auto() # (= 0x01) #/< Carrier power is on - activating = enum.auto() # (= 0x02) #/< Carrier power is turning on - unknown = enum.auto() # (= 0x03) #/< Carrier power state is unknown + inactive = enum.auto() # (= 0x00) #/< Carrier power is off + active = enum.auto() # (= 0x01) #/< Carrier power is on + activating = enum.auto() # (= 0x02) #/< Carrier power is turning on + unknown = enum.auto() # (= 0x03) #/< Carrier power state is unknown class BtEir(enum.Enum): """* @@ -2304,67 +2067,67 @@ class Ndef: * out of band (OOB) pairing NDEF records. """ - flags = enum.auto() # (= 0x01) #/< BT flags: b0: LE limited discoverable mode, b1: LE general discoverable mode, + flags = enum.auto() # (= 0x01) #/< BT flags: b0: LE limited discoverable mode, b1: LE general discoverable mode, #/< b2: BR/EDR not supported, b3: Simultaneous LE & BR/EDR controller, b4: #/< simultaneous LE & BR/EDR Host - uuids_16_bit_partial = enum.auto() # (= 0x02) #/< Incomplete list of 16 bit service class UUIDs - uuids_16_bit_complete = enum.auto() # (= 0x03) #/< Complete list of 16 bit service class UUIDs - uuids_32_bit_partial = enum.auto() # (= 0x04) #/< Incomplete list of 32 bit service class UUIDs - uuids_32_bit_complete = enum.auto() # (= 0x05) #/< Complete list of 32 bit service class UUIDs - uuids_128_bit_partial = enum.auto() # (= 0x06) #/< Incomplete list of 128 bit service class UUIDs - uuids_128_bit_complete = enum.auto() # (= 0x07) #/< Complete list of 128 bit service class UUIDs - short_local_name = enum.auto() # (= 0x08) #/< Shortened Bluetooth Local Name - long_local_name = enum.auto() # (= 0x09) #/< Complete Bluetooth Local Name - tx_power_level = enum.auto() # (= 0x0A) #/< TX Power level (1 byte), -127 dBm to +127 dBm - class_of_device = enum.auto() # (= 0x0D) #/< Class of Device - sp_hash_c192 = enum.auto() # (= 0x0E) #/< Simple Pairing Hash C-192 - sp_random_r192 = enum.auto() # (= 0x0F) #/< Simple Pairing Randomizer R-192 - security_manager_tk = enum.auto() # (= 0x10) #/< Security Manager TK Value (LE Legacy Pairing) - security_manager_flags = enum.auto() # (= 0x11) #/< Flags (1 B), b0: OOB flags field (1 = 00B data present, 0 not), b1: LE Supported + uuids_16_bit_partial = enum.auto() # (= 0x02) #/< Incomplete list of 16 bit service class UUIDs + uuids_16_bit_complete = enum.auto() # (= 0x03) #/< Complete list of 16 bit service class UUIDs + uuids_32_bit_partial = enum.auto() # (= 0x04) #/< Incomplete list of 32 bit service class UUIDs + uuids_32_bit_complete = enum.auto() # (= 0x05) #/< Complete list of 32 bit service class UUIDs + uuids_128_bit_partial = enum.auto() # (= 0x06) #/< Incomplete list of 128 bit service class UUIDs + uuids_128_bit_complete = enum.auto() # (= 0x07) #/< Complete list of 128 bit service class UUIDs + short_local_name = enum.auto() # (= 0x08) #/< Shortened Bluetooth Local Name + long_local_name = enum.auto() # (= 0x09) #/< Complete Bluetooth Local Name + tx_power_level = enum.auto() # (= 0x0A) #/< TX Power level (1 byte), -127 dBm to +127 dBm + class_of_device = enum.auto() # (= 0x0D) #/< Class of Device + sp_hash_c192 = enum.auto() # (= 0x0E) #/< Simple Pairing Hash C-192 + sp_random_r192 = enum.auto() # (= 0x0F) #/< Simple Pairing Randomizer R-192 + security_manager_tk = enum.auto() # (= 0x10) #/< Security Manager TK Value (LE Legacy Pairing) + security_manager_flags = enum.auto() # (= 0x11) #/< Flags (1 B), b0: OOB flags field (1 = 00B data present, 0 not), b1: LE Supported #/< (host), b2: Simultaneous LE & BR/EDR to same device capable (host), b3: address #/< type (0 = public, 1 = random) - appearance = enum.auto() # (= 0x19) #/< Appearance - mac = enum.auto() # (= 0x1B) #/< Bluetooth Device Address - le_role = enum.auto() # (= 0x1C) #/< LE Role - sp_hash_c256 = enum.auto() # (= 0x1D) #/< Simple Pairing Hash C-256 - sp_hash_r256 = enum.auto() # (= 0x1E) #/< Simple Pairing Randomizer R-256 - le_sc_confirmation = enum.auto() # (= 0x22) #/< LE Secure Connections Confirmation Value - le_sc_random = enum.auto() # (= 0x23) #/< LE Secure Connections Random Value + appearance = enum.auto() # (= 0x19) #/< Appearance + mac = enum.auto() # (= 0x1B) #/< Bluetooth Device Address + le_role = enum.auto() # (= 0x1C) #/< LE Role + sp_hash_c256 = enum.auto() # (= 0x1D) #/< Simple Pairing Hash C-256 + sp_hash_r256 = enum.auto() # (= 0x1E) #/< Simple Pairing Randomizer R-256 + le_sc_confirmation = enum.auto() # (= 0x22) #/< LE Secure Connections Confirmation Value + le_sc_random = enum.auto() # (= 0x23) #/< LE Secure Connections Random Value class BleRole(enum.Enum): """* * @brief Possible roles for BLE records to indicate support for. """ - peripheral_only = enum.auto() # (= 0x00) #/< Radio can only act as a peripheral - central_only = enum.auto() # (= 0x01) #/< Radio can only act as a central - peripheral_central = enum.auto() # (= 0x02) #/< Radio can act as both a peripheral and a central, but prefers peripheral - central_peripheral = enum.auto() # (= 0x03) #/< Radio can act as both a peripheral and a central, but prefers central + peripheral_only = enum.auto() # (= 0x00) #/< Radio can only act as a peripheral + central_only = enum.auto() # (= 0x01) #/< Radio can only act as a central + peripheral_central = enum.auto() # (= 0x02) #/< Radio can act as both a peripheral and a central, but prefers peripheral + central_peripheral = enum.auto() # (= 0x03) #/< Radio can act as both a peripheral and a central, but prefers central class WifiEncryptionType(enum.Enum): """* * @brief Types of configurable encryption for WiFi networks """ - none = enum.auto() # (= 0x01) #/< No encryption - wep = enum.auto() # (= 0x02) #/< WEP - tkip = enum.auto() # (= 0x04) #/< TKIP - aes = enum.auto() # (= 0x08) #/< AES + none = enum.auto() # (= 0x01) #/< No encryption + wep = enum.auto() # (= 0x02) #/< WEP + tkip = enum.auto() # (= 0x04) #/< TKIP + aes = enum.auto() # (= 0x08) #/< AES class WifiAuthenticationType(enum.Enum): """* * @brief WiFi network authentication """ - open = enum.auto() # (= 0x01) #/< Open / no security - wpa_personal = enum.auto() # (= 0x02) #/< WPA personal - shared = enum.auto() # (= 0x04) #/< Shared key - wpa_enterprise = enum.auto() # (= 0x08) #/< WPA enterprise - wpa2_enterprise = enum.auto() # (= 0x10) #/< WPA2 Enterprise - wpa2_personal = enum.auto() # (= 0x20) #/< WPA2 personal - wpa_wpa2_personal = enum.auto() # (= 0x22) #/< Both WPA and WPA2 personal + open = enum.auto() # (= 0x01) #/< Open / no security + wpa_personal = enum.auto() # (= 0x02) #/< WPA personal + shared = enum.auto() # (= 0x04) #/< Shared key + wpa_enterprise = enum.auto() # (= 0x08) #/< WPA enterprise + wpa2_enterprise = enum.auto() # (= 0x10) #/< WPA2 Enterprise + wpa2_personal = enum.auto() # (= 0x20) #/< WPA2 personal + wpa_wpa2_personal = enum.auto() # (= 0x22) #/< Both WPA and WPA2 personal - handover_version: int = 0x13 #/< Connection Handover version 1.3 # (C++ static member) + handover_version: int = 0x13 #/< Connection Handover version 1.3 # (C++ static member) # (const) def __init__( self, @@ -2418,17 +2181,18 @@ class Ndef: * @brief Configuration structure for wifi configuration ndef structure. """ - ssid: std.string_view #/< SSID for the network - key: std.string_view #/< Security key / password for the network - authentication: WifiAuthenticationType = WifiAuthenticationType.wpa2_personal #/< Authentication type the network uses. - encryption: WifiEncryptionType = WifiEncryptionType.aes #/< Encryption type the network uses. - mac_address: int = 0xFFFFFFFFFFFF #/< Broadcast MAC address FF:FF:FF:FF:FF:FF + ssid: std.string_view #/< SSID for the network + key: std.string_view #/< Security key / password for the network + authentication: espp.Ndef.WifiAuthenticationType = espp.Ndef.WifiAuthenticationType.wpa2_personal #/< Authentication type the network + #/< uses. + encryption: espp.Ndef.WifiEncryptionType = espp.Ndef.WifiEncryptionType.aes #/< Encryption type the network uses. + mac_address: int = 0xFFFFFFFFFFFF #/< Broadcast MAC address FF:FF:FF:FF:FF:FF def __init__( self, ssid: std.string_view = std.string_view(), key: std.string_view = std.string_view(), - authentication: WifiAuthenticationType = WifiAuthenticationType.wpa2_personal, - encryption: WifiEncryptionType = WifiEncryptionType.aes, + authentication: Ndef.WifiAuthenticationType = Ndef.WifiAuthenticationType.wpa2_personal, + encryption: Ndef.WifiEncryptionType = Ndef.WifiEncryptionType.aes, mac_address: int = 0xFFFFFFFFFFFF ) -> None: """Auto-generated default constructor with named params""" @@ -3349,13 +3113,15 @@ class Task: * * \section task_ex1 Basic Task Example * \snippet task_example.cpp Task example - * \section task_ex2 Many Task Example + * \section task_ex2 Task Watchdog Example + * \snippet task_example.cpp task watchdog example + * \section task_ex3 Many Task Example * \snippet task_example.cpp ManyTask example - * \section task_ex3 Long Running Task Example + * \section task_ex4 Long Running Task Example * \snippet task_example.cpp LongRunningTask example - * \section task_ex4 Task Info Example + * \section task_ex5 Task Info Example * \snippet task_example.cpp Task Info example - * \section task_ex5 Task Request Stop Example + * \section task_ex6 Task Request Stop Example * \snippet task_example.cpp Task Request Stop example * * \section run_on_core_ex1 Run on Core Example @@ -3364,6 +3130,7 @@ class Task: """ + class BaseConfig: """* * @brief Base configuration struct for the Task. @@ -3504,10 +3271,12 @@ class Task: def stop(self) -> bool: """* - * @brief Stop the task execution, blocking until it stops. - * + * @brief Stop the task execution. + * @details This will request the task to stop, notify the condition variable, + * and (if this calling context is not the task context) join the + * thread. * @return True if the task stopped, False if it was not started / already - * stopped. + * stopped. """ pass @@ -3530,7 +3299,24 @@ class Task: """ pass - + + def get_id(self) -> task_id_t: + """* + * @brief Get the ID for this Task's thread / task context. + * @return ID for this Task's thread / task context. + + """ + pass + + @staticmethod + def get_current_id() -> task_id_t: + """* + * @brief Get the ID for the current thread / task context. + * @return ID for the current thread / task context. + + """ + pass + def __init__(self) -> None: """Auto-generated default constructor""" pass @@ -3574,17 +3360,19 @@ class Timer: / / \section timer_ex1 Timer Example 1 / \snippet timer_example.cpp timer example - / \section timer_ex2 Timer Delay Example + / \section timer_ex2 Timer Watchdog Example + / \snippet timer_example.cpp timer watchdog example + / \section timer_ex3 Timer Delay Example / \snippet timer_example.cpp timer delay example - / \section timer_ex3 Oneshot Timer Example + / \section timer_ex4 Oneshot Timer Example / \snippet timer_example.cpp timer oneshot example - / \section timer_ex4 Timer Cancel Itself Example + / \section timer_ex5 Timer Cancel Itself Example / \snippet timer_example.cpp timer cancel itself example - / \section timer_ex5 Oneshot Timer Cancel Itself Then Start again with Delay Example + / \section timer_ex6 Oneshot Timer Cancel Itself Then Start again with Delay Example / \snippet timer_example.cpp timer oneshot restart example - / \section timer_ex6 Timer Update Period Example + / \section timer_ex7 Timer Update Period Example / \snippet timer_example.cpp timer update period example - / \section timer_ex7 Timer AdvancedConfig Example + / \section timer_ex8 Timer AdvancedConfig Example / \snippet timer_example.cpp timer advanced config example """ @@ -3672,6 +3460,7 @@ class Timer: """ pass + def set_period(self, period: std.chrono.duration) -> None: """/ @brief Set the period of the timer. / @details Sets the period of the timer. @@ -3696,5 +3485,260 @@ class Timer: #################### #################### + +#################### #################### + + + +class Joystick: + """* + * @brief 2-axis Joystick with axis mapping / calibration. + * + * \section joystick_ex1 Basic Circular and Rectangular Joystick Example + * \snippet joystick_example.cpp circular joystick example + * \section joystick_ex2 ADC Joystick Example + * \snippet joystick_example.cpp adc joystick example + + """ + class Type(enum.Enum): + """* + * @brief Type of the joystick. + * @note When using a Type::CIRCULAR joystick, it's recommended to set the + * individual x/y calibration deadzones to be 0 and to only use the + * deadzone_radius field to set the deadzone around the center. + + """ + rectangular = enum.auto() # (= 0) #/< The default type of joystick. Uses the rangemappers for + #/ each axis (to convert raw values from input range to be + #/ [-1,1]) independently which results in x/y deadzones and + #/ output that are rectangular. + circular = enum.auto() # (= 1) #/< The joystick is configured to have a circular output. This + #/ means that the x/y < deadzones are circular around the + #/ input and range and the output is clamped to be on or + #/ within the unit circle. + + + class Config: + """* + * @brief Configuration structure for the joystick. + + """ + x_calibration: espp.FloatRangeMapper.Config #*< Configuration for the x axis. + y_calibration: espp.FloatRangeMapper.Config #*< Configuration for the y axis. + type: espp.Joystick.Type = espp.Joystick.Type(espp.Joystick.Type.rectangular) #*< The type of the joystick. See + Type enum for more information. + center_deadzone_radius: float = float(0) #*< The radius of the unit circle's deadzone [0, 1.0] around the center, only used + when the joystick is configured as Type::CIRCULAR. + range_deadzone: float = float(0) #*< The deadzone around the edge of the unit circle, only used when + the joystick is configured as Type::CIRCULAR. This scales the output so + that the output appears to have magnitude 1 (meaning it appears to be on + the edge of the unit circle) when the joystick value magnitude is within + the range [1-range_deadzone, 1]. + get_values: espp.Joystick.get_values_fn = espp.Joystick.get_values_fn(None) #*< Function to retrieve the latest + unmapped joystick values. Required if + you want to use update(), unused if + you call update(float raw_x, float + raw_y). + log_level: espp.Logger.Verbosity = espp.Logger.Verbosity(espp.Logger.Verbosity.warn) #*< Verbosity for the Joystick logger_. + def __init__( + self, + x_calibration: FloatRangeMapper.Config = FloatRangeMapper.Config(), + y_calibration: FloatRangeMapper.Config = FloatRangeMapper.Config(), + type: Joystick.Type = Joystick.Type(Joystick.Type.rectangular), + center_deadzone_radius: float = float(0), + range_deadzone: float = float(0), + get_values: Joystick.get_values_fn = Joystick.get_values_fn(None), + log_level: Logger.Verbosity = Logger.Verbosity(Logger.Verbosity.warn) + ) -> None: + """Auto-generated default constructor with named params""" + pass + + + def set_type( + self, + type: Joystick.Type, + radius: float = 0, + range_deadzone: float = 0 + ) -> None: + """* + * @brief Set the type of the joystick. + * @param type The Type of the joystick. + * @param radius Optional radius parameter used when \p type is + * Type::CIRCULAR. When the magnitude of the joystick's mapped + * position vector is less than this value, the vector is set to + * (0,0). + * @param range_deadzone Optional deadzone around the edge of the unit circle + * when \p type is Type::CIRCULAR. This scales the output so that the + * output appears to have magnitude 1 (meaning it appears to be on the + * edge of the unit circle) if the magnitude of the mapped position + * vector is greater than 1-range_deadzone. Example: if the range + * deadzone is 0.1, then the output will be scaled so that the + * magnitude of the output is 1 if the magnitude of the mapped + * position vector is greater than 0.9. + * @note If the Joystick is Type::CIRCULAR, the actual calibrations that are + * saved into the joystick will have 0 deadzone around the center value + * and range values, so that center and range deadzones are actually + * applied on the vector value instead of on the individual axes + * independently. + * @sa set_center_deadzone_radius + * @sa set_range_deadzone + * @sa set_calibration + + """ + pass + + def type(self) -> Joystick.Type: + """* + * @brief Get the type of the joystick. + * @return The Type of the joystick. + + """ + pass + + def set_center_deadzone_radius(self, radius: float) -> None: + """* + * @brief Sets the center deadzone radius. + * @note Radius is only applied when \p deadzone is Deadzone::CIRCULAR. + * @param radius Optional radius parameter used when \p deadzone is + * Deadzone::CIRCULAR. When the magnitude of the joystick's mapped + * position vector is less than this value, the vector is set to + * (0,0). + + """ + pass + + def center_deadzone_radius(self) -> float: + """* + * @brief Get the center deadzone radius. + * @return The center deadzone radius. + + """ + pass + + def set_range_deadzone(self, range_deadzone: float) -> None: + """* + * @brief Sets the range deadzone. + * @note Range deadzone is only applied when \p deadzone is Deadzone::CIRCULAR. + * @param range_deadzone Optional deadzone around the edge of the unit circle + * when \p deadzone is Deadzone::CIRCULAR. This scales the output so + * that the output appears to have magnitude 1 (meaning it appears to + * be on the edge of the unit circle) if the magnitude of the mapped + * position vector is greater than 1-range_deadzone. Example: if the + * range deadzone is 0.1, then the output will be scaled so that the + * magnitude of the output is 1 if the magnitude of the mapped position + * vector is greater than 0.9. + + """ + pass + + def range_deadzone(self) -> float: + """* + * @brief Get the range deadzone. + * @return The range deadzone. + + """ + pass + + def set_calibration( + self, + x_calibration: FloatRangeMapper.Config, + y_calibration: FloatRangeMapper.Config, + center_deadzone_radius: float = 0, + range_deadzone: float = 0 + ) -> None: + """* + * @brief Update the x and y axis mapping. + * @param x_calibration New x-axis range mapping configuration to use. + * @param y_calibration New y-axis range mapping configuration to use. + * @param center_deadzone_radius The radius of the unit circle's deadzone [0, + * 1.0] around the center, only used when the joystick is configured + * as Type::CIRCULAR. + * @param range_deadzone Optional deadzone around the edge of the unit circle + * when \p type is Type::CIRCULAR. This scales the output so that the + * output appears to have magnitude 1 (meaning it appears to be on the + * edge of the unit circle) if the magnitude of the mapped position + * vector is greater than 1-range_deadzone. Example: if the range + * deadzone is 0.1, then the output will be scaled so that the + * magnitude of the output is 1 if the magnitude of the mapped + * position vector is greater than 0.9. + * @note If the Joystick is Type::CIRCULAR, the actual calibrations that are + * saved into the joystick will have 0 deadzone around the center and range values, + * so that center and range deadzones are actually applied on the vector value. + * @sa set_center_deadzone_radius + * @sa set_range_deadzone + + """ + pass + + @overload + def update(self) -> None: + """* + * @brief Read the raw values and use the calibration data to update the + * position. + * @note Requires that the get_values_ function is set. + + """ + pass + + @overload + def update(self, raw_x: float, raw_y: float) -> None: + """* + * @brief Update the joystick's position using the provided raw x and y + * values. + * @param raw_x The raw x-axis value. + * @param raw_y The raw y-axis value. + * @note This function is useful when you have the raw values and don't want + * to use the get_values_ function. + + """ + pass + + def x(self) -> float: + """* + * @brief Get the most recently updated x axis calibrated position. + * @return The most recent x-axis position (from when update() was last + * called). + + """ + pass + + def y(self) -> float: + """* + * @brief Get the most recently updated y axis calibrated position. + * @return The most recent y-axis position (from when update() was last + * called). + + """ + pass + + def position(self) -> Vector2f: + """* + * @brief Get the most recently updated calibrated position. + * @return The most recent position (from when update() was last called). + + """ + pass + + def raw(self) -> Vector2f: + """* + * @brief Get the most recently updated raw / uncalibrated readings. This + * function is useful for externally performing a calibration routine + * and creating updated calibration / mapper configuration + * structures. + * @return The most recent raw measurements (from when update() was last + * called). + + """ + pass + + + def __init__(self) -> None: + """Auto-generated default constructor""" + pass + +# namespace espp + +#################### #################### + # # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AUTOGENERATED CODE END !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/lib/python_bindings/pybind_espp.cpp b/lib/python_bindings/pybind_espp.cpp index 2d7985e42..30f1a4815 100644 --- a/lib/python_bindings/pybind_espp.cpp +++ b/lib/python_bindings/pybind_espp.cpp @@ -241,9 +241,15 @@ void py_init_module_espp(py::module &m) { "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 * \\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"); + "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 py::enum_( @@ -284,7 +290,7 @@ void py_init_module_espp(py::module &m) { "*< The verbosity level for the logger."); } // end of inner classes & enums of Logger - pyClassLogger + pyClassLogger.def(py::init()) .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") @@ -304,7 +310,11 @@ void py_init_module_espp(py::module &m) { "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"); + "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"); //////////////////// //////////////////// //////////////////// //////////////////// @@ -1257,7 +1267,7 @@ void py_init_module_espp(py::module &m) { .def_readwrite("key", &espp::Ndef::WifiConfig::key, "/< Security key / password for the network") .def_readwrite("authentication", &espp::Ndef::WifiConfig::authentication, - "/< Authentication type the network uses.") + "/< Authentication type the network") .def_readwrite("encryption", &espp::Ndef::WifiConfig::encryption, "/< Encryption type the network uses.") .def_readwrite("mac_address", &espp::Ndef::WifiConfig::mac_address, @@ -1855,12 +1865,13 @@ void py_init_module_espp(py::module &m) { "specific core, which can\n * be used to run a specific function on a specific core, as you " "might want to\n * do when registering an interrupt driver on a specific core.\n *\n * " "\\section task_ex1 Basic Task Example\n * \\snippet task_example.cpp Task example\n * " - "\\section task_ex2 Many Task Example\n * \\snippet task_example.cpp ManyTask example\n * " - "\\section task_ex3 Long Running Task Example\n * \\snippet task_example.cpp LongRunningTask " - "example\n * \\section task_ex4 Task Info Example\n * \\snippet task_example.cpp Task Info " - "example\n * \\section task_ex5 Task Request Stop Example\n * \\snippet task_example.cpp " - "Task Request Stop example\n *\n * \\section run_on_core_ex1 Run on Core Example\n * " - "\\snippet task_example.cpp run on core example\n"); + "\\section task_ex2 Task Watchdog Example\n * \\snippet task_example.cpp task watchdog " + "example\n * \\section task_ex3 Many Task Example\n * \\snippet task_example.cpp ManyTask " + "example\n * \\section task_ex4 Long Running Task Example\n * \\snippet task_example.cpp " + "LongRunningTask example\n * \\section task_ex5 Task Info Example\n * \\snippet " + "task_example.cpp Task Info example\n * \\section task_ex6 Task Request Stop Example\n * " + "\\snippet task_example.cpp Task Request Stop example\n *\n * \\section run_on_core_ex1 Run " + "on Core Example\n * \\snippet task_example.cpp run on core example\n"); { // inner classes & enums of Task auto pyClassTask_ClassBaseConfig = @@ -2002,14 +2013,22 @@ void py_init_module_espp(py::module &m) { "*\n * @brief Start executing the task.\n *\n * @return True if the task started, " "False if it was already started.\n") .def("stop", &espp::Task::stop, - "*\n * @brief Stop the task execution, blocking until it stops.\n *\n * @return " - "True if the task stopped, False if it was not started / already\n * stopped.\n") + "*\n * @brief Stop the task execution.\n * @details This will request the task to " + "stop, notify the condition variable,\n * and (if this calling context is " + "not the task context) join the\n * thread.\n * @return True if the task " + "stopped, False if it was not started / already\n * stopped.\n") .def("is_started", &espp::Task::is_started, "*\n * @brief Has the task been started or not?\n *\n * @return True if the task " "is started / running, False otherwise.\n") .def("is_running", &espp::Task::is_running, "*\n * @brief Is the task running?\n *\n * @return True if the task is running, " - "False otherwise.\n"); + "False otherwise.\n") + .def("get_id", &espp::Task::get_id, + "*\n * @brief Get the ID for this Task's thread / task context.\n * @return ID for " + "this Task's thread / task context.\n") + .def_static("get_current_id", &espp::Task::get_current_id, + "*\n * @brief Get the ID for the current thread / task context.\n * @return " + "ID for the current thread / task context.\n"); //////////////////// //////////////////// //////////////////// //////////////////// @@ -2034,14 +2053,15 @@ void py_init_module_espp(py::module &m) { "it\n/ will block the task. If the timer callback function blocks for a\n/ long " "time, then the timer will not be able to keep up with the\n/ period.\n/\n/ \\section " "timer_ex1 Timer Example 1\n/ \\snippet timer_example.cpp timer example\n/ \\section " - "timer_ex2 Timer Delay Example\n/ \\snippet timer_example.cpp timer delay example\n/ " - "\\section timer_ex3 Oneshot Timer Example\n/ \\snippet timer_example.cpp timer oneshot " - "example\n/ \\section timer_ex4 Timer Cancel Itself Example\n/ \\snippet timer_example.cpp " - "timer cancel itself example\n/ \\section timer_ex5 Oneshot Timer Cancel Itself Then Start " - "again with Delay Example\n/ \\snippet timer_example.cpp timer oneshot restart example\n/ " - "\\section timer_ex6 Timer Update Period Example\n/ \\snippet timer_example.cpp timer update " - "period example\n/ \\section timer_ex7 Timer AdvancedConfig Example\n/ \\snippet " - "timer_example.cpp timer advanced config example"); + "timer_ex2 Timer Watchdog Example\n/ \\snippet timer_example.cpp timer watchdog example\n/ " + "\\section timer_ex3 Timer Delay Example\n/ \\snippet timer_example.cpp timer delay " + "example\n/ \\section timer_ex4 Oneshot Timer Example\n/ \\snippet timer_example.cpp timer " + "oneshot example\n/ \\section timer_ex5 Timer Cancel Itself Example\n/ \\snippet " + "timer_example.cpp timer cancel itself example\n/ \\section timer_ex6 Oneshot Timer Cancel " + "Itself Then Start again with Delay Example\n/ \\snippet timer_example.cpp timer oneshot " + "restart example\n/ \\section timer_ex7 Timer Update Period Example\n/ \\snippet " + "timer_example.cpp timer update period example\n/ \\section timer_ex8 Timer AdvancedConfig " + "Example\n/ \\snippet timer_example.cpp timer advanced config example"); { // inner classes & enums of Timer auto pyClassTimer_ClassConfig =